master
   1gpa: Allocator,
   2bin_file: *link.File,
   3format: DW.Format,
   4endian: std.builtin.Endian,
   5address_size: AddressSize,
   6
   7mods: std.AutoArrayHashMapUnmanaged(*Module, ModInfo),
   8types: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index),
   9values: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index),
  10navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index),
  11decls: std.AutoArrayHashMapUnmanaged(InternPool.TrackedInst.Index, Entry.Index),
  12
  13debug_abbrev: DebugAbbrev,
  14debug_aranges: DebugAranges,
  15debug_frame: DebugFrame,
  16debug_info: DebugInfo,
  17debug_line: DebugLine,
  18debug_line_str: StringSection,
  19debug_loclists: DebugLocLists,
  20debug_rnglists: DebugRngLists,
  21debug_str: StringSection,
  22
  23pub const UpdateError = error{
  24    WriteFailed,
  25    ReinterpretDeclRef,
  26    Unimplemented,
  27    EndOfStream,
  28    Underflow,
  29    UnexpectedEndOfFile,
  30} ||
  31    codegen.GenerateSymbolError ||
  32    std.fs.File.OpenError ||
  33    std.fs.File.SetEndPosError ||
  34    std.fs.File.CopyRangeError ||
  35    std.fs.File.PReadError ||
  36    std.fs.File.PWriteError;
  37
  38pub const FlushError = UpdateError;
  39
  40pub const RelocError =
  41    std.fs.File.PWriteError;
  42
  43pub const AddressSize = enum(u8) {
  44    @"32" = 4,
  45    @"64" = 8,
  46    _,
  47};
  48
  49const ModInfo = struct {
  50    root_dir_path: Entry.Index,
  51    dirs: std.AutoArrayHashMapUnmanaged(Unit.Index, void),
  52    files: std.AutoArrayHashMapUnmanaged(Zcu.File.Index, void),
  53
  54    fn deinit(mod_info: *ModInfo, gpa: Allocator) void {
  55        mod_info.dirs.deinit(gpa);
  56        mod_info.files.deinit(gpa);
  57        mod_info.* = undefined;
  58    }
  59};
  60
  61const DebugAbbrev = struct {
  62    section: Section,
  63    const unit: Unit.Index = @enumFromInt(0);
  64
  65    const header_bytes = 0;
  66
  67    const trailer_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.null));
  68};
  69
  70const DebugAranges = struct {
  71    section: Section,
  72
  73    fn headerBytes(dwarf: *Dwarf) u32 {
  74        return dwarf.unitLengthBytes() + 2 + dwarf.sectionOffsetBytes() + 1 + 1;
  75    }
  76
  77    fn trailerBytes(dwarf: *Dwarf) u32 {
  78        return @intFromEnum(dwarf.address_size) * 2;
  79    }
  80};
  81
  82const DebugFrame = struct {
  83    header: Header,
  84    section: Section,
  85
  86    const Format = enum { none, debug_frame, eh_frame };
  87    const Header = struct {
  88        format: Format,
  89        code_alignment_factor: u32,
  90        data_alignment_factor: i32,
  91        return_address_register: u32,
  92        initial_instructions: []const Cfa,
  93    };
  94
  95    fn headerBytes(dwarf: *Dwarf) u32 {
  96        const target = &dwarf.bin_file.comp.root_mod.resolved_target.result;
  97        return @intCast(switch (dwarf.debug_frame.header.format) {
  98            .none => return 0,
  99            .debug_frame => dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() + 1 + "\x00".len + 1 + 1,
 100            .eh_frame => dwarf.unitLengthBytes() + 4 + 1 + "zR\x00".len +
 101                uleb128Bytes(1) + 1,
 102        } + switch (target.cpu.arch) {
 103            .x86_64 => len: {
 104                dev.check(.x86_64_backend);
 105                const Register = @import("../codegen/x86_64/bits.zig").Register;
 106                break :len uleb128Bytes(1) + sleb128Bytes(-8) + uleb128Bytes(Register.rip.dwarfNum()) +
 107                    1 + uleb128Bytes(Register.rsp.dwarfNum()) + sleb128Bytes(-1) +
 108                    1 + uleb128Bytes(1);
 109            },
 110            else => unreachable,
 111        });
 112    }
 113
 114    fn trailerBytes(dwarf: *Dwarf) u32 {
 115        return @intCast(switch (dwarf.debug_frame.header.format) {
 116            .none => 0,
 117            .debug_frame => dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() + 1 + "\x00".len + 1 + 1 + uleb128Bytes(1) + sleb128Bytes(1) + uleb128Bytes(0),
 118            .eh_frame => dwarf.unitLengthBytes() + 4 + 1 + "\x00".len + uleb128Bytes(1) + sleb128Bytes(1) + uleb128Bytes(0),
 119        });
 120    }
 121};
 122
 123const DebugInfo = struct {
 124    section: Section,
 125
 126    fn headerBytes(dwarf: *Dwarf) u32 {
 127        return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() +
 128            uleb128Bytes(@intFromEnum(AbbrevCode.compile_unit)) + 1 + dwarf.sectionOffsetBytes() * 6 + uleb128Bytes(0) +
 129            uleb128Bytes(@intFromEnum(AbbrevCode.module)) + dwarf.sectionOffsetBytes() + uleb128Bytes(0);
 130    }
 131
 132    fn declEntryLineOff(dwarf: *Dwarf) u32 {
 133        return AbbrevCode.decl_bytes + dwarf.sectionOffsetBytes();
 134    }
 135
 136    fn declAbbrevCode(debug_info: *DebugInfo, unit: Unit.Index, entry: Entry.Index) !AbbrevCode {
 137        const dwarf: *Dwarf = @fieldParentPtr("debug_info", debug_info);
 138        const unit_ptr = debug_info.section.getUnit(unit);
 139        const entry_ptr = unit_ptr.getEntry(entry);
 140        if (entry_ptr.len < AbbrevCode.decl_bytes) return .null;
 141        var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined;
 142        if (try dwarf.getFile().?.preadAll(
 143            &abbrev_code_buf,
 144            debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off,
 145        ) != abbrev_code_buf.len) return error.InputOutput;
 146        var abbrev_code_reader: std.Io.Reader = .fixed(&abbrev_code_buf);
 147        return @enumFromInt(
 148            abbrev_code_reader.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable,
 149        );
 150    }
 151
 152    const trailer_bytes = 1 + 1;
 153};
 154
 155const DebugLine = struct {
 156    header: Header,
 157    section: Section,
 158
 159    const Header = struct {
 160        minimum_instruction_length: u8,
 161        maximum_operations_per_instruction: u8,
 162        default_is_stmt: bool,
 163        line_base: i8,
 164        line_range: u8,
 165        opcode_base: u8,
 166    };
 167
 168    fn dirIndexInfo(dir_count: u32) struct { bytes: u8, form: DeclValEnum(DW.FORM) } {
 169        return if (dir_count <= 1 << 8)
 170            .{ .bytes = 1, .form = .data1 }
 171        else if (dir_count <= 1 << 16)
 172            .{ .bytes = 2, .form = .data2 }
 173        else
 174            unreachable;
 175    }
 176
 177    fn headerBytes(dwarf: *Dwarf, dir_count: u32, file_count: u32) u32 {
 178        const dir_index_info = dirIndexInfo(dir_count);
 179        return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() + 1 + 1 + 1 + 1 + 1 + 1 + 1 * (dwarf.debug_line.header.opcode_base - 1) +
 180            1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(dir_count) + (dwarf.sectionOffsetBytes()) * dir_count +
 181            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;
 182    }
 183
 184    const trailer_bytes = 1 + uleb128Bytes(1) + 1;
 185};
 186
 187const DebugLocLists = struct {
 188    section: Section,
 189
 190    fn baseOffset(dwarf: *Dwarf) u32 {
 191        return dwarf.unitLengthBytes() + 2 + 1 + 1 + 4;
 192    }
 193
 194    fn headerBytes(dwarf: *Dwarf) u32 {
 195        return baseOffset(dwarf);
 196    }
 197
 198    const trailer_bytes = 0;
 199};
 200
 201const DebugRngLists = struct {
 202    section: Section,
 203
 204    const baseOffset = DebugLocLists.baseOffset;
 205
 206    fn headerBytes(dwarf: *Dwarf) u32 {
 207        return baseOffset(dwarf) + dwarf.sectionOffsetBytes() * 1;
 208    }
 209
 210    const trailer_bytes = 1;
 211};
 212
 213const StringSection = struct {
 214    contents: std.ArrayList(u8),
 215    map: std.AutoArrayHashMapUnmanaged(void, void),
 216    section: Section,
 217
 218    const unit: Unit.Index = @enumFromInt(0);
 219
 220    const init: StringSection = .{
 221        .contents = .empty,
 222        .map = .empty,
 223        .section = Section.init,
 224    };
 225
 226    fn deinit(str_sec: *StringSection, gpa: Allocator) void {
 227        str_sec.contents.deinit(gpa);
 228        str_sec.map.deinit(gpa);
 229        str_sec.section.deinit(gpa);
 230    }
 231
 232    fn addString(str_sec: *StringSection, dwarf: *Dwarf, str: []const u8) UpdateError!Entry.Index {
 233        const gop = try str_sec.map.getOrPutAdapted(dwarf.gpa, str, Adapter{ .str_sec = str_sec });
 234        const entry: Entry.Index = @enumFromInt(gop.index);
 235        if (!gop.found_existing) {
 236            errdefer _ = str_sec.map.pop();
 237            const unit_ptr = str_sec.section.getUnit(unit);
 238            assert(try str_sec.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
 239            errdefer _ = unit_ptr.entries.pop();
 240            const entry_ptr = unit_ptr.getEntry(entry);
 241            if (unit_ptr.last.unwrap()) |last_entry|
 242                unit_ptr.getEntry(last_entry).next = entry.toOptional();
 243            entry_ptr.prev = unit_ptr.last;
 244            unit_ptr.last = entry.toOptional();
 245            entry_ptr.off = @intCast(str_sec.contents.items.len);
 246            entry_ptr.len = @intCast(str.len + 1);
 247            try str_sec.contents.ensureUnusedCapacity(dwarf.gpa, str.len + 1);
 248            str_sec.contents.appendSliceAssumeCapacity(str);
 249            str_sec.contents.appendAssumeCapacity(0);
 250            str_sec.section.dirty = true;
 251        }
 252        return entry;
 253    }
 254
 255    const Adapter = struct {
 256        str_sec: *StringSection,
 257
 258        pub fn hash(_: Adapter, key: []const u8) u32 {
 259            return @truncate(std.hash.Wyhash.hash(0, key));
 260        }
 261
 262        pub fn eql(adapter: Adapter, key: []const u8, _: void, rhs_index: usize) bool {
 263            const entry = adapter.str_sec.section.getUnit(unit).getEntry(@enumFromInt(rhs_index));
 264            return std.mem.eql(u8, key, adapter.str_sec.contents.items[entry.off..][0 .. entry.len - 1 :0]);
 265        }
 266    };
 267};
 268
 269/// A linker section containing a sequence of `Unit`s.
 270pub const Section = struct {
 271    dirty: bool,
 272    pad_entries_to_ideal: bool,
 273    alignment: InternPool.Alignment,
 274    index: u32,
 275    first: Unit.Index.Optional,
 276    last: Unit.Index.Optional,
 277    len: u64,
 278    units: std.ArrayList(Unit),
 279
 280    pub const Index = enum {
 281        debug_abbrev,
 282        debug_aranges,
 283        debug_frame,
 284        debug_info,
 285        debug_line,
 286        debug_line_str,
 287        debug_loclists,
 288        debug_rnglists,
 289        debug_str,
 290    };
 291
 292    const init: Section = .{
 293        .dirty = true,
 294        .pad_entries_to_ideal = true,
 295        .alignment = .@"1",
 296        .index = std.math.maxInt(u32),
 297        .first = .none,
 298        .last = .none,
 299        .units = .empty,
 300        .len = 0,
 301    };
 302
 303    fn deinit(sec: *Section, gpa: Allocator) void {
 304        for (sec.units.items) |*unit| unit.deinit(gpa);
 305        sec.units.deinit(gpa);
 306        sec.* = undefined;
 307    }
 308
 309    fn off(sec: Section, dwarf: *Dwarf) u64 {
 310        if (dwarf.bin_file.cast(.elf)) |elf_file| {
 311            const zo = elf_file.zigObjectPtr().?;
 312            const atom = zo.symbol(sec.index).atom(elf_file).?;
 313            return atom.offset(elf_file);
 314        } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
 315            const header = if (macho_file.d_sym) |d_sym|
 316                d_sym.sections.items[sec.index]
 317            else
 318                macho_file.sections.items(.header)[sec.index];
 319            return header.offset;
 320        } else unreachable;
 321    }
 322
 323    fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index {
 324        const unit: Unit.Index = @enumFromInt(sec.units.items.len);
 325        const unit_ptr = try sec.units.addOne(dwarf.gpa);
 326        errdefer sec.popUnit(dwarf.gpa);
 327        const aligned_header_len: u32 = @intCast(sec.alignment.forward(header_len));
 328        const aligned_trailer_len: u32 = @intCast(sec.alignment.forward(trailer_len));
 329        unit_ptr.* = .{
 330            .prev = sec.last,
 331            .next = .none,
 332            .first = .none,
 333            .last = .none,
 334            .free = .none,
 335            .header_len = aligned_header_len,
 336            .trailer_len = aligned_trailer_len,
 337            .off = 0,
 338            .len = aligned_header_len + aligned_trailer_len,
 339            .entries = .empty,
 340            .cross_unit_relocs = .empty,
 341            .cross_section_relocs = .empty,
 342        };
 343        if (sec.last.unwrap()) |last_unit| {
 344            const last_unit_ptr = sec.getUnit(last_unit);
 345            last_unit_ptr.next = unit.toOptional();
 346            unit_ptr.off = last_unit_ptr.off + sec.padUnitToIdeal(last_unit_ptr.len);
 347        }
 348        if (sec.first == .none)
 349            sec.first = unit.toOptional();
 350        sec.last = unit.toOptional();
 351        try sec.resize(dwarf, unit_ptr.off + sec.padUnitToIdeal(unit_ptr.len));
 352        return unit;
 353    }
 354
 355    fn unlinkUnit(sec: *Section, unit: Unit.Index) void {
 356        const unit_ptr = sec.getUnit(unit);
 357        if (unit_ptr.prev.unwrap()) |prev_unit| sec.getUnit(prev_unit).next = unit_ptr.next;
 358        if (unit_ptr.next.unwrap()) |next_unit| sec.getUnit(next_unit).prev = unit_ptr.prev;
 359        if (sec.first == unit.toOptional()) sec.first = unit_ptr.next;
 360        if (sec.last == unit.toOptional()) sec.last = unit_ptr.prev;
 361    }
 362
 363    fn popUnit(sec: *Section, gpa: Allocator) void {
 364        const unit_index: Unit.Index = @enumFromInt(sec.units.items.len - 1);
 365        sec.unlinkUnit(unit_index);
 366        var unit = sec.units.pop().?;
 367        unit.deinit(gpa);
 368    }
 369
 370    pub fn getUnit(sec: *Section, unit: Unit.Index) *Unit {
 371        return &sec.units.items[@intFromEnum(unit)];
 372    }
 373
 374    fn resizeEntry(
 375        sec: *Section,
 376        unit: Unit.Index,
 377        entry: Entry.Index,
 378        dwarf: *Dwarf,
 379        len: u32,
 380    ) (UpdateError || Writer.Error)!void {
 381        const unit_ptr = sec.getUnit(unit);
 382        const entry_ptr = unit_ptr.getEntry(entry);
 383        if (len > 0) {
 384            if (entry_ptr.len == 0) {
 385                assert(entry_ptr.prev == .none and entry_ptr.next == .none);
 386                entry_ptr.off = if (unit_ptr.last.unwrap()) |last_entry| off: {
 387                    const last_entry_ptr = unit_ptr.getEntry(last_entry);
 388                    last_entry_ptr.next = entry.toOptional();
 389                    break :off last_entry_ptr.off + sec.padEntryToIdeal(last_entry_ptr.len);
 390                } else 0;
 391                entry_ptr.prev = unit_ptr.last;
 392                unit_ptr.last = entry.toOptional();
 393                if (unit_ptr.first == .none) unit_ptr.first = unit_ptr.last;
 394                if (entry_ptr.prev.unwrap()) |prev_entry| try unit_ptr.getEntry(prev_entry).pad(unit_ptr, sec, dwarf);
 395            }
 396            try entry_ptr.resize(unit_ptr, sec, dwarf, len);
 397        }
 398        assert(entry_ptr.len == len);
 399    }
 400
 401    fn replaceEntry(
 402        sec: *Section,
 403        unit: Unit.Index,
 404        entry: Entry.Index,
 405        dwarf: *Dwarf,
 406        contents: []const u8,
 407    ) (UpdateError || Writer.Error)!void {
 408        try sec.resizeEntry(unit, entry, dwarf, @intCast(contents.len));
 409        const unit_ptr = sec.getUnit(unit);
 410        try unit_ptr.getEntry(entry).replace(unit_ptr, sec, dwarf, contents);
 411    }
 412
 413    fn freeEntry(
 414        sec: *Section,
 415        unit: Unit.Index,
 416        entry: Entry.Index,
 417        dwarf: *Dwarf,
 418    ) (UpdateError || Writer.Error)!void {
 419        const unit_ptr = sec.getUnit(unit);
 420        const entry_ptr = unit_ptr.getEntry(entry);
 421        if (entry_ptr.len > 0) {
 422            if (entry_ptr.next.unwrap()) |next_entry| unit_ptr.getEntry(next_entry).prev = entry_ptr.prev;
 423            if (entry_ptr.prev.unwrap()) |prev_entry| {
 424                const prev_entry_ptr = unit_ptr.getEntry(prev_entry);
 425                prev_entry_ptr.next = entry_ptr.next;
 426                try prev_entry_ptr.pad(unit_ptr, sec, dwarf);
 427            } else {
 428                unit_ptr.trim();
 429                sec.trim(dwarf);
 430            }
 431        } else assert(entry_ptr.prev == .none and entry_ptr.next == .none);
 432        entry_ptr.prev = .none;
 433        entry_ptr.next = unit_ptr.free;
 434        entry_ptr.off = 0;
 435        entry_ptr.len = 0;
 436        entry_ptr.clear();
 437        unit_ptr.free = entry.toOptional();
 438    }
 439
 440    fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {
 441        if (len <= sec.len) return;
 442        if (dwarf.bin_file.cast(.elf)) |elf_file| {
 443            const zo = elf_file.zigObjectPtr().?;
 444            const atom = zo.symbol(sec.index).atom(elf_file).?;
 445            atom.size = len;
 446            atom.alignment = sec.alignment;
 447            sec.len = len;
 448            try zo.allocateAtom(atom, false, elf_file);
 449        } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
 450            const header = if (macho_file.d_sym) |*d_sym| header: {
 451                try d_sym.growSection(@intCast(sec.index), len, true, macho_file);
 452                break :header &d_sym.sections.items[sec.index];
 453            } else header: {
 454                try macho_file.growSection(@intCast(sec.index), len);
 455                break :header &macho_file.sections.items(.header)[sec.index];
 456            };
 457            sec.len = header.size;
 458        }
 459    }
 460
 461    fn trim(sec: *Section, dwarf: *Dwarf) void {
 462        const len = sec.getUnit(sec.first.unwrap() orelse return).off;
 463        if (len == 0) return;
 464        for (sec.units.items) |*unit| unit.off -= len;
 465        sec.len -= len;
 466        if (dwarf.bin_file.cast(.elf)) |elf_file| {
 467            const zo = elf_file.zigObjectPtr().?;
 468            const atom = zo.symbol(sec.index).atom(elf_file).?;
 469            if (atom.prevAtom(elf_file)) |_| {
 470                atom.value += len;
 471            } else {
 472                const shdr = &elf_file.sections.items(.shdr)[atom.output_section_index];
 473                shdr.sh_offset += len;
 474                shdr.sh_size -= len;
 475                atom.value = 0;
 476            }
 477            atom.size -= len;
 478        } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
 479            const header = if (macho_file.d_sym) |*d_sym|
 480                &d_sym.sections.items[sec.index]
 481            else
 482                &macho_file.sections.items(.header)[sec.index];
 483            header.offset += @intCast(len);
 484            header.size -= len;
 485        }
 486    }
 487
 488    fn resolveRelocs(sec: *Section, dwarf: *Dwarf) RelocError!void {
 489        for (sec.units.items) |*unit| try unit.resolveRelocs(sec, dwarf);
 490    }
 491
 492    fn padUnitToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) {
 493        return @intCast(sec.alignment.forward(Dwarf.padToIdeal(actual_size)));
 494    }
 495
 496    fn padEntryToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) {
 497        return @intCast(sec.alignment.forward(if (sec.pad_entries_to_ideal) Dwarf.padToIdeal(actual_size) else actual_size));
 498    }
 499};
 500
 501/// A unit within a `Section` containing a sequence of `Entry`s.
 502const Unit = struct {
 503    prev: Index.Optional,
 504    next: Index.Optional,
 505    first: Entry.Index.Optional,
 506    last: Entry.Index.Optional,
 507    free: Entry.Index.Optional,
 508    /// offset within containing section
 509    off: u32,
 510    header_len: u32,
 511    trailer_len: u32,
 512    /// data length in bytes
 513    len: u32,
 514    entries: std.ArrayList(Entry),
 515    cross_unit_relocs: std.ArrayList(CrossUnitReloc),
 516    cross_section_relocs: std.ArrayList(CrossSectionReloc),
 517
 518    const Index = enum(u32) {
 519        main,
 520        _,
 521
 522        const Optional = enum(u32) {
 523            none = std.math.maxInt(u32),
 524            _,
 525
 526            pub fn unwrap(uio: Optional) ?Index {
 527                return if (uio != .none) @enumFromInt(@intFromEnum(uio)) else null;
 528            }
 529        };
 530
 531        fn toOptional(ui: Index) Optional {
 532            return @enumFromInt(@intFromEnum(ui));
 533        }
 534    };
 535
 536    fn clear(unit: *Unit) void {
 537        unit.cross_unit_relocs.clearRetainingCapacity();
 538        unit.cross_section_relocs.clearRetainingCapacity();
 539    }
 540
 541    fn deinit(unit: *Unit, gpa: Allocator) void {
 542        for (unit.entries.items) |*entry| entry.deinit(gpa);
 543        unit.entries.deinit(gpa);
 544        unit.cross_unit_relocs.deinit(gpa);
 545        unit.cross_section_relocs.deinit(gpa);
 546        unit.* = undefined;
 547    }
 548
 549    fn addEntry(unit: *Unit, gpa: Allocator) Allocator.Error!Entry.Index {
 550        if (unit.free.unwrap()) |entry| {
 551            const entry_ptr = unit.getEntry(entry);
 552            unit.free = entry_ptr.next;
 553            entry_ptr.next = .none;
 554            return entry;
 555        }
 556        const entry: Entry.Index = @enumFromInt(unit.entries.items.len);
 557        const entry_ptr = try unit.entries.addOne(gpa);
 558        entry_ptr.* = .{
 559            .prev = .none,
 560            .next = .none,
 561            .off = 0,
 562            .len = 0,
 563            .cross_entry_relocs = .empty,
 564            .cross_unit_relocs = .empty,
 565            .cross_section_relocs = .empty,
 566            .external_relocs = .empty,
 567        };
 568        return entry;
 569    }
 570
 571    pub fn getEntry(unit: *Unit, entry: Entry.Index) *Entry {
 572        return &unit.entries.items[@intFromEnum(entry)];
 573    }
 574
 575    fn resize(unit_ptr: *Unit, sec: *Section, dwarf: *Dwarf, extra_header_len: u32, len: u32) UpdateError!void {
 576        const end = if (unit_ptr.next.unwrap()) |next_unit|
 577            sec.getUnit(next_unit).off
 578        else
 579            sec.len;
 580        if (extra_header_len > 0 or unit_ptr.off + len > end) {
 581            unit_ptr.len = @min(unit_ptr.len, len);
 582            var new_off = unit_ptr.off;
 583            if (unit_ptr.next.unwrap()) |next_unit| {
 584                const next_unit_ptr = sec.getUnit(next_unit);
 585                if (unit_ptr.prev.unwrap()) |prev_unit|
 586                    sec.getUnit(prev_unit).next = unit_ptr.next
 587                else
 588                    sec.first = unit_ptr.next;
 589                const unit = next_unit_ptr.prev;
 590                next_unit_ptr.prev = unit_ptr.prev;
 591                const last_unit_ptr = sec.getUnit(sec.last.unwrap().?);
 592                last_unit_ptr.next = unit;
 593                unit_ptr.prev = sec.last;
 594                unit_ptr.next = .none;
 595                new_off = last_unit_ptr.off + sec.padUnitToIdeal(last_unit_ptr.len);
 596                sec.last = unit;
 597                sec.dirty = true;
 598            } else if (extra_header_len > 0) {
 599                // `copyRangeAll` in `move` does not support overlapping ranges
 600                // so make sure new location is disjoint from current location.
 601                new_off += unit_ptr.len -| extra_header_len;
 602            }
 603            try sec.resize(dwarf, new_off + len);
 604            try unit_ptr.move(sec, dwarf, new_off + extra_header_len);
 605            unit_ptr.off -= extra_header_len;
 606            unit_ptr.header_len += extra_header_len;
 607            sec.trim(dwarf);
 608        }
 609        unit_ptr.len = len;
 610    }
 611
 612    fn trim(unit: *Unit) void {
 613        const len = unit.getEntry(unit.first.unwrap() orelse return).off;
 614        if (len == 0) return;
 615        for (unit.entries.items) |*entry| entry.off -= len;
 616        unit.off += len;
 617        unit.len -= len;
 618    }
 619
 620    fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {
 621        if (unit.off == new_off) return;
 622        const n = try dwarf.getFile().?.copyRangeAll(
 623            sec.off(dwarf) + unit.off,
 624            dwarf.getFile().?,
 625            sec.off(dwarf) + new_off,
 626            unit.len,
 627        );
 628        if (n != unit.len) return error.InputOutput;
 629        unit.off = new_off;
 630    }
 631
 632    fn resizeHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void {
 633        unit.trim();
 634        if (unit.header_len == len) return;
 635        const available_len = if (unit.prev.unwrap()) |prev_unit| prev_excess: {
 636            const prev_unit_ptr = sec.getUnit(prev_unit);
 637            break :prev_excess unit.off - prev_unit_ptr.off - prev_unit_ptr.len;
 638        } else 0;
 639        if (available_len + unit.header_len < len)
 640            try unit.resize(sec, dwarf, len - unit.header_len, unit.len - unit.header_len + len);
 641        if (unit.header_len > len) {
 642            const excess_header_len = unit.header_len - len;
 643            unit.off += excess_header_len;
 644            unit.header_len -= excess_header_len;
 645            unit.len -= excess_header_len;
 646        } else if (unit.header_len < len) {
 647            const needed_header_len = len - unit.header_len;
 648            unit.off -= needed_header_len;
 649            unit.header_len += needed_header_len;
 650            unit.len += needed_header_len;
 651        }
 652        assert(unit.header_len == len);
 653        sec.trim(dwarf);
 654    }
 655
 656    fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
 657        assert(contents.len == unit.header_len);
 658        try dwarf.getFile().?.pwriteAll(contents, sec.off(dwarf) + unit.off);
 659    }
 660
 661    fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
 662        const start = unit.off + unit.header_len + if (unit.last.unwrap()) |last_entry| end: {
 663            const last_entry_ptr = unit.getEntry(last_entry);
 664            break :end last_entry_ptr.off + last_entry_ptr.len;
 665        } else 0;
 666        const end = if (unit.next.unwrap()) |next_unit| sec.getUnit(next_unit).off else sec.len;
 667        const len: usize = @intCast(end - start);
 668        assert(len >= unit.trailer_len);
 669        if (sec == &dwarf.debug_line.section) {
 670            var buf: [1 + uleb128Bytes(std.math.maxInt(u32)) + 1]u8 = undefined;
 671            var fw: Writer = .fixed(&buf);
 672            fw.writeByte(DW.LNS.extended_op) catch unreachable;
 673            const extended_op_bytes = fw.end;
 674            var op_len_bytes: u5 = 1;
 675            while (true) switch (std.math.order(len - extended_op_bytes - op_len_bytes, @as(u32, 1) << 7 * op_len_bytes)) {
 676                .lt => break fw.writeUleb128(len - extended_op_bytes - op_len_bytes) catch unreachable,
 677                .eq => {
 678                    // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
 679                    op_len_bytes += 1;
 680                    std.leb.writeUnsignedExtended(
 681                        fw.writableSlice(op_len_bytes) catch unreachable,
 682                        len - extended_op_bytes - op_len_bytes,
 683                    );
 684                    break;
 685                },
 686                .gt => op_len_bytes += 1,
 687            };
 688            assert(fw.end == extended_op_bytes + op_len_bytes);
 689            fw.writeByte(DW.LNE.padding) catch unreachable;
 690            assert(fw.end >= unit.trailer_len and fw.end <= len);
 691            return dwarf.getFile().?.pwriteAll(fw.buffered(), sec.off(dwarf) + start);
 692        }
 693        var trailer_aw: Writer.Allocating = try .initCapacity(dwarf.gpa, len);
 694        defer trailer_aw.deinit();
 695        const tw = &trailer_aw.writer;
 696        const fill_byte: u8 = if (sec == &dwarf.debug_abbrev.section) fill: {
 697            tw.writeUleb128(@intFromEnum(AbbrevCode.null)) catch unreachable;
 698            assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1);
 699            break :fill @intFromEnum(AbbrevCode.null);
 700        } else if (sec == &dwarf.debug_aranges.section) fill: {
 701            tw.splatByteAll(0, @intFromEnum(dwarf.address_size) * 2) catch unreachable;
 702            break :fill 0;
 703        } else if (sec == &dwarf.debug_frame.section) fill: {
 704            switch (dwarf.debug_frame.header.format) {
 705                .none => {},
 706                .debug_frame, .eh_frame => |format| {
 707                    const unit_len = len - dwarf.unitLengthBytes();
 708                    switch (dwarf.format) {
 709                        .@"32" => tw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
 710                        .@"64" => {
 711                            tw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
 712                            tw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
 713                        },
 714                    }
 715                    switch (format) {
 716                        .none => unreachable,
 717                        .debug_frame => {
 718                            switch (dwarf.format) {
 719                                .@"32" => tw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable,
 720                                .@"64" => tw.writeInt(u64, std.math.maxInt(u64), dwarf.endian) catch unreachable,
 721                            }
 722                            tw.writeByte(4) catch unreachable;
 723                            tw.writeAll("\x00") catch unreachable;
 724                            tw.writeByte(@intFromEnum(dwarf.address_size)) catch unreachable;
 725                            tw.writeByte(0) catch unreachable;
 726                        },
 727                        .eh_frame => {
 728                            tw.writeInt(u32, 0, dwarf.endian) catch unreachable;
 729                            tw.writeByte(1) catch unreachable;
 730                            tw.writeAll("\x00") catch unreachable;
 731                        },
 732                    }
 733                    tw.writeUleb128(1) catch unreachable;
 734                    tw.writeSleb128(1) catch unreachable;
 735                    tw.writeUleb128(0) catch unreachable;
 736                },
 737            }
 738            tw.splatByteAll(DW.CFA.nop, unit.trailer_len - tw.end) catch unreachable;
 739            break :fill DW.CFA.nop;
 740        } else if (sec == &dwarf.debug_info.section) fill: {
 741            for (0..2) |_| tw.writeUleb128(@intFromEnum(AbbrevCode.null)) catch unreachable;
 742            assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1);
 743            break :fill @intFromEnum(AbbrevCode.null);
 744        } else if (sec == &dwarf.debug_rnglists.section) fill: {
 745            tw.writeByte(DW.RLE.end_of_list) catch unreachable;
 746            break :fill DW.RLE.end_of_list;
 747        } else unreachable;
 748        assert(tw.end == unit.trailer_len);
 749        tw.splatByteAll(fill_byte, len - unit.trailer_len) catch unreachable;
 750        assert(tw.end == len);
 751        try dwarf.getFile().?.pwriteAll(trailer_aw.written(), sec.off(dwarf) + start);
 752    }
 753
 754    fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {
 755        const unit_off = sec.off(dwarf) + unit.off;
 756        for (unit.cross_unit_relocs.items) |reloc| {
 757            const target_unit = sec.getUnit(reloc.target_unit);
 758            try dwarf.resolveReloc(
 759                unit_off + reloc.source_off,
 760                target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
 761                    target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(target_unit, sec, dwarf).off
 762                else
 763                    0) + reloc.target_off,
 764                dwarf.sectionOffsetBytes(),
 765            );
 766        }
 767        for (unit.cross_section_relocs.items) |reloc| {
 768            const target_sec = switch (reloc.target_sec) {
 769                inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section,
 770            };
 771            const target_unit = target_sec.getUnit(reloc.target_unit);
 772            try dwarf.resolveReloc(
 773                unit_off + reloc.source_off,
 774                target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
 775                    target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(target_unit, sec, dwarf).off
 776                else
 777                    0) + reloc.target_off,
 778                dwarf.sectionOffsetBytes(),
 779            );
 780        }
 781        for (unit.entries.items) |*entry| try entry.resolveRelocs(unit, sec, dwarf);
 782    }
 783};
 784
 785/// An indivisible entry within a `Unit` containing section-specific data.
 786const Entry = struct {
 787    prev: Index.Optional,
 788    next: Index.Optional,
 789    /// offset from end of containing unit header
 790    off: u32,
 791    /// data length in bytes
 792    len: u32,
 793    cross_entry_relocs: std.ArrayList(CrossEntryReloc),
 794    cross_unit_relocs: std.ArrayList(CrossUnitReloc),
 795    cross_section_relocs: std.ArrayList(CrossSectionReloc),
 796    external_relocs: std.ArrayList(ExternalReloc),
 797
 798    fn clear(entry: *Entry) void {
 799        entry.cross_entry_relocs.clearRetainingCapacity();
 800        entry.cross_unit_relocs.clearRetainingCapacity();
 801        entry.cross_section_relocs.clearRetainingCapacity();
 802        entry.external_relocs.clearRetainingCapacity();
 803    }
 804
 805    fn deinit(entry: *Entry, gpa: Allocator) void {
 806        entry.cross_entry_relocs.deinit(gpa);
 807        entry.cross_unit_relocs.deinit(gpa);
 808        entry.cross_section_relocs.deinit(gpa);
 809        entry.external_relocs.deinit(gpa);
 810        entry.* = undefined;
 811    }
 812
 813    const Index = enum(u32) {
 814        _,
 815
 816        const Optional = enum(u32) {
 817            none = std.math.maxInt(u32),
 818            _,
 819
 820            pub fn unwrap(eio: Optional) ?Index {
 821                return if (eio != .none) @enumFromInt(@intFromEnum(eio)) else null;
 822            }
 823        };
 824
 825        fn toOptional(ei: Index) Optional {
 826            return @enumFromInt(@intFromEnum(ei));
 827        }
 828    };
 829
 830    fn pad(
 831        entry: *Entry,
 832        unit: *Unit,
 833        sec: *Section,
 834        dwarf: *Dwarf,
 835    ) (UpdateError || Writer.Error)!void {
 836        assert(entry.len > 0);
 837        const start = entry.off + entry.len;
 838        if (sec == &dwarf.debug_frame.section) {
 839            const len = if (entry.next.unwrap()) |next_entry|
 840                unit.getEntry(next_entry).off - entry.off
 841            else
 842                entry.len;
 843            var unit_len_buf: [8]u8 = undefined;
 844            const unit_len_bytes = unit_len_buf[0..dwarf.sectionOffsetBytes()];
 845            dwarf.writeInt(unit_len_bytes, len - dwarf.unitLengthBytes());
 846            try dwarf.getFile().?.pwriteAll(unit_len_bytes, sec.off(dwarf) + unit.off + unit.header_len + entry.off);
 847            const buf = try dwarf.gpa.alloc(u8, len - entry.len);
 848            defer dwarf.gpa.free(buf);
 849            @memset(buf, DW.CFA.nop);
 850            try dwarf.getFile().?.pwriteAll(buf, sec.off(dwarf) + unit.off + unit.header_len + start);
 851            return;
 852        }
 853        const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;
 854        var buf: [
 855            @max(
 856                uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)),
 857                uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) + uleb128Bytes(std.math.maxInt(u32)),
 858                1 + uleb128Bytes(std.math.maxInt(u32)) + 1,
 859            )
 860        ]u8 = undefined;
 861        var fw: Writer = .fixed(&buf);
 862        if (sec == &dwarf.debug_info.section) switch (len) {
 863            0 => {},
 864            1 => fw.writeUleb128(try dwarf.refAbbrevCode(.pad_1)) catch unreachable,
 865            else => {
 866                fw.writeUleb128(try dwarf.refAbbrevCode(.pad_n)) catch unreachable;
 867                const abbrev_code_bytes = fw.end;
 868                var block_len_bytes: u5 = 1;
 869                while (true) switch (std.math.order(len - abbrev_code_bytes - block_len_bytes, @as(u32, 1) << 7 * block_len_bytes)) {
 870                    .lt => break fw.writeUleb128(len - abbrev_code_bytes - block_len_bytes) catch unreachable,
 871                    .eq => {
 872                        // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
 873                        block_len_bytes += 1;
 874                        std.leb.writeUnsignedExtended(
 875                            fw.writableSlice(block_len_bytes) catch unreachable,
 876                            len - abbrev_code_bytes - block_len_bytes,
 877                        );
 878                        break;
 879                    },
 880                    .gt => block_len_bytes += 1,
 881                };
 882                assert(fw.end == abbrev_code_bytes + block_len_bytes);
 883            },
 884        } else if (sec == &dwarf.debug_line.section) switch (len) {
 885            0 => {},
 886            1 => fw.writeByte(DW.LNS.const_add_pc) catch unreachable,
 887            else => {
 888                fw.writeByte(DW.LNS.extended_op) catch unreachable;
 889                const extended_op_bytes = fw.end;
 890                var op_len_bytes: u5 = 1;
 891                while (true) switch (std.math.order(len - extended_op_bytes - op_len_bytes, @as(u32, 1) << 7 * op_len_bytes)) {
 892                    .lt => break fw.writeUleb128(len - extended_op_bytes - op_len_bytes) catch unreachable,
 893                    .eq => {
 894                        // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
 895                        op_len_bytes += 1;
 896                        std.leb.writeUnsignedExtended(
 897                            fw.writableSlice(op_len_bytes) catch unreachable,
 898                            len - extended_op_bytes - op_len_bytes,
 899                        );
 900                        break;
 901                    },
 902                    .gt => op_len_bytes += 1,
 903                };
 904                assert(fw.end == extended_op_bytes + op_len_bytes);
 905                if (len > 2) fw.writeByte(DW.LNE.padding) catch unreachable;
 906            },
 907        } else assert(!sec.pad_entries_to_ideal and len == 0);
 908        assert(fw.end <= len);
 909        try dwarf.getFile().?.pwriteAll(fw.buffered(), sec.off(dwarf) + unit.off + unit.header_len + start);
 910    }
 911
 912    fn resize(
 913        entry_ptr: *Entry,
 914        unit: *Unit,
 915        sec: *Section,
 916        dwarf: *Dwarf,
 917        len: u32,
 918    ) (UpdateError || Writer.Error)!void {
 919        assert(len > 0);
 920        assert(sec.alignment.check(len));
 921        if (entry_ptr.len == len) return;
 922        const end = if (entry_ptr.next.unwrap()) |next_entry|
 923            unit.getEntry(next_entry).off
 924        else
 925            unit.len -| (unit.header_len + unit.trailer_len);
 926        if (entry_ptr.off + len > end) {
 927            if (entry_ptr.next.unwrap()) |next_entry| {
 928                if (entry_ptr.prev.unwrap()) |prev_entry| {
 929                    const prev_entry_ptr = unit.getEntry(prev_entry);
 930                    prev_entry_ptr.next = entry_ptr.next;
 931                    try prev_entry_ptr.pad(unit, sec, dwarf);
 932                } else unit.first = entry_ptr.next;
 933                const next_entry_ptr = unit.getEntry(next_entry);
 934                const entry = next_entry_ptr.prev;
 935                next_entry_ptr.prev = entry_ptr.prev;
 936                const last_entry_ptr = unit.getEntry(unit.last.unwrap().?);
 937                last_entry_ptr.next = entry;
 938                entry_ptr.prev = unit.last;
 939                entry_ptr.next = .none;
 940                entry_ptr.off = last_entry_ptr.off + sec.padEntryToIdeal(last_entry_ptr.len);
 941                unit.last = entry;
 942                try last_entry_ptr.pad(unit, sec, dwarf);
 943            }
 944            try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padEntryToIdeal(len) + unit.trailer_len));
 945        }
 946        entry_ptr.len = len;
 947        try entry_ptr.pad(unit, sec, dwarf);
 948    }
 949
 950    fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
 951        assert(contents.len == entry_ptr.len);
 952        try dwarf.getFile().?.pwriteAll(contents, sec.off(dwarf) + unit.off + unit.header_len + entry_ptr.off);
 953        if (false) {
 954            const buf = try dwarf.gpa.alloc(u8, sec.len);
 955            defer dwarf.gpa.free(buf);
 956            _ = try dwarf.getFile().?.preadAll(buf, sec.off(dwarf));
 957            log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{
 958                @intFromEnum(sec.first),
 959                @intFromEnum(sec.last),
 960                sec.off(dwarf),
 961                sec.len,
 962            });
 963            for (sec.units.items) |*unit_ptr| {
 964                log.info("  Unit{{ .prev = {}, .next = {}, .first = {}, .last = {}, .off = 0x{x}, .header_len = 0x{x}, .trailer_len = 0x{x}, .len = 0x{x} }}", .{
 965                    @intFromEnum(unit_ptr.prev),
 966                    @intFromEnum(unit_ptr.next),
 967                    @intFromEnum(unit_ptr.first),
 968                    @intFromEnum(unit_ptr.last),
 969                    unit_ptr.off,
 970                    unit_ptr.header_len,
 971                    unit_ptr.trailer_len,
 972                    unit_ptr.len,
 973                });
 974                for (unit_ptr.entries.items) |*entry| {
 975                    log.info("    Entry{{ .prev = {}, .next = {}, .off = 0x{x}, .len = 0x{x} }}", .{
 976                        @intFromEnum(entry.prev),
 977                        @intFromEnum(entry.next),
 978                        entry.off,
 979                        entry.len,
 980                    });
 981                }
 982            }
 983            std.debug.dumpHex(buf);
 984        }
 985    }
 986
 987    pub fn assertNonEmpty(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) *Entry {
 988        if (entry.len > 0) return entry;
 989        if (std.debug.runtime_safety) {
 990            log.err("missing {} from {s}", .{
 991                @as(Entry.Index, @enumFromInt(entry - unit.entries.items.ptr)),
 992                std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file|
 993                    elf_file.zigObjectPtr().?.symbol(sec.index).name(elf_file)
 994                else if (dwarf.bin_file.cast(.macho)) |macho_file|
 995                    if (macho_file.d_sym) |*d_sym|
 996                        &d_sym.sections.items[sec.index].segname
 997                    else
 998                        &macho_file.sections.items(.header)[sec.index].segname
 999                else
1000                    "?", 0),
1001            });
1002            const zcu = dwarf.bin_file.comp.zcu.?;
1003            const ip = &zcu.intern_pool;
1004            for (dwarf.types.keys(), dwarf.types.values()) |ty, other_entry| {
1005                const ty_unit: Unit.Index = if (Type.fromInterned(ty).typeDeclInst(zcu)) |inst_index|
1006                    dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod.?) catch unreachable
1007                else
1008                    .main;
1009                if (sec.getUnit(ty_unit) == unit and unit.getEntry(other_entry) == entry)
1010                    log.err("missing Type({f}({d}))", .{
1011                        Type.fromInterned(ty).fmt(.{ .tid = .main, .zcu = zcu }),
1012                        @intFromEnum(ty),
1013                    });
1014            }
1015            for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| {
1016                const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFile(ip)).mod.?) catch unreachable;
1017                if (sec.getUnit(nav_unit) == unit and unit.getEntry(other_entry) == entry)
1018                    log.err("missing Nav({f}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) });
1019            }
1020        }
1021        @panic("missing dwarf relocation target");
1022    }
1023
1024    fn resolveRelocs(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {
1025        const entry_off = sec.off(dwarf) + unit.off + unit.header_len + entry.off;
1026        for (entry.cross_entry_relocs.items) |reloc| {
1027            try dwarf.resolveReloc(
1028                entry_off + reloc.source_off,
1029                unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off,
1030                dwarf.sectionOffsetBytes(),
1031            );
1032        }
1033        for (entry.cross_unit_relocs.items) |reloc| {
1034            const target_unit = sec.getUnit(reloc.target_unit);
1035            try dwarf.resolveReloc(
1036                entry_off + reloc.source_off,
1037                target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
1038                    target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(target_unit, sec, dwarf).off
1039                else
1040                    0) + reloc.target_off,
1041                dwarf.sectionOffsetBytes(),
1042            );
1043        }
1044        for (entry.cross_section_relocs.items) |reloc| {
1045            const target_sec = switch (reloc.target_sec) {
1046                inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section,
1047            };
1048            const target_unit = target_sec.getUnit(reloc.target_unit);
1049            try dwarf.resolveReloc(
1050                entry_off + reloc.source_off,
1051                target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
1052                    target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(target_unit, sec, dwarf).off
1053                else
1054                    0) + reloc.target_off,
1055                dwarf.sectionOffsetBytes(),
1056            );
1057        }
1058        if (sec == &dwarf.debug_frame.section) switch (DebugFrame.format(dwarf)) {
1059            .none, .debug_frame => {},
1060            .eh_frame => return if (dwarf.bin_file.cast(.elf)) |elf_file| {
1061                const zo = elf_file.zigObjectPtr().?;
1062                const shndx = zo.symbol(sec.index).atom(elf_file).?.output_section_index;
1063                const entry_addr: i64 = @intCast(entry_off - sec.off(dwarf) + elf_file.shdrs.items[shndx].sh_addr);
1064                for (entry.external_relocs.items) |reloc| {
1065                    const symbol = zo.symbol(reloc.target_sym);
1066                    try dwarf.resolveReloc(
1067                        entry_off + reloc.source_off,
1068                        @bitCast((symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off))) -
1069                            (entry_addr + reloc.source_off + 4)),
1070                        4,
1071                    );
1072                }
1073            } else unreachable,
1074        };
1075        if (dwarf.bin_file.cast(.elf)) |elf_file| {
1076            const zo = elf_file.zigObjectPtr().?;
1077            for (entry.external_relocs.items) |reloc| {
1078                const symbol = zo.symbol(reloc.target_sym);
1079                try dwarf.resolveReloc(
1080                    entry_off + reloc.source_off,
1081                    @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) -
1082                        if (symbol.flags.is_tls) elf_file.dtpAddress() else 0),
1083                    @intFromEnum(dwarf.address_size),
1084                );
1085            }
1086        } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
1087            const zo = macho_file.getZigObject().?;
1088            for (entry.external_relocs.items) |reloc| {
1089                const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
1090                try dwarf.resolveReloc(
1091                    entry_off + reloc.source_off,
1092                    ref.getSymbol(macho_file).?.getAddress(.{}, macho_file) + @as(i64, @intCast(reloc.target_off)),
1093                    @intFromEnum(dwarf.address_size),
1094                );
1095            }
1096        }
1097    }
1098};
1099
1100const CrossEntryReloc = struct {
1101    source_off: u32 = 0,
1102    target_entry: Entry.Index.Optional = .none,
1103    target_off: u32 = 0,
1104};
1105const CrossUnitReloc = struct {
1106    source_off: u32 = 0,
1107    target_unit: Unit.Index,
1108    target_entry: Entry.Index.Optional = .none,
1109    target_off: u32 = 0,
1110};
1111const CrossSectionReloc = struct {
1112    source_off: u32 = 0,
1113    target_sec: Section.Index,
1114    target_unit: Unit.Index,
1115    target_entry: Entry.Index.Optional = .none,
1116    target_off: u32 = 0,
1117};
1118const ExternalReloc = struct {
1119    source_off: u32 = 0,
1120    target_sym: u32,
1121    target_off: u64 = 0,
1122};
1123
1124pub const Loc = union(enum) {
1125    empty,
1126    addr_reloc: u32,
1127    deref: *const Loc,
1128    constu: u64,
1129    consts: i64,
1130    plus: Bin,
1131    reg: u32,
1132    breg: u32,
1133    push_object_address,
1134    call: struct {
1135        args: []const Loc = &.{},
1136        unit: Unit.Index,
1137        entry: Entry.Index,
1138    },
1139    form_tls_address: *const Loc,
1140    implicit_value: []const u8,
1141    stack_value: *const Loc,
1142    implicit_pointer: struct {
1143        unit: Unit.Index,
1144        entry: Entry.Index,
1145        offset: i65,
1146    },
1147    wasm_ext: union(enum) {
1148        local: u32,
1149        global: u32,
1150        operand_stack: u32,
1151    },
1152
1153    pub const Bin = struct { *const Loc, *const Loc };
1154
1155    fn getConst(loc: Loc, comptime Int: type) ?Int {
1156        return switch (loc) {
1157            .constu => |constu| std.math.cast(Int, constu),
1158            .consts => |consts| std.math.cast(Int, consts),
1159            else => null,
1160        };
1161    }
1162
1163    fn getBaseReg(loc: Loc) ?u32 {
1164        return switch (loc) {
1165            .breg => |breg| breg,
1166            else => null,
1167        };
1168    }
1169
1170    fn writeReg(reg: u32, op0: u8, opx: u8, writer: *Writer) Writer.Error!void {
1171        if (std.math.cast(u5, reg)) |small_reg| {
1172            try writer.writeByte(op0 + small_reg);
1173        } else {
1174            try writer.writeByte(opx);
1175            try writer.writeUleb128(reg);
1176        }
1177    }
1178
1179    fn write(loc: Loc, adapter: anytype) (UpdateError || Writer.Error)!void {
1180        const writer = adapter.writer();
1181        switch (loc) {
1182            .empty => {},
1183            .addr_reloc => |sym_index| {
1184                try writer.writeByte(DW.OP.addr);
1185                try adapter.addrSym(sym_index);
1186            },
1187            .deref => |addr| {
1188                try addr.write(adapter);
1189                try writer.writeByte(DW.OP.deref);
1190            },
1191            .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
1192                try writer.writeByte(@as(u8, DW.OP.lit0) + lit);
1193            } else if (std.math.cast(u8, constu)) |const1u| {
1194                try writer.writeAll(&.{ DW.OP.const1u, const1u });
1195            } else if (std.math.cast(u16, constu)) |const2u| {
1196                try writer.writeByte(DW.OP.const2u);
1197                try writer.writeInt(u16, const2u, adapter.endian());
1198            } else if (std.math.cast(u21, constu)) |const3u| {
1199                try writer.writeByte(DW.OP.constu);
1200                try writer.writeUleb128(const3u);
1201            } else if (std.math.cast(u32, constu)) |const4u| {
1202                try writer.writeByte(DW.OP.const4u);
1203                try writer.writeInt(u32, const4u, adapter.endian());
1204            } else if (std.math.cast(u49, constu)) |const7u| {
1205                try writer.writeByte(DW.OP.constu);
1206                try writer.writeUleb128(const7u);
1207            } else {
1208                try writer.writeByte(DW.OP.const8u);
1209                try writer.writeInt(u64, constu, adapter.endian());
1210            },
1211            .consts => |consts| if (std.math.cast(i8, consts)) |const1s| {
1212                try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) });
1213            } else if (std.math.cast(i16, consts)) |const2s| {
1214                try writer.writeByte(DW.OP.const2s);
1215                try writer.writeInt(i16, const2s, adapter.endian());
1216            } else if (std.math.cast(i21, consts)) |const3s| {
1217                try writer.writeByte(DW.OP.consts);
1218                try writer.writeSleb128(const3s);
1219            } else if (std.math.cast(i32, consts)) |const4s| {
1220                try writer.writeByte(DW.OP.const4s);
1221                try writer.writeInt(i32, const4s, adapter.endian());
1222            } else if (std.math.cast(i49, consts)) |const7s| {
1223                try writer.writeByte(DW.OP.consts);
1224                try writer.writeSleb128(const7s);
1225            } else {
1226                try writer.writeByte(DW.OP.const8s);
1227                try writer.writeInt(i64, consts, adapter.endian());
1228            },
1229            .plus => |plus| done: {
1230                if (plus[0].getConst(u0)) |_| {
1231                    try plus[1].write(adapter);
1232                    break :done;
1233                }
1234                if (plus[1].getConst(u0)) |_| {
1235                    try plus[0].write(adapter);
1236                    break :done;
1237                }
1238                if (plus[0].getBaseReg()) |breg| {
1239                    if (plus[1].getConst(i65)) |offset| {
1240                        try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
1241                        try writer.writeSleb128(offset);
1242                        break :done;
1243                    }
1244                }
1245                if (plus[1].getBaseReg()) |breg| {
1246                    if (plus[0].getConst(i65)) |offset| {
1247                        try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
1248                        try writer.writeSleb128(offset);
1249                        break :done;
1250                    }
1251                }
1252                if (plus[0].getConst(u64)) |uconst| {
1253                    try plus[1].write(adapter);
1254                    try writer.writeByte(DW.OP.plus_uconst);
1255                    try writer.writeUleb128(uconst);
1256                    break :done;
1257                }
1258                if (plus[1].getConst(u64)) |uconst| {
1259                    try plus[0].write(adapter);
1260                    try writer.writeByte(DW.OP.plus_uconst);
1261                    try writer.writeUleb128(uconst);
1262                    break :done;
1263                }
1264                try plus[0].write(adapter);
1265                try plus[1].write(adapter);
1266                try writer.writeByte(DW.OP.plus);
1267            },
1268            .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer),
1269            .breg => |breg| {
1270                try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
1271                try writer.writeSleb128(0);
1272            },
1273            .push_object_address => try writer.writeByte(DW.OP.push_object_address),
1274            .call => |call| {
1275                for (call.args) |arg| try arg.write(adapter);
1276                try writer.writeByte(DW.OP.call_ref);
1277                try adapter.infoEntry(call.unit, call.entry);
1278            },
1279            .form_tls_address => |addr| {
1280                try addr.write(adapter);
1281                try writer.writeByte(DW.OP.form_tls_address);
1282            },
1283            .implicit_value => |value| {
1284                try writer.writeByte(DW.OP.implicit_value);
1285                try writer.writeUleb128(value.len);
1286                try writer.writeAll(value);
1287            },
1288            .stack_value => |value| {
1289                try value.write(adapter);
1290                try writer.writeByte(DW.OP.stack_value);
1291            },
1292            .implicit_pointer => |implicit_pointer| {
1293                try writer.writeByte(DW.OP.implicit_pointer);
1294                try adapter.infoEntry(implicit_pointer.unit, implicit_pointer.entry);
1295                try writer.writeSleb128(implicit_pointer.offset);
1296            },
1297            .wasm_ext => |wasm_ext| {
1298                try writer.writeByte(DW.OP.WASM_location);
1299                switch (wasm_ext) {
1300                    .local => |local| {
1301                        try writer.writeByte(DW.OP.WASM_local);
1302                        try writer.writeUleb128(local);
1303                    },
1304                    .global => |global| if (std.math.cast(u21, global)) |global_u21| {
1305                        try writer.writeByte(DW.OP.WASM_global);
1306                        try writer.writeUleb128(global_u21);
1307                    } else {
1308                        try writer.writeByte(DW.OP.WASM_global_u32);
1309                        try writer.writeInt(u32, global, adapter.endian());
1310                    },
1311                    .operand_stack => |operand_stack| {
1312                        try writer.writeByte(DW.OP.WASM_operand_stack);
1313                        try writer.writeUleb128(operand_stack);
1314                    },
1315                }
1316            },
1317        }
1318    }
1319};
1320
1321pub const Cfa = union(enum) {
1322    nop,
1323    advance_loc: u32,
1324    offset: RegOff,
1325    rel_offset: RegOff,
1326    restore: u32,
1327    undefined: u32,
1328    same_value: u32,
1329    register: [2]u32,
1330    remember_state,
1331    restore_state,
1332    def_cfa: RegOff,
1333    def_cfa_register: u32,
1334    def_cfa_offset: i64,
1335    adjust_cfa_offset: i64,
1336    def_cfa_expression: Loc,
1337    expression: RegExpr,
1338    val_offset: RegOff,
1339    val_expression: RegExpr,
1340    escape: []const u8,
1341
1342    const RegOff = struct { reg: u32, off: i64 };
1343    const RegExpr = struct { reg: u32, expr: Loc };
1344
1345    fn write(cfa: Cfa, wip_nav: *WipNav) (UpdateError || Writer.Error)!void {
1346        const dfw = &wip_nav.debug_frame.writer;
1347        switch (cfa) {
1348            .nop => try dfw.writeByte(DW.CFA.nop),
1349            .advance_loc => |loc| {
1350                const delta = @divExact(loc - wip_nav.cfi.loc, wip_nav.dwarf.debug_frame.header.code_alignment_factor);
1351                if (delta == 0) {} else if (std.math.cast(u6, delta)) |small_delta|
1352                    try dfw.writeByte(@as(u8, DW.CFA.advance_loc) + small_delta)
1353                else if (std.math.cast(u8, delta)) |ubyte_delta|
1354                    try dfw.writeAll(&.{ DW.CFA.advance_loc1, ubyte_delta })
1355                else if (std.math.cast(u16, delta)) |uhalf_delta| {
1356                    try dfw.writeByte(DW.CFA.advance_loc2);
1357                    try dfw.writeInt(u16, uhalf_delta, wip_nav.dwarf.endian);
1358                } else if (std.math.cast(u32, delta)) |uword_delta| {
1359                    try dfw.writeByte(DW.CFA.advance_loc4);
1360                    try dfw.writeInt(u32, uword_delta, wip_nav.dwarf.endian);
1361                }
1362                wip_nav.cfi.loc = loc;
1363            },
1364            .offset, .rel_offset => |reg_off| {
1365                const factored_off = @divExact(reg_off.off - switch (cfa) {
1366                    else => unreachable,
1367                    .offset => 0,
1368                    .rel_offset => wip_nav.cfi.cfa.off,
1369                }, wip_nav.dwarf.debug_frame.header.data_alignment_factor);
1370                if (std.math.cast(u63, factored_off)) |unsigned_off| {
1371                    if (std.math.cast(u6, reg_off.reg)) |small_reg| {
1372                        try dfw.writeByte(@as(u8, DW.CFA.offset) + small_reg);
1373                    } else {
1374                        try dfw.writeByte(DW.CFA.offset_extended);
1375                        try dfw.writeUleb128(reg_off.reg);
1376                    }
1377                    try dfw.writeUleb128(unsigned_off);
1378                } else {
1379                    try dfw.writeByte(DW.CFA.offset_extended_sf);
1380                    try dfw.writeUleb128(reg_off.reg);
1381                    try dfw.writeSleb128(factored_off);
1382                }
1383            },
1384            .restore => |reg| if (std.math.cast(u6, reg)) |small_reg|
1385                try dfw.writeByte(@as(u8, DW.CFA.restore) + small_reg)
1386            else {
1387                try dfw.writeByte(DW.CFA.restore_extended);
1388                try dfw.writeUleb128(reg);
1389            },
1390            .undefined => |reg| {
1391                try dfw.writeByte(DW.CFA.undefined);
1392                try dfw.writeUleb128(reg);
1393            },
1394            .same_value => |reg| {
1395                try dfw.writeByte(DW.CFA.same_value);
1396                try dfw.writeUleb128(reg);
1397            },
1398            .register => |regs| if (regs[0] != regs[1]) {
1399                try dfw.writeByte(DW.CFA.register);
1400                for (regs) |reg| try dfw.writeUleb128(reg);
1401            } else {
1402                try dfw.writeByte(DW.CFA.same_value);
1403                try dfw.writeUleb128(regs[0]);
1404            },
1405            .remember_state => try dfw.writeByte(DW.CFA.remember_state),
1406            .restore_state => try dfw.writeByte(DW.CFA.restore_state),
1407            .def_cfa, .def_cfa_register, .def_cfa_offset, .adjust_cfa_offset => {
1408                const reg_off: RegOff = switch (cfa) {
1409                    else => unreachable,
1410                    .def_cfa => |reg_off| reg_off,
1411                    .def_cfa_register => |reg| .{ .reg = reg, .off = wip_nav.cfi.cfa.off },
1412                    .def_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = off },
1413                    .adjust_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = wip_nav.cfi.cfa.off + off },
1414                };
1415                const changed_reg = reg_off.reg != wip_nav.cfi.cfa.reg;
1416                const unsigned_off = std.math.cast(u63, reg_off.off);
1417                if (reg_off.off == wip_nav.cfi.cfa.off) {
1418                    if (changed_reg) {
1419                        try dfw.writeByte(DW.CFA.def_cfa_register);
1420                        try dfw.writeUleb128(reg_off.reg);
1421                    }
1422                } else if (switch (wip_nav.dwarf.debug_frame.header.data_alignment_factor) {
1423                    0 => unreachable,
1424                    1 => unsigned_off != null,
1425                    else => |data_alignment_factor| @rem(reg_off.off, data_alignment_factor) != 0,
1426                }) {
1427                    try dfw.writeByte(if (changed_reg) DW.CFA.def_cfa else DW.CFA.def_cfa_offset);
1428                    if (changed_reg) try dfw.writeUleb128(reg_off.reg);
1429                    try dfw.writeUleb128(unsigned_off.?);
1430                } else {
1431                    try dfw.writeByte(if (changed_reg) DW.CFA.def_cfa_sf else DW.CFA.def_cfa_offset_sf);
1432                    if (changed_reg) try dfw.writeUleb128(reg_off.reg);
1433                    try dfw.writeSleb128(@divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor));
1434                }
1435                wip_nav.cfi.cfa = reg_off;
1436            },
1437            .def_cfa_expression => |expr| {
1438                try dfw.writeByte(DW.CFA.def_cfa_expression);
1439                try wip_nav.frameExprLoc(expr);
1440            },
1441            .expression => |reg_expr| {
1442                try dfw.writeByte(DW.CFA.expression);
1443                try dfw.writeUleb128(reg_expr.reg);
1444                try wip_nav.frameExprLoc(reg_expr.expr);
1445            },
1446            .val_offset => |reg_off| {
1447                const factored_off = @divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor);
1448                if (std.math.cast(u63, factored_off)) |unsigned_off| {
1449                    try dfw.writeByte(DW.CFA.val_offset);
1450                    try dfw.writeUleb128(reg_off.reg);
1451                    try dfw.writeUleb128(unsigned_off);
1452                } else {
1453                    try dfw.writeByte(DW.CFA.val_offset_sf);
1454                    try dfw.writeUleb128(reg_off.reg);
1455                    try dfw.writeSleb128(factored_off);
1456                }
1457            },
1458            .val_expression => |reg_expr| {
1459                try dfw.writeByte(DW.CFA.val_expression);
1460                try dfw.writeUleb128(reg_expr.reg);
1461                try wip_nav.frameExprLoc(reg_expr.expr);
1462            },
1463            .escape => |bytes| try dfw.writeAll(bytes),
1464        }
1465    }
1466};
1467
1468pub const WipNav = struct {
1469    dwarf: *Dwarf,
1470    pt: Zcu.PerThread,
1471    unit: Unit.Index,
1472    entry: Entry.Index,
1473    any_children: bool,
1474    func: InternPool.Index,
1475    func_sym_index: u32,
1476    func_high_pc: u32,
1477    blocks: std.ArrayList(struct {
1478        abbrev_code: u32,
1479        low_pc_off: u64,
1480        high_pc: u32,
1481    }),
1482    cfi: struct {
1483        loc: u32,
1484        cfa: Cfa.RegOff,
1485    },
1486    debug_frame: Writer.Allocating,
1487    debug_info: Writer.Allocating,
1488    debug_line: Writer.Allocating,
1489    debug_loclists: Writer.Allocating,
1490    pending_lazy: PendingLazy,
1491
1492    pub fn deinit(wip_nav: *WipNav) void {
1493        const gpa = wip_nav.dwarf.gpa;
1494        if (wip_nav.func != .none) wip_nav.blocks.deinit(gpa);
1495        wip_nav.debug_frame.deinit();
1496        wip_nav.debug_info.deinit();
1497        wip_nav.debug_line.deinit();
1498        wip_nav.debug_loclists.deinit();
1499        wip_nav.pending_lazy.types.deinit(gpa);
1500        wip_nav.pending_lazy.values.deinit(gpa);
1501    }
1502
1503    pub fn genDebugFrame(wip_nav: *WipNav, loc: u32, cfa: Cfa) UpdateError!void {
1504        return wip_nav.genDebugFrameWriterError(loc, cfa) catch |err| switch (err) {
1505            error.WriteFailed => error.OutOfMemory,
1506            else => |e| e,
1507        };
1508    }
1509    fn genDebugFrameWriterError(wip_nav: *WipNav, loc: u32, cfa: Cfa) (UpdateError || Writer.Error)!void {
1510        assert(wip_nav.func != .none);
1511        if (wip_nav.dwarf.debug_frame.header.format == .none) return;
1512        const loc_cfa: Cfa = .{ .advance_loc = loc };
1513        try loc_cfa.write(wip_nav);
1514        try cfa.write(wip_nav);
1515    }
1516
1517    pub const LocalVarTag = enum { arg, local_var };
1518    pub fn genLocalVarDebugInfo(
1519        wip_nav: *WipNav,
1520        tag: LocalVarTag,
1521        opt_name: ?[]const u8,
1522        ty: Type,
1523        loc: Loc,
1524    ) UpdateError!void {
1525        return wip_nav.genLocalVarDebugInfoWriterError(tag, opt_name, ty, loc) catch |err| switch (err) {
1526            error.WriteFailed => error.OutOfMemory,
1527            else => |e| e,
1528        };
1529    }
1530    fn genLocalVarDebugInfoWriterError(
1531        wip_nav: *WipNav,
1532        tag: LocalVarTag,
1533        opt_name: ?[]const u8,
1534        ty: Type,
1535        loc: Loc,
1536    ) (UpdateError || Writer.Error)!void {
1537        assert(wip_nav.func != .none);
1538        try wip_nav.abbrevCode(switch (tag) {
1539            .arg => if (opt_name) |_| .arg else .unnamed_arg,
1540            .local_var => if (opt_name) |_| .local_var else unreachable,
1541        });
1542        if (opt_name) |name| try wip_nav.strp(name);
1543        try wip_nav.refType(ty);
1544        try wip_nav.infoExprLoc(loc);
1545        wip_nav.any_children = true;
1546    }
1547
1548    pub const LocalConstTag = enum { comptime_arg, local_const };
1549    pub fn genLocalConstDebugInfo(
1550        wip_nav: *WipNav,
1551        src_loc: Zcu.LazySrcLoc,
1552        tag: LocalConstTag,
1553        opt_name: ?[]const u8,
1554        val: Value,
1555    ) UpdateError!void {
1556        return wip_nav.genLocalConstDebugInfoWriterError(src_loc, tag, opt_name, val) catch |err| switch (err) {
1557            error.WriteFailed => error.OutOfMemory,
1558            else => |e| e,
1559        };
1560    }
1561    fn genLocalConstDebugInfoWriterError(
1562        wip_nav: *WipNav,
1563        src_loc: Zcu.LazySrcLoc,
1564        tag: LocalConstTag,
1565        opt_name: ?[]const u8,
1566        val: Value,
1567    ) (UpdateError || Writer.Error)!void {
1568        assert(wip_nav.func != .none);
1569        const pt = wip_nav.pt;
1570        const zcu = pt.zcu;
1571        const ty = val.typeOf(zcu);
1572        const has_runtime_bits = ty.hasRuntimeBits(zcu);
1573        const has_comptime_state = ty.comptimeOnly(zcu) and try ty.onePossibleValue(pt) == null;
1574        try wip_nav.abbrevCode(if (has_runtime_bits and has_comptime_state) switch (tag) {
1575            .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits_comptime_state else .unnamed_comptime_arg_runtime_bits_comptime_state,
1576            .local_const => if (opt_name) |_| .local_const_runtime_bits_comptime_state else unreachable,
1577        } else if (has_comptime_state) switch (tag) {
1578            .comptime_arg => if (opt_name) |_| .comptime_arg_comptime_state else .unnamed_comptime_arg_comptime_state,
1579            .local_const => if (opt_name) |_| .local_const_comptime_state else unreachable,
1580        } else if (has_runtime_bits) switch (tag) {
1581            .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits else .unnamed_comptime_arg_runtime_bits,
1582            .local_const => if (opt_name) |_| .local_const_runtime_bits else unreachable,
1583        } else switch (tag) {
1584            .comptime_arg => if (opt_name) |_| .comptime_arg else .unnamed_comptime_arg,
1585            .local_const => if (opt_name) |_| .local_const else unreachable,
1586        });
1587        if (opt_name) |name| try wip_nav.strp(name);
1588        try wip_nav.refType(ty);
1589        if (has_runtime_bits) try wip_nav.blockValue(src_loc, val);
1590        if (has_comptime_state) try wip_nav.refValue(val);
1591        wip_nav.any_children = true;
1592    }
1593
1594    pub fn genVarArgsDebugInfo(wip_nav: *WipNav) UpdateError!void {
1595        return wip_nav.genVarArgsDebugInfoWriterError() catch |err| switch (err) {
1596            error.WriteFailed => error.OutOfMemory,
1597            else => |e| e,
1598        };
1599    }
1600    fn genVarArgsDebugInfoWriterError(wip_nav: *WipNav) (UpdateError || Writer.Error)!void {
1601        assert(wip_nav.func != .none);
1602        try wip_nav.abbrevCode(.is_var_args);
1603        wip_nav.any_children = true;
1604    }
1605
1606    pub fn advancePCAndLine(wip_nav: *WipNav, delta_line: i33, delta_pc: u64) Allocator.Error!void {
1607        return wip_nav.advancePCAndLineWriterError(delta_line, delta_pc) catch |err| switch (err) {
1608            error.WriteFailed => error.OutOfMemory,
1609        };
1610    }
1611    fn advancePCAndLineWriterError(
1612        wip_nav: *WipNav,
1613        delta_line: i33,
1614        delta_pc: u64,
1615    ) Writer.Error!void {
1616        const dlw = &wip_nav.debug_line.writer;
1617
1618        const header = wip_nav.dwarf.debug_line.header;
1619        assert(header.maximum_operations_per_instruction == 1);
1620        const delta_op: u64 = 0;
1621
1622        const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or
1623            delta_line - header.line_base >= header.line_range)
1624        remaining: {
1625            assert(delta_line != 0);
1626            try dlw.writeByte(DW.LNS.advance_line);
1627            try dlw.writeSleb128(delta_line);
1628            break :remaining 0;
1629        } else delta_line);
1630
1631        const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
1632            header.maximum_operations_per_instruction + delta_op;
1633        const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
1634        const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: {
1635            try dlw.writeByte(DW.LNS.advance_pc);
1636            try dlw.writeUleb128(op_advance);
1637            break :remaining 0;
1638        } else if (op_advance >= max_op_advance) remaining: {
1639            try dlw.writeByte(DW.LNS.const_add_pc);
1640            break :remaining op_advance - max_op_advance;
1641        } else op_advance);
1642
1643        if (remaining_delta_line == 0 and remaining_op_advance == 0)
1644            try dlw.writeByte(DW.LNS.copy)
1645        else
1646            try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +
1647                (header.line_range * remaining_op_advance) + header.opcode_base));
1648    }
1649
1650    pub fn setColumn(wip_nav: *WipNav, column: u32) Allocator.Error!void {
1651        return wip_nav.setColumnWriterError(column) catch |err| switch (err) {
1652            error.WriteFailed => error.OutOfMemory,
1653        };
1654    }
1655    fn setColumnWriterError(wip_nav: *WipNav, column: u32) Writer.Error!void {
1656        const dlw = &wip_nav.debug_line.writer;
1657        try dlw.writeByte(DW.LNS.set_column);
1658        try dlw.writeUleb128(column + 1);
1659    }
1660
1661    pub fn negateStmt(wip_nav: *WipNav) Allocator.Error!void {
1662        return wip_nav.negateStmtWriterError() catch |err| switch (err) {
1663            error.WriteFailed => error.OutOfMemory,
1664        };
1665    }
1666    fn negateStmtWriterError(wip_nav: *WipNav) Writer.Error!void {
1667        try wip_nav.debug_line.writer.writeByte(DW.LNS.negate_stmt);
1668    }
1669
1670    pub fn setPrologueEnd(wip_nav: *WipNav) Allocator.Error!void {
1671        return wip_nav.setPrologueEndWriterError() catch |err| switch (err) {
1672            error.WriteFailed => error.OutOfMemory,
1673        };
1674    }
1675    fn setPrologueEndWriterError(wip_nav: *WipNav) Writer.Error!void {
1676        try wip_nav.debug_line.writer.writeByte(DW.LNS.set_prologue_end);
1677    }
1678
1679    pub fn setEpilogueBegin(wip_nav: *WipNav) Allocator.Error!void {
1680        return wip_nav.setEpilogueBeginWriterError() catch |err| switch (err) {
1681            error.WriteFailed => error.OutOfMemory,
1682        };
1683    }
1684    fn setEpilogueBeginWriterError(wip_nav: *WipNav) Writer.Error!void {
1685        try wip_nav.debug_line.writer.writeByte(DW.LNS.set_epilogue_begin);
1686    }
1687
1688    pub fn enterBlock(wip_nav: *WipNav, code_off: u64) UpdateError!void {
1689        return wip_nav.enterBlockWriterError(code_off) catch |err| switch (err) {
1690            error.WriteFailed => error.OutOfMemory,
1691            else => |e| e,
1692        };
1693    }
1694    fn enterBlockWriterError(wip_nav: *WipNav, code_off: u64) (UpdateError || Writer.Error)!void {
1695        const dwarf = wip_nav.dwarf;
1696        const diw = &wip_nav.debug_info.writer;
1697        const block = try wip_nav.blocks.addOne(dwarf.gpa);
1698
1699        block.abbrev_code = @intCast(diw.end);
1700        try wip_nav.abbrevCode(.block);
1701        block.low_pc_off = code_off;
1702        try wip_nav.infoAddrSym(wip_nav.func_sym_index, code_off);
1703        block.high_pc = @intCast(diw.end);
1704        try diw.writeInt(u32, 0, dwarf.endian);
1705        wip_nav.any_children = false;
1706    }
1707
1708    pub fn leaveBlock(wip_nav: *WipNav, code_off: u64) UpdateError!void {
1709        return wip_nav.leaveBlockWriterError(code_off) catch |err| switch (err) {
1710            error.WriteFailed => error.OutOfMemory,
1711            else => |e| e,
1712        };
1713    }
1714    fn leaveBlockWriterError(wip_nav: *WipNav, code_off: u64) (UpdateError || Writer.Error)!void {
1715        const block_bytes = comptime uleb128Bytes(@intFromEnum(AbbrevCode.block));
1716        const block = wip_nav.blocks.pop().?;
1717        if (wip_nav.any_children)
1718            try wip_nav.debug_info.writer.writeUleb128(@intFromEnum(AbbrevCode.null))
1719        else
1720            std.leb.writeUnsignedFixed(
1721                block_bytes,
1722                wip_nav.debug_info.written()[block.abbrev_code..][0..block_bytes],
1723                @intCast(try wip_nav.dwarf.refAbbrevCode(.empty_block)),
1724            );
1725        std.mem.writeInt(u32, wip_nav.debug_info.written()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian);
1726        wip_nav.any_children = true;
1727    }
1728
1729    pub fn enterInlineFunc(
1730        wip_nav: *WipNav,
1731        func: InternPool.Index,
1732        code_off: u64,
1733        line: u32,
1734        column: u32,
1735    ) UpdateError!void {
1736        return wip_nav.enterInlineFuncWriterError(func, code_off, line, column) catch |err| switch (err) {
1737            error.WriteFailed => error.OutOfMemory,
1738            else => |e| e,
1739        };
1740    }
1741    fn enterInlineFuncWriterError(
1742        wip_nav: *WipNav,
1743        func: InternPool.Index,
1744        code_off: u64,
1745        line: u32,
1746        column: u32,
1747    ) (UpdateError || Writer.Error)!void {
1748        const dwarf = wip_nav.dwarf;
1749        const zcu = wip_nav.pt.zcu;
1750        const diw = &wip_nav.debug_info.writer;
1751        const block = try wip_nav.blocks.addOne(dwarf.gpa);
1752
1753        block.abbrev_code = @intCast(diw.end);
1754        try wip_nav.abbrevCode(.inlined_func);
1755        try wip_nav.refNav(zcu.funcInfo(func).owner_nav);
1756        try diw.writeUleb128(zcu.navSrcLine(zcu.funcInfo(wip_nav.func).owner_nav) + line + 1);
1757        try diw.writeUleb128(column + 1);
1758        block.low_pc_off = code_off;
1759        try wip_nav.infoAddrSym(wip_nav.func_sym_index, code_off);
1760        block.high_pc = @intCast(diw.end);
1761        try diw.writeInt(u32, 0, dwarf.endian);
1762        try wip_nav.setInlineFunc(func);
1763        wip_nav.any_children = false;
1764    }
1765
1766    pub fn leaveInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64) UpdateError!void {
1767        return wip_nav.leaveInlineFuncWriterError(func, code_off) catch |err| switch (err) {
1768            error.WriteFailed => error.OutOfMemory,
1769            else => |e| e,
1770        };
1771    }
1772    fn leaveInlineFuncWriterError(
1773        wip_nav: *WipNav,
1774        func: InternPool.Index,
1775        code_off: u64,
1776    ) (UpdateError || Writer.Error)!void {
1777        const inlined_func_bytes = comptime uleb128Bytes(@intFromEnum(AbbrevCode.inlined_func));
1778        const block = wip_nav.blocks.pop().?;
1779        if (wip_nav.any_children)
1780            try wip_nav.debug_info.writer.writeUleb128(@intFromEnum(AbbrevCode.null))
1781        else
1782            std.leb.writeUnsignedFixed(
1783                inlined_func_bytes,
1784                wip_nav.debug_info.written()[block.abbrev_code..][0..inlined_func_bytes],
1785                @intCast(try wip_nav.dwarf.refAbbrevCode(.empty_inlined_func)),
1786            );
1787        std.mem.writeInt(u32, wip_nav.debug_info.written()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian);
1788        try wip_nav.setInlineFunc(func);
1789        wip_nav.any_children = true;
1790    }
1791
1792    pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void {
1793        return wip_nav.setInlineFuncWriterError(func) catch |err| switch (err) {
1794            error.WriteFailed => error.OutOfMemory,
1795            else => |e| e,
1796        };
1797    }
1798    fn setInlineFuncWriterError(wip_nav: *WipNav, func: InternPool.Index) (UpdateError || Writer.Error)!void {
1799        const zcu = wip_nav.pt.zcu;
1800        const dwarf = wip_nav.dwarf;
1801        if (wip_nav.func == func) return;
1802
1803        const new_func_info = zcu.funcInfo(func);
1804        const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav);
1805        const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod.?);
1806
1807        const dlw = &wip_nav.debug_line.writer;
1808        if (dwarf.incremental()) {
1809            const new_nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, new_func_info.owner_nav);
1810            errdefer _ = if (!new_nav_gop.found_existing) dwarf.navs.pop();
1811            if (!new_nav_gop.found_existing) new_nav_gop.value_ptr.* = try dwarf.addCommonEntry(new_unit);
1812
1813            try dlw.writeByte(DW.LNS.extended_op);
1814            try dlw.writeUleb128(1 + dwarf.sectionOffsetBytes());
1815            try dlw.writeByte(DW.LNE.ZIG_set_decl);
1816            try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{
1817                .source_off = @intCast(dlw.end),
1818                .target_sec = .debug_info,
1819                .target_unit = new_unit,
1820                .target_entry = new_nav_gop.value_ptr.toOptional(),
1821            });
1822            try dlw.splatByteAll(0, dwarf.sectionOffsetBytes());
1823            return;
1824        }
1825
1826        const old_func_info = zcu.funcInfo(wip_nav.func);
1827        const old_file = zcu.navFileScopeIndex(old_func_info.owner_nav);
1828        if (old_file != new_file) {
1829            const mod_info = dwarf.getModInfo(wip_nav.unit);
1830            try mod_info.dirs.put(dwarf.gpa, new_unit, {});
1831            const file_gop = try mod_info.files.getOrPut(dwarf.gpa, new_file);
1832
1833            try dlw.writeByte(DW.LNS.set_file);
1834            try dlw.writeUleb128(file_gop.index);
1835        }
1836
1837        const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav);
1838        const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav);
1839        if (new_src_line != old_src_line) {
1840            try dlw.writeByte(DW.LNS.advance_line);
1841            try dlw.writeSleb128(new_src_line - old_src_line);
1842        }
1843
1844        wip_nav.func = func;
1845    }
1846
1847    fn externalReloc(wip_nav: *WipNav, sec: *Section, reloc: ExternalReloc) Allocator.Error!void {
1848        try sec.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(wip_nav.dwarf.gpa, reloc);
1849    }
1850
1851    pub fn infoExternalReloc(wip_nav: *WipNav, reloc: ExternalReloc) Allocator.Error!void {
1852        try wip_nav.externalReloc(&wip_nav.dwarf.debug_info.section, reloc);
1853    }
1854
1855    fn frameExternalReloc(wip_nav: *WipNav, reloc: ExternalReloc) Allocator.Error!void {
1856        try wip_nav.externalReloc(&wip_nav.dwarf.debug_frame.section, reloc);
1857    }
1858
1859    fn abbrevCode(wip_nav: *WipNav, abbrev_code: AbbrevCode) (UpdateError || Writer.Error)!void {
1860        try wip_nav.debug_info.writer.writeUleb128(try wip_nav.dwarf.refAbbrevCode(abbrev_code));
1861    }
1862
1863    fn sectionOffset(
1864        wip_nav: *WipNav,
1865        comptime sec: Section.Index,
1866        target_sec: Section.Index,
1867        target_unit: Unit.Index,
1868        target_entry: Entry.Index,
1869        target_off: u32,
1870    ) (UpdateError || Writer.Error)!void {
1871        const dwarf = wip_nav.dwarf;
1872        const gpa = dwarf.gpa;
1873        const entry_ptr = @field(dwarf, @tagName(sec)).section.getUnit(wip_nav.unit).getEntry(wip_nav.entry);
1874        const sw = &@field(wip_nav, @tagName(sec)).writer;
1875        const source_off: u32 = @intCast(sw.end);
1876        if (target_sec != sec) {
1877            try entry_ptr.cross_section_relocs.append(gpa, .{
1878                .source_off = source_off,
1879                .target_sec = target_sec,
1880                .target_unit = target_unit,
1881                .target_entry = target_entry.toOptional(),
1882                .target_off = target_off,
1883            });
1884        } else if (target_unit != wip_nav.unit) {
1885            try entry_ptr.cross_unit_relocs.append(gpa, .{
1886                .source_off = source_off,
1887                .target_unit = target_unit,
1888                .target_entry = target_entry.toOptional(),
1889                .target_off = target_off,
1890            });
1891        } else {
1892            try entry_ptr.cross_entry_relocs.append(gpa, .{
1893                .source_off = source_off,
1894                .target_entry = target_entry.toOptional(),
1895                .target_off = target_off,
1896            });
1897        }
1898        try sw.splatByteAll(0, dwarf.sectionOffsetBytes());
1899    }
1900
1901    fn infoSectionOffset(
1902        wip_nav: *WipNav,
1903        target_sec: Section.Index,
1904        target_unit: Unit.Index,
1905        target_entry: Entry.Index,
1906        target_off: u32,
1907    ) (UpdateError || Writer.Error)!void {
1908        try wip_nav.sectionOffset(.debug_info, target_sec, target_unit, target_entry, target_off);
1909    }
1910
1911    fn strp(wip_nav: *WipNav, str: []const u8) (UpdateError || Writer.Error)!void {
1912        try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0);
1913    }
1914
1915    const ExprLocCounter = struct {
1916        dw: Writer.Discarding,
1917        section_offset_bytes: u32,
1918        address_size: AddressSize,
1919        fn init(dwarf: *Dwarf, buf: []u8) ExprLocCounter {
1920            return .{
1921                .dw = .init(buf),
1922                .section_offset_bytes = dwarf.sectionOffsetBytes(),
1923                .address_size = dwarf.address_size,
1924            };
1925        }
1926        fn writer(counter: *ExprLocCounter) *Writer {
1927            return &counter.dw.writer;
1928        }
1929        fn endian(_: ExprLocCounter) std.builtin.Endian {
1930            return @import("builtin").cpu.arch.endian();
1931        }
1932        fn addrSym(counter: *ExprLocCounter, _: u32) Writer.Error!void {
1933            try counter.dw.writer.splatByteAll(undefined, @intFromEnum(counter.address_size));
1934        }
1935        fn infoEntry(counter: *ExprLocCounter, _: Unit.Index, _: Entry.Index) Writer.Error!void {
1936            try counter.dw.writer.splatByteAll(undefined, counter.section_offset_bytes);
1937        }
1938    };
1939
1940    fn infoExprLoc(wip_nav: *WipNav, loc: Loc) (UpdateError || Writer.Error)!void {
1941        var buf: [64]u8 = undefined;
1942        var counter: ExprLocCounter = .init(wip_nav.dwarf, &buf);
1943        try loc.write(&counter);
1944
1945        const adapter: struct {
1946            wip_nav: *WipNav,
1947            fn writer(ctx: @This()) *Writer {
1948                return &ctx.wip_nav.debug_info.writer;
1949            }
1950            fn endian(ctx: @This()) std.builtin.Endian {
1951                return ctx.wip_nav.dwarf.endian;
1952            }
1953            fn addrSym(ctx: @This(), sym_index: u32) (UpdateError || Writer.Error)!void {
1954                try ctx.wip_nav.infoAddrSym(sym_index, 0);
1955            }
1956            fn infoEntry(
1957                ctx: @This(),
1958                unit: Unit.Index,
1959                entry: Entry.Index,
1960            ) (UpdateError || Writer.Error)!void {
1961                try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
1962            }
1963        } = .{ .wip_nav = wip_nav };
1964        try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end);
1965        try loc.write(adapter);
1966    }
1967
1968    fn infoAddrSym(
1969        wip_nav: *WipNav,
1970        sym_index: u32,
1971        sym_off: u64,
1972    ) (UpdateError || Writer.Error)!void {
1973        const diw = &wip_nav.debug_info.writer;
1974        try wip_nav.infoExternalReloc(.{
1975            .source_off = @intCast(diw.end),
1976            .target_sym = sym_index,
1977            .target_off = sym_off,
1978        });
1979        try diw.splatByteAll(0, @intFromEnum(wip_nav.dwarf.address_size));
1980    }
1981
1982    fn frameExprLoc(wip_nav: *WipNav, loc: Loc) (UpdateError || Writer.Error)!void {
1983        var buf: [64]u8 = undefined;
1984        var counter: ExprLocCounter = .init(wip_nav.dwarf, &buf);
1985        try loc.write(&counter);
1986
1987        const adapter: struct {
1988            wip_nav: *WipNav,
1989            fn writer(ctx: @This()) *Writer {
1990                return &ctx.wip_nav.debug_frame.writer;
1991            }
1992            fn endian(ctx: @This()) std.builtin.Endian {
1993                return ctx.wip_nav.dwarf.endian;
1994            }
1995            fn addrSym(ctx: @This(), sym_index: u32) (UpdateError || Writer.Error)!void {
1996                try ctx.wip_nav.frameAddrSym(sym_index, 0);
1997            }
1998            fn infoEntry(
1999                ctx: @This(),
2000                unit: Unit.Index,
2001                entry: Entry.Index,
2002            ) (UpdateError || Writer.Error)!void {
2003                try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0);
2004            }
2005        } = .{ .wip_nav = wip_nav };
2006        try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end);
2007        try loc.write(adapter);
2008    }
2009
2010    fn frameAddrSym(
2011        wip_nav: *WipNav,
2012        sym_index: u32,
2013        sym_off: u64,
2014    ) (UpdateError || Writer.Error)!void {
2015        const dfw = &wip_nav.debug_frame.writer;
2016        try wip_nav.frameExternalReloc(.{
2017            .source_off = @intCast(dfw.end),
2018            .target_sym = sym_index,
2019            .target_off = sym_off,
2020        });
2021        try dfw.splatByteAll(0, @intFromEnum(wip_nav.dwarf.address_size));
2022    }
2023
2024    fn getNavEntry(
2025        wip_nav: *WipNav,
2026        nav_index: InternPool.Nav.Index,
2027    ) UpdateError!struct { Unit.Index, Entry.Index } {
2028        const zcu = wip_nav.pt.zcu;
2029        const ip = &zcu.intern_pool;
2030        const nav = ip.getNav(nav_index);
2031        const unit = try wip_nav.dwarf.getUnit(zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?);
2032        const gop = try wip_nav.dwarf.navs.getOrPut(wip_nav.dwarf.gpa, nav_index);
2033        if (gop.found_existing) return .{ unit, gop.value_ptr.* };
2034        const entry = try wip_nav.dwarf.addCommonEntry(unit);
2035        gop.value_ptr.* = entry;
2036        return .{ unit, entry };
2037    }
2038
2039    fn refNav(
2040        wip_nav: *WipNav,
2041        nav_index: InternPool.Nav.Index,
2042    ) (UpdateError || Writer.Error)!void {
2043        const unit, const entry = try wip_nav.getNavEntry(nav_index);
2044        try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
2045    }
2046
2047    fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } {
2048        const zcu = wip_nav.pt.zcu;
2049        const ip = &zcu.intern_pool;
2050        const maybe_inst_index = ty.typeDeclInst(zcu);
2051        const unit = if (maybe_inst_index) |inst_index| switch (switch (ip.indexToKey(ty.toIntern())) {
2052            else => unreachable,
2053            .struct_type => ip.loadStructType(ty.toIntern()).name_nav,
2054            .union_type => ip.loadUnionType(ty.toIntern()).name_nav,
2055            .enum_type => ip.loadEnumType(ty.toIntern()).name_nav,
2056            .opaque_type => ip.loadOpaqueType(ty.toIntern()).name_nav,
2057        }) {
2058            .none => try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod.?),
2059            else => |name_nav| return wip_nav.getNavEntry(name_nav.unwrap().?),
2060        } else .main;
2061        const gop = try wip_nav.dwarf.types.getOrPut(wip_nav.dwarf.gpa, ty.toIntern());
2062        if (gop.found_existing) return .{ unit, gop.value_ptr.* };
2063        const entry = try wip_nav.dwarf.addCommonEntry(unit);
2064        gop.value_ptr.* = entry;
2065        if (maybe_inst_index == null) try wip_nav.pending_lazy.types.append(wip_nav.dwarf.gpa, ty.toIntern());
2066        return .{ unit, entry };
2067    }
2068
2069    fn refType(wip_nav: *WipNav, ty: Type) (UpdateError || Writer.Error)!void {
2070        const unit, const entry = try wip_nav.getTypeEntry(ty);
2071        try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
2072    }
2073
2074    fn getValueEntry(wip_nav: *WipNav, value: Value) UpdateError!struct { Unit.Index, Entry.Index } {
2075        const zcu = wip_nav.pt.zcu;
2076        const ip = &zcu.intern_pool;
2077        const ty = value.typeOf(zcu);
2078        if (std.debug.runtime_safety) assert(ty.comptimeOnly(zcu) and try ty.onePossibleValue(wip_nav.pt) == null);
2079        if (ty.toIntern() == .type_type) return wip_nav.getTypeEntry(value.toType());
2080        if (ip.isFunctionType(ty.toIntern()) and !value.isUndef(zcu)) return wip_nav.getNavEntry(switch (ip.indexToKey(value.toIntern())) {
2081            else => unreachable,
2082            .func => |func| func.owner_nav,
2083            .@"extern" => |@"extern"| @"extern".owner_nav,
2084        });
2085        const gop = try wip_nav.dwarf.values.getOrPut(wip_nav.dwarf.gpa, value.toIntern());
2086        const unit: Unit.Index = .main;
2087        if (gop.found_existing) return .{ unit, gop.value_ptr.* };
2088        const entry = try wip_nav.dwarf.addCommonEntry(unit);
2089        gop.value_ptr.* = entry;
2090        try wip_nav.pending_lazy.values.append(wip_nav.dwarf.gpa, value.toIntern());
2091        return .{ unit, entry };
2092    }
2093
2094    fn refValue(wip_nav: *WipNav, value: Value) (UpdateError || Writer.Error)!void {
2095        const unit, const entry = try wip_nav.getValueEntry(value);
2096        try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
2097    }
2098
2099    fn refForward(wip_nav: *WipNav) (Allocator.Error || Writer.Error)!u32 {
2100        const dwarf = wip_nav.dwarf;
2101        const diw = &wip_nav.debug_info.writer;
2102        const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs;
2103        const reloc_index: u32 = @intCast(cross_entry_relocs.items.len);
2104        try cross_entry_relocs.append(dwarf.gpa, .{
2105            .source_off = @intCast(diw.end),
2106            .target_entry = undefined,
2107            .target_off = undefined,
2108        });
2109        try diw.splatByteAll(0, dwarf.sectionOffsetBytes());
2110        return reloc_index;
2111    }
2112
2113    fn finishForward(wip_nav: *WipNav, reloc_index: u32) void {
2114        const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs.items[reloc_index];
2115        reloc.target_entry = wip_nav.entry.toOptional();
2116        reloc.target_off = @intCast(wip_nav.debug_info.writer.end);
2117    }
2118
2119    fn blockValue(
2120        wip_nav: *WipNav,
2121        src_loc: Zcu.LazySrcLoc,
2122        val: Value,
2123    ) (UpdateError || Writer.Error)!void {
2124        const ty = val.typeOf(wip_nav.pt.zcu);
2125        const diw = &wip_nav.debug_info.writer;
2126        const size = if (ty.hasRuntimeBits(wip_nav.pt.zcu)) ty.abiSize(wip_nav.pt.zcu) else 0;
2127        try diw.writeUleb128(size);
2128        if (size == 0) return;
2129        const old_end = wip_nav.debug_info.writer.end;
2130        try codegen.generateSymbol(
2131            wip_nav.dwarf.bin_file,
2132            wip_nav.pt,
2133            src_loc,
2134            val,
2135            &wip_nav.debug_info.writer,
2136            .{ .debug_output = .{ .dwarf = wip_nav } },
2137        );
2138        if (old_end + size != wip_nav.debug_info.writer.end) {
2139            std.debug.print("{f} [{}]: {} != {}\n", .{
2140                ty.fmt(wip_nav.pt),
2141                ty.toIntern(),
2142                size,
2143                wip_nav.debug_info.writer.end - old_end,
2144            });
2145            unreachable;
2146        }
2147    }
2148
2149    const AbbrevCodeForForm = struct {
2150        sdata: AbbrevCode,
2151        udata: AbbrevCode,
2152        block: AbbrevCode,
2153    };
2154
2155    fn bigIntConstValue(
2156        wip_nav: *WipNav,
2157        abbrev_code: AbbrevCodeForForm,
2158        ty: Type,
2159        big_int: std.math.big.int.Const,
2160    ) (UpdateError || Writer.Error)!void {
2161        const zcu = wip_nav.pt.zcu;
2162        const diw = &wip_nav.debug_info.writer;
2163        const signedness = switch (ty.toIntern()) {
2164            .comptime_int_type, .comptime_float_type => .signed,
2165            else => ty.intInfo(zcu).signedness,
2166        };
2167        const bits = @max(1, big_int.bitCountTwosCompForSignedness(signedness));
2168        if (bits <= 64) {
2169            try wip_nav.abbrevCode(switch (signedness) {
2170                .signed => abbrev_code.sdata,
2171                .unsigned => abbrev_code.udata,
2172            });
2173            try wip_nav.debug_info.ensureUnusedCapacity(std.math.divCeil(usize, bits, 7) catch unreachable);
2174            var bit: usize = 0;
2175            var carry: u1 = 1;
2176            while (bit < bits) {
2177                const limb_bits = @typeInfo(std.math.big.Limb).int.bits;
2178                const limb_index = bit / limb_bits;
2179                const limb_shift: std.math.Log2Int(std.math.big.Limb) = @intCast(bit % limb_bits);
2180                const low_abs_part: u7 = @truncate(big_int.limbs[limb_index] >> limb_shift);
2181                const abs_part = if (limb_shift > limb_bits - 7 and limb_index + 1 < big_int.limbs.len) abs_part: {
2182                    const high_abs_part: u7 = @truncate(big_int.limbs[limb_index + 1] << -%limb_shift);
2183                    break :abs_part high_abs_part | low_abs_part;
2184                } else low_abs_part;
2185                const twos_comp_part = if (big_int.positive) abs_part else twos_comp_part: {
2186                    const twos_comp_part, carry = @addWithOverflow(~abs_part, carry);
2187                    break :twos_comp_part twos_comp_part;
2188                };
2189                bit += 7;
2190                diw.writeByte(@as(u8, if (bit < bits) 0x80 else 0x00) | twos_comp_part) catch unreachable;
2191            }
2192        } else {
2193            try wip_nav.abbrevCode(abbrev_code.block);
2194            const bytes = @max(ty.abiSize(zcu), std.math.divCeil(usize, bits, 8) catch unreachable);
2195            try diw.writeUleb128(bytes);
2196            try wip_nav.debug_info.ensureUnusedCapacity(@intCast(bytes));
2197            big_int.writeTwosComplement(
2198                try diw.writableSlice(@intCast(bytes)),
2199                wip_nav.dwarf.endian,
2200            );
2201        }
2202    }
2203
2204    fn enumConstValue(
2205        wip_nav: *WipNav,
2206        loaded_enum: InternPool.LoadedEnumType,
2207        abbrev_code: AbbrevCodeForForm,
2208        field_index: usize,
2209    ) (UpdateError || Writer.Error)!void {
2210        const zcu = wip_nav.pt.zcu;
2211        const ip = &zcu.intern_pool;
2212        var big_int_space: Value.BigIntSpace = undefined;
2213        try wip_nav.bigIntConstValue(abbrev_code, .fromInterned(loaded_enum.tag_ty), if (loaded_enum.values.len > 0)
2214            Value.fromInterned(loaded_enum.values.get(ip)[field_index]).toBigInt(&big_int_space, zcu)
2215        else
2216            std.math.big.int.Mutable.init(&big_int_space.limbs, field_index).toConst());
2217    }
2218
2219    fn declCommon(
2220        wip_nav: *WipNav,
2221        abbrev_code: struct {
2222            decl: AbbrevCode,
2223            generic_decl: AbbrevCode,
2224            decl_instance: AbbrevCode,
2225        },
2226        nav: *const InternPool.Nav,
2227        file: Zcu.File.Index,
2228        decl: *const std.zig.Zir.Inst.Declaration.Unwrapped,
2229    ) (UpdateError || Writer.Error)!void {
2230        const zcu = wip_nav.pt.zcu;
2231        const ip = &zcu.intern_pool;
2232        const dwarf = wip_nav.dwarf;
2233        const diw = &wip_nav.debug_info.writer;
2234
2235        const orig_entry = wip_nav.entry;
2236        defer wip_nav.entry = orig_entry;
2237        const parent_type, const is_generic_decl = if (nav.analysis) |analysis| parent_info: {
2238            const parent_type: Type = .fromInterned(zcu.namespacePtr(analysis.namespace).owner_type);
2239            const decl_gop = try dwarf.decls.getOrPut(dwarf.gpa, analysis.zir_index);
2240            errdefer _ = if (!decl_gop.found_existing) dwarf.decls.pop();
2241            const was_generic_decl = decl_gop.found_existing and
2242                switch (try dwarf.debug_info.declAbbrevCode(wip_nav.unit, decl_gop.value_ptr.*)) {
2243                    .null,
2244                    .decl_alias,
2245                    .decl_empty_enum,
2246                    .decl_enum,
2247                    .decl_namespace_struct,
2248                    .decl_struct,
2249                    .decl_packed_struct,
2250                    .decl_union,
2251                    .decl_var,
2252                    .decl_const,
2253                    .decl_const_runtime_bits,
2254                    .decl_const_comptime_state,
2255                    .decl_const_runtime_bits_comptime_state,
2256                    .decl_nullary_func,
2257                    .decl_func,
2258                    .decl_nullary_func_generic,
2259                    .decl_func_generic,
2260                    .decl_extern_nullary_func,
2261                    .decl_extern_func,
2262                    => false,
2263                    .generic_decl_var,
2264                    .generic_decl_const,
2265                    .generic_decl_func,
2266                    => true,
2267                    else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}),
2268                };
2269            if (parent_type.getCaptures(zcu).len == 0) {
2270                if (was_generic_decl) try dwarf.freeCommonEntry(wip_nav.unit, decl_gop.value_ptr.*);
2271                decl_gop.value_ptr.* = orig_entry;
2272                break :parent_info .{ parent_type, false };
2273            } else {
2274                if (was_generic_decl)
2275                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(decl_gop.value_ptr.*).clear()
2276                else
2277                    decl_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
2278                wip_nav.entry = decl_gop.value_ptr.*;
2279                break :parent_info .{ parent_type, true };
2280            }
2281        } else .{ null, false };
2282
2283        try wip_nav.abbrevCode(if (is_generic_decl) abbrev_code.generic_decl else abbrev_code.decl);
2284        try wip_nav.refType((if (is_generic_decl) null else parent_type) orelse
2285            .fromInterned(zcu.fileRootType(file)));
2286        assert(diw.end == DebugInfo.declEntryLineOff(dwarf));
2287        try diw.writeInt(u32, decl.src_line + 1, dwarf.endian);
2288        try diw.writeUleb128(decl.src_column + 1);
2289        try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
2290        try wip_nav.strp(nav.name.toSlice(ip));
2291
2292        if (!is_generic_decl) return;
2293        const generic_decl_entry = wip_nav.entry;
2294        try dwarf.debug_info.section.replaceEntry(wip_nav.unit, generic_decl_entry, dwarf, wip_nav.debug_info.written());
2295        wip_nav.debug_info.clearRetainingCapacity();
2296        wip_nav.entry = orig_entry;
2297        try wip_nav.abbrevCode(abbrev_code.decl_instance);
2298        try wip_nav.refType(parent_type.?);
2299        try wip_nav.infoSectionOffset(.debug_info, wip_nav.unit, generic_decl_entry, 0);
2300    }
2301
2302    const PendingLazy = struct {
2303        types: std.ArrayList(InternPool.Index),
2304        values: std.ArrayList(InternPool.Index),
2305
2306        const empty: PendingLazy = .{ .types = .empty, .values = .empty };
2307    };
2308
2309    fn updateLazy(wip_nav: *WipNav, src_loc: Zcu.LazySrcLoc) (UpdateError || Writer.Error)!void {
2310        while (true) if (wip_nav.pending_lazy.types.pop()) |pending_ty|
2311            try wip_nav.dwarf.updateLazyType(wip_nav.pt, src_loc, pending_ty, &wip_nav.pending_lazy)
2312        else if (wip_nav.pending_lazy.values.pop()) |pending_val|
2313            try wip_nav.dwarf.updateLazyValue(wip_nav.pt, src_loc, pending_val, &wip_nav.pending_lazy)
2314        else
2315            break;
2316    }
2317};
2318
2319/// When allocating, the ideal_capacity is calculated by
2320/// actual_capacity + (actual_capacity / ideal_factor)
2321const ideal_factor = 3;
2322
2323fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
2324    return actual_size +| (actual_size / ideal_factor);
2325}
2326
2327pub fn init(lf: *link.File, format: DW.Format) Dwarf {
2328    const comp = lf.comp;
2329    const gpa = comp.gpa;
2330    const target = &comp.root_mod.resolved_target.result;
2331    return .{
2332        .gpa = gpa,
2333        .bin_file = lf,
2334        .format = format,
2335        .address_size = switch (target.ptrBitWidth()) {
2336            0...32 => .@"32",
2337            33...64 => .@"64",
2338            else => unreachable,
2339        },
2340        .endian = target.cpu.arch.endian(),
2341
2342        .mods = .empty,
2343        .types = .empty,
2344        .values = .empty,
2345        .navs = .empty,
2346        .decls = .empty,
2347
2348        .debug_abbrev = .{ .section = Section.init },
2349        .debug_aranges = .{ .section = Section.init },
2350        .debug_frame = .{
2351            .header = if (target.cpu.arch == .x86_64 and target.ofmt == .elf) header: {
2352                const Register = @import("../codegen/x86_64/bits.zig").Register;
2353                break :header comptime .{
2354                    .format = .eh_frame,
2355                    .code_alignment_factor = 1,
2356                    .data_alignment_factor = -8,
2357                    .return_address_register = Register.rip.dwarfNum(),
2358                    .initial_instructions = &.{
2359                        .{ .def_cfa = .{ .reg = Register.rsp.dwarfNum(), .off = 8 } },
2360                        .{ .offset = .{ .reg = Register.rip.dwarfNum(), .off = -8 } },
2361                    },
2362                };
2363            } else .{
2364                .format = .none,
2365                .code_alignment_factor = undefined,
2366                .data_alignment_factor = undefined,
2367                .return_address_register = undefined,
2368                .initial_instructions = &.{},
2369            },
2370            .section = Section.init,
2371        },
2372        .debug_info = .{ .section = Section.init },
2373        .debug_line = .{
2374            .header = switch (target.cpu.arch) {
2375                .x86_64, .aarch64 => .{
2376                    .minimum_instruction_length = 1,
2377                    .maximum_operations_per_instruction = 1,
2378                    .default_is_stmt = true,
2379                    .line_base = -5,
2380                    .line_range = 14,
2381                    .opcode_base = DW.LNS.set_isa + 1,
2382                },
2383                else => .{
2384                    .minimum_instruction_length = 1,
2385                    .maximum_operations_per_instruction = 1,
2386                    .default_is_stmt = true,
2387                    .line_base = 0,
2388                    .line_range = 1,
2389                    .opcode_base = DW.LNS.set_isa + 1,
2390                },
2391            },
2392            .section = Section.init,
2393        },
2394        .debug_line_str = StringSection.init,
2395        .debug_loclists = .{ .section = Section.init },
2396        .debug_rnglists = .{ .section = Section.init },
2397        .debug_str = StringSection.init,
2398    };
2399}
2400
2401pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
2402    if (dwarf.bin_file.cast(.macho)) |macho_file| {
2403        if (macho_file.d_sym) |*d_sym| {
2404            for ([_]*Section{
2405                &dwarf.debug_abbrev.section,
2406                &dwarf.debug_aranges.section,
2407                &dwarf.debug_info.section,
2408                &dwarf.debug_line.section,
2409                &dwarf.debug_line_str.section,
2410                &dwarf.debug_loclists.section,
2411                &dwarf.debug_rnglists.section,
2412                &dwarf.debug_str.section,
2413            }, [_]u8{
2414                d_sym.debug_abbrev_section_index.?,
2415                d_sym.debug_aranges_section_index.?,
2416                d_sym.debug_info_section_index.?,
2417                d_sym.debug_line_section_index.?,
2418                d_sym.debug_line_str_section_index.?,
2419                d_sym.debug_loclists_section_index.?,
2420                d_sym.debug_rnglists_section_index.?,
2421                d_sym.debug_str_section_index.?,
2422            }) |sec, sect_index| {
2423                const header = &d_sym.sections.items[sect_index];
2424                sec.index = sect_index;
2425                sec.len = header.size;
2426            }
2427        } else {
2428            for ([_]*Section{
2429                &dwarf.debug_abbrev.section,
2430                &dwarf.debug_aranges.section,
2431                &dwarf.debug_info.section,
2432                &dwarf.debug_line.section,
2433                &dwarf.debug_line_str.section,
2434                &dwarf.debug_loclists.section,
2435                &dwarf.debug_rnglists.section,
2436                &dwarf.debug_str.section,
2437            }, [_]u8{
2438                macho_file.debug_abbrev_sect_index.?,
2439                macho_file.debug_aranges_sect_index.?,
2440                macho_file.debug_info_sect_index.?,
2441                macho_file.debug_line_sect_index.?,
2442                macho_file.debug_line_str_sect_index.?,
2443                macho_file.debug_loclists_sect_index.?,
2444                macho_file.debug_rnglists_sect_index.?,
2445                macho_file.debug_str_sect_index.?,
2446            }) |sec, sect_index| {
2447                const header = &macho_file.sections.items(.header)[sect_index];
2448                sec.index = sect_index;
2449                sec.len = header.size;
2450            }
2451        }
2452    }
2453}
2454
2455pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
2456    if (dwarf.bin_file.cast(.elf)) |elf_file| {
2457        const zo = elf_file.zigObjectPtr().?;
2458        for ([_]*Section{
2459            &dwarf.debug_abbrev.section,
2460            &dwarf.debug_aranges.section,
2461            &dwarf.debug_frame.section,
2462            &dwarf.debug_info.section,
2463            &dwarf.debug_line.section,
2464            &dwarf.debug_line_str.section,
2465            &dwarf.debug_loclists.section,
2466            &dwarf.debug_rnglists.section,
2467            &dwarf.debug_str.section,
2468        }, [_]u32{
2469            zo.debug_abbrev_index.?,
2470            zo.debug_aranges_index.?,
2471            zo.eh_frame_index.?,
2472            zo.debug_info_index.?,
2473            zo.debug_line_index.?,
2474            zo.debug_line_str_index.?,
2475            zo.debug_loclists_index.?,
2476            zo.debug_rnglists_index.?,
2477            zo.debug_str_index.?,
2478        }) |sec, sym_index| {
2479            sec.index = sym_index;
2480        }
2481    }
2482    dwarf.reloadSectionMetadata();
2483
2484    dwarf.debug_abbrev.section.pad_entries_to_ideal = false;
2485    assert(try dwarf.debug_abbrev.section.addUnit(DebugAbbrev.header_bytes, DebugAbbrev.trailer_bytes, dwarf) == DebugAbbrev.unit);
2486    errdefer dwarf.debug_abbrev.section.popUnit(dwarf.gpa);
2487    for (std.enums.values(AbbrevCode)) |abbrev_code|
2488        assert(@intFromEnum(try dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).addEntry(dwarf.gpa)) == @intFromEnum(abbrev_code));
2489
2490    dwarf.debug_aranges.section.pad_entries_to_ideal = false;
2491    dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size) * 2);
2492
2493    dwarf.debug_frame.section.alignment = switch (dwarf.debug_frame.header.format) {
2494        .none => .@"1",
2495        .debug_frame => InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size)),
2496        .eh_frame => .@"4",
2497    };
2498
2499    dwarf.debug_line_str.section.pad_entries_to_ideal = false;
2500    assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
2501    errdefer dwarf.debug_line_str.section.popUnit(dwarf.gpa);
2502
2503    dwarf.debug_str.section.pad_entries_to_ideal = false;
2504    assert(try dwarf.debug_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
2505    errdefer dwarf.debug_str.section.popUnit(dwarf.gpa);
2506
2507    dwarf.debug_loclists.section.pad_entries_to_ideal = false;
2508
2509    dwarf.debug_rnglists.section.pad_entries_to_ideal = false;
2510}
2511
2512pub fn deinit(dwarf: *Dwarf) void {
2513    const gpa = dwarf.gpa;
2514    for (dwarf.mods.values()) |*mod_info| mod_info.deinit(gpa);
2515    dwarf.mods.deinit(gpa);
2516    dwarf.types.deinit(gpa);
2517    dwarf.values.deinit(gpa);
2518    dwarf.navs.deinit(gpa);
2519    dwarf.decls.deinit(gpa);
2520    dwarf.debug_abbrev.section.deinit(gpa);
2521    dwarf.debug_aranges.section.deinit(gpa);
2522    dwarf.debug_frame.section.deinit(gpa);
2523    dwarf.debug_info.section.deinit(gpa);
2524    dwarf.debug_line.section.deinit(gpa);
2525    dwarf.debug_line_str.deinit(gpa);
2526    dwarf.debug_loclists.section.deinit(gpa);
2527    dwarf.debug_rnglists.section.deinit(gpa);
2528    dwarf.debug_str.deinit(gpa);
2529    dwarf.* = undefined;
2530}
2531
2532fn getUnit(dwarf: *Dwarf, mod: *Module) !Unit.Index {
2533    const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod);
2534    const unit: Unit.Index = @enumFromInt(mod_gop.index);
2535    if (!mod_gop.found_existing) {
2536        errdefer _ = dwarf.mods.pop();
2537        mod_gop.value_ptr.* = .{
2538            .root_dir_path = undefined,
2539            .dirs = .empty,
2540            .files = .empty,
2541        };
2542        errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa);
2543        try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {});
2544        assert(try dwarf.debug_aranges.section.addUnit(
2545            DebugAranges.headerBytes(dwarf),
2546            DebugAranges.trailerBytes(dwarf),
2547            dwarf,
2548        ) == unit);
2549        errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa);
2550        assert(try dwarf.debug_frame.section.addUnit(
2551            DebugFrame.headerBytes(dwarf),
2552            DebugFrame.trailerBytes(dwarf),
2553            dwarf,
2554        ) == unit);
2555        errdefer dwarf.debug_frame.section.popUnit(dwarf.gpa);
2556        assert(try dwarf.debug_info.section.addUnit(
2557            DebugInfo.headerBytes(dwarf),
2558            DebugInfo.trailer_bytes,
2559            dwarf,
2560        ) == unit);
2561        errdefer dwarf.debug_info.section.popUnit(dwarf.gpa);
2562        assert(try dwarf.debug_line.section.addUnit(
2563            DebugLine.headerBytes(dwarf, 5, 25),
2564            DebugLine.trailer_bytes,
2565            dwarf,
2566        ) == unit);
2567        errdefer dwarf.debug_line.section.popUnit(dwarf.gpa);
2568        assert(try dwarf.debug_loclists.section.addUnit(
2569            DebugLocLists.headerBytes(dwarf),
2570            DebugLocLists.trailer_bytes,
2571            dwarf,
2572        ) == unit);
2573        errdefer dwarf.debug_loclists.section.popUnit(dwarf.gpa);
2574        assert(try dwarf.debug_rnglists.section.addUnit(
2575            DebugRngLists.headerBytes(dwarf),
2576            DebugRngLists.trailer_bytes,
2577            dwarf,
2578        ) == unit);
2579        errdefer dwarf.debug_rnglists.section.popUnit(dwarf.gpa);
2580    }
2581    return unit;
2582}
2583
2584fn getUnitIfExists(dwarf: *const Dwarf, mod: *Module) ?Unit.Index {
2585    return @enumFromInt(dwarf.mods.getIndex(mod) orelse return null);
2586}
2587
2588fn getModInfo(dwarf: *Dwarf, unit: Unit.Index) *ModInfo {
2589    return &dwarf.mods.values()[@intFromEnum(unit)];
2590}
2591
2592pub fn initWipNav(
2593    dwarf: *Dwarf,
2594    pt: Zcu.PerThread,
2595    nav_index: InternPool.Nav.Index,
2596    sym_index: u32,
2597) error{ OutOfMemory, CodegenFail }!WipNav {
2598    return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) {
2599        error.OutOfMemory => error.OutOfMemory,
2600        else => |e| pt.zcu.codegenFail(nav_index, "failed to init dwarf: {s}", .{@errorName(e)}),
2601    };
2602}
2603
2604fn initWipNavInner(
2605    dwarf: *Dwarf,
2606    pt: Zcu.PerThread,
2607    nav_index: InternPool.Nav.Index,
2608    sym_index: u32,
2609) !WipNav {
2610    const zcu = pt.zcu;
2611    const ip = &zcu.intern_pool;
2612
2613    const nav = ip.getNav(nav_index);
2614    const inst_info = nav.srcInst(ip).resolveFull(ip).?;
2615    const file = zcu.fileByIndex(inst_info.file);
2616    const decl = file.zir.?.getDeclaration(inst_info.inst);
2617    log.debug("initWipNav({s}:{d}:{d} %{d} = {f})", .{
2618        file.sub_file_path,
2619        decl.src_line + 1,
2620        decl.src_column + 1,
2621        @intFromEnum(inst_info.inst),
2622        nav.fqn.fmt(ip),
2623    });
2624
2625    const mod = file.mod.?;
2626    const unit = try dwarf.getUnit(mod);
2627    const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
2628    errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
2629    if (nav_gop.found_existing) {
2630        for ([_]*Section{
2631            &dwarf.debug_aranges.section,
2632            &dwarf.debug_info.section,
2633            &dwarf.debug_line.section,
2634            &dwarf.debug_loclists.section,
2635            &dwarf.debug_rnglists.section,
2636        }) |sec| sec.getUnit(unit).getEntry(nav_gop.value_ptr.*).clear();
2637    } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2638    var wip_nav: WipNav = .{
2639        .dwarf = dwarf,
2640        .pt = pt,
2641        .unit = unit,
2642        .entry = nav_gop.value_ptr.*,
2643        .any_children = false,
2644        .func = .none,
2645        .func_sym_index = undefined,
2646        .func_high_pc = undefined,
2647        .blocks = undefined,
2648        .cfi = undefined,
2649        .debug_frame = .init(dwarf.gpa),
2650        .debug_info = .init(dwarf.gpa),
2651        .debug_line = .init(dwarf.gpa),
2652        .debug_loclists = .init(dwarf.gpa),
2653        .pending_lazy = .empty,
2654    };
2655    errdefer wip_nav.deinit();
2656
2657    const nav_val = zcu.navValue(nav_index);
2658    nav_val: switch (ip.indexToKey(nav_val.toIntern())) {
2659        .@"extern" => |@"extern"| switch (@"extern".source) {
2660            .builtin => {
2661                const maybe_func_type = switch (ip.indexToKey(@"extern".ty)) {
2662                    .func_type => |func_type| func_type,
2663                    else => null,
2664                };
2665                const diw = &wip_nav.debug_info.writer;
2666                try wip_nav.abbrevCode(if (maybe_func_type) |func_type|
2667                    if (func_type.param_types.len > 0 or func_type.is_var_args) .builtin_extern_func else .builtin_extern_nullary_func
2668                else
2669                    .builtin_extern_var);
2670                try wip_nav.refType(.fromInterned(zcu.fileRootType(inst_info.file)));
2671                try wip_nav.strp(@"extern".name.toSlice(ip));
2672                try wip_nav.refType(.fromInterned(if (maybe_func_type) |func_type| func_type.return_type else @"extern".ty));
2673                if (maybe_func_type) |func_type| {
2674                    try wip_nav.infoAddrSym(sym_index, 0);
2675                    try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
2676                    if (func_type.param_types.len > 0 or func_type.is_var_args) {
2677                        for (func_type.param_types.get(ip)) |param_type| {
2678                            try wip_nav.abbrevCode(.extern_param);
2679                            try wip_nav.refType(.fromInterned(param_type));
2680                        }
2681                        if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
2682                        try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
2683                    }
2684                } else try wip_nav.infoExprLoc(.{ .addr_reloc = sym_index });
2685            },
2686            .syntax => switch (ip.isFunctionType(@"extern".ty)) {
2687                false => continue :nav_val .{ .variable = undefined },
2688                true => {
2689                    const func_type = ip.indexToKey(@"extern".ty).func_type;
2690                    const diw = &wip_nav.debug_info.writer;
2691                    try wip_nav.declCommon(if (func_type.param_types.len > 0 or func_type.is_var_args) .{
2692                        .decl = .decl_extern_func,
2693                        .generic_decl = .generic_decl_func,
2694                        .decl_instance = .decl_instance_extern_func,
2695                    } else .{
2696                        .decl = .decl_extern_nullary_func,
2697                        .generic_decl = .generic_decl_func,
2698                        .decl_instance = .decl_instance_extern_nullary_func,
2699                    }, &nav, inst_info.file, &decl);
2700                    try wip_nav.strp(@"extern".name.toSlice(ip));
2701                    try wip_nav.refType(.fromInterned(func_type.return_type));
2702                    try wip_nav.infoAddrSym(sym_index, 0);
2703                    try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
2704                    if (func_type.param_types.len > 0 or func_type.is_var_args) {
2705                        for (func_type.param_types.get(ip)) |param_type| {
2706                            try wip_nav.abbrevCode(.extern_param);
2707                            try wip_nav.refType(.fromInterned(param_type));
2708                        }
2709                        if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
2710                        try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
2711                    }
2712                },
2713            },
2714        },
2715        .func => |func| if (func.owner_nav != nav_index) {
2716            try wip_nav.declCommon(.{
2717                .decl = .decl_alias,
2718                .generic_decl = .generic_decl_const,
2719                .decl_instance = .decl_instance_alias,
2720            }, &nav, inst_info.file, &decl);
2721            try wip_nav.refNav(func.owner_nav);
2722        } else {
2723            const func_type = ip.indexToKey(func.ty).func_type;
2724            wip_nav.func = nav_val.toIntern();
2725            wip_nav.func_sym_index = sym_index;
2726            wip_nav.blocks = .empty;
2727            if (dwarf.debug_frame.header.format != .none) wip_nav.cfi = .{
2728                .loc = 0,
2729                .cfa = dwarf.debug_frame.header.initial_instructions[0].def_cfa,
2730            };
2731
2732            switch (dwarf.debug_frame.header.format) {
2733                .none => {},
2734                .debug_frame, .eh_frame => |format| {
2735                    const entry = dwarf.debug_frame.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry);
2736                    const dfw = &wip_nav.debug_frame.writer;
2737                    switch (dwarf.format) {
2738                        .@"32" => try dfw.writeInt(u32, undefined, dwarf.endian),
2739                        .@"64" => {
2740                            try dfw.writeInt(u32, std.math.maxInt(u32), dwarf.endian);
2741                            try dfw.writeInt(u64, undefined, dwarf.endian);
2742                        },
2743                    }
2744                    switch (format) {
2745                        .none => unreachable,
2746                        .debug_frame => {
2747                            try entry.cross_entry_relocs.append(dwarf.gpa, .{
2748                                .source_off = @intCast(dfw.end),
2749                            });
2750                            try dfw.splatByteAll(0, dwarf.sectionOffsetBytes());
2751                            try wip_nav.frameAddrSym(sym_index, 0);
2752                            try dfw.splatByteAll(undefined, @intFromEnum(dwarf.address_size));
2753                        },
2754                        .eh_frame => {
2755                            try dfw.writeInt(u32, undefined, dwarf.endian);
2756                            try wip_nav.frameExternalReloc(.{
2757                                .source_off = @intCast(dfw.end),
2758                                .target_sym = sym_index,
2759                            });
2760                            try dfw.writeInt(u32, 0, dwarf.endian);
2761                            try dfw.writeInt(u32, undefined, dwarf.endian);
2762                            try dfw.writeUleb128(0);
2763                        },
2764                    }
2765                },
2766            }
2767
2768            const diw = &wip_nav.debug_info.writer;
2769            try wip_nav.declCommon(.{
2770                .decl = .decl_func,
2771                .generic_decl = .generic_decl_func,
2772                .decl_instance = .decl_instance_func,
2773            }, &nav, inst_info.file, &decl);
2774            try wip_nav.strp(switch (decl.linkage) {
2775                .normal => nav.fqn,
2776                .@"extern", .@"export" => nav.name,
2777            }.toSlice(ip));
2778            try wip_nav.refType(.fromInterned(func_type.return_type));
2779            try wip_nav.infoAddrSym(sym_index, 0);
2780            wip_nav.func_high_pc = @intCast(diw.end);
2781            try diw.writeInt(u32, 0, dwarf.endian);
2782            const target = &mod.resolved_target.result;
2783            try diw.writeUleb128(switch (nav.status.fully_resolved.alignment) {
2784                .none => target_info.defaultFunctionAlignment(target),
2785                else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
2786            }.toByteUnits().?);
2787            try diw.writeByte(@intFromBool(decl.linkage != .normal));
2788            try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
2789
2790            const dlw = &wip_nav.debug_line.writer;
2791            try dlw.writeByte(DW.LNS.extended_op);
2792            if (dwarf.incremental()) {
2793                try dlw.writeUleb128(1 + dwarf.sectionOffsetBytes());
2794                try dlw.writeByte(DW.LNE.ZIG_set_decl);
2795                try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{
2796                    .source_off = @intCast(dlw.end),
2797                    .target_sec = .debug_info,
2798                    .target_unit = wip_nav.unit,
2799                    .target_entry = wip_nav.entry.toOptional(),
2800                });
2801                try dlw.splatByteAll(0, dwarf.sectionOffsetBytes());
2802
2803                try dlw.writeByte(DW.LNS.set_column);
2804                try dlw.writeUleb128(func.lbrace_column + 1);
2805
2806                try wip_nav.advancePCAndLine(func.lbrace_line, 0);
2807            } else {
2808                try dlw.writeUleb128(1 + @intFromEnum(dwarf.address_size));
2809                try dlw.writeByte(DW.LNE.set_address);
2810                try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
2811                    .source_off = @intCast(dlw.end),
2812                    .target_sym = sym_index,
2813                });
2814                try dlw.splatByteAll(0, @intFromEnum(dwarf.address_size));
2815
2816                const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
2817                try dlw.writeByte(DW.LNS.set_file);
2818                try dlw.writeUleb128(file_gop.index);
2819
2820                try dlw.writeByte(DW.LNS.set_column);
2821                try dlw.writeUleb128(func.lbrace_column + 1);
2822
2823                try wip_nav.advancePCAndLine(@intCast(decl.src_line + func.lbrace_line), 0);
2824            }
2825        },
2826        else => {
2827            const diw = &wip_nav.debug_info.writer;
2828            try wip_nav.declCommon(.{
2829                .decl = .decl_var,
2830                .generic_decl = .generic_decl_var,
2831                .decl_instance = .decl_instance_var,
2832            }, &nav, inst_info.file, &decl);
2833            try wip_nav.strp(switch (decl.linkage) {
2834                .normal => nav.fqn,
2835                .@"extern", .@"export" => nav.name,
2836            }.toSlice(ip));
2837            const ty: Type = nav_val.typeOf(zcu);
2838            const addr: Loc = .{ .addr_reloc = sym_index };
2839            const loc: Loc = if (decl.is_threadlocal) loc: {
2840                const target = zcu.comp.root_mod.resolved_target.result;
2841                break :loc switch (target.cpu.arch) {
2842                    .x86_64 => .{ .form_tls_address = &addr },
2843                    else => .empty,
2844                };
2845            } else addr;
2846            switch (decl.kind) {
2847                .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
2848                .@"const" => {
2849                    const const_ty_reloc_index = try wip_nav.refForward();
2850                    try wip_nav.infoExprLoc(loc);
2851                    try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
2852                        ty.abiAlignment(zcu).toByteUnits().?);
2853                    try diw.writeByte(@intFromBool(decl.linkage != .normal));
2854                    wip_nav.finishForward(const_ty_reloc_index);
2855                    try wip_nav.abbrevCode(.is_const);
2856                    try wip_nav.refType(ty);
2857                },
2858                .@"var" => {
2859                    try wip_nav.refType(ty);
2860                    try wip_nav.infoExprLoc(loc);
2861                    try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
2862                        ty.abiAlignment(zcu).toByteUnits().?);
2863                    try diw.writeByte(@intFromBool(decl.linkage != .normal));
2864                },
2865            }
2866        },
2867    }
2868    return wip_nav;
2869}
2870
2871pub fn finishWipNavFunc(
2872    dwarf: *Dwarf,
2873    pt: Zcu.PerThread,
2874    nav_index: InternPool.Nav.Index,
2875    code_size: u64,
2876    wip_nav: *WipNav,
2877) UpdateError!void {
2878    return dwarf.finishWipNavFuncWriterError(pt, nav_index, code_size, wip_nav) catch |err| switch (err) {
2879        error.WriteFailed => error.OutOfMemory,
2880        else => |e| e,
2881    };
2882}
2883fn finishWipNavFuncWriterError(
2884    dwarf: *Dwarf,
2885    pt: Zcu.PerThread,
2886    nav_index: InternPool.Nav.Index,
2887    code_size: u64,
2888    wip_nav: *WipNav,
2889) (UpdateError || Writer.Error)!void {
2890    const zcu = pt.zcu;
2891    const ip = &zcu.intern_pool;
2892    const nav = ip.getNav(nav_index);
2893    assert(wip_nav.func != .none);
2894    log.debug("finishWipNavFunc({f})", .{nav.fqn.fmt(ip)});
2895
2896    {
2897        const external_relocs = &dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
2898        try external_relocs.append(dwarf.gpa, .{ .target_sym = wip_nav.func_sym_index });
2899        var entry: [8 + 8]u8 = undefined;
2900        @memset(entry[0..@intFromEnum(dwarf.address_size)], 0);
2901        dwarf.writeInt(entry[@intFromEnum(dwarf.address_size)..][0..@intFromEnum(dwarf.address_size)], code_size);
2902        try dwarf.debug_aranges.section.replaceEntry(
2903            wip_nav.unit,
2904            wip_nav.entry,
2905            dwarf,
2906            entry[0 .. @intFromEnum(dwarf.address_size) * 2],
2907        );
2908    }
2909    switch (dwarf.debug_frame.header.format) {
2910        .none => {},
2911        .debug_frame, .eh_frame => |format| {
2912            const dfw = &wip_nav.debug_frame.writer;
2913            try dfw.splatByteAll(
2914                DW.CFA.nop,
2915                @intCast(dwarf.debug_frame.section.alignment.forward(dfw.end) - dfw.end),
2916            );
2917            const contents = wip_nav.debug_frame.written();
2918            try dwarf.debug_frame.section.resizeEntry(wip_nav.unit, wip_nav.entry, dwarf, @intCast(contents.len));
2919            const unit = dwarf.debug_frame.section.getUnit(wip_nav.unit);
2920            const entry = unit.getEntry(wip_nav.entry);
2921            const unit_len = (if (entry.next.unwrap()) |next_entry|
2922                unit.getEntry(next_entry).off - entry.off
2923            else
2924                entry.len) - dwarf.unitLengthBytes();
2925            dwarf.writeInt(contents[dwarf.unitLengthBytes() - dwarf.sectionOffsetBytes() ..][0..dwarf.sectionOffsetBytes()], unit_len);
2926            switch (format) {
2927                .none => unreachable,
2928                .debug_frame => dwarf.writeInt(contents[dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() +
2929                    @intFromEnum(dwarf.address_size) ..][0..@intFromEnum(dwarf.address_size)], code_size),
2930                .eh_frame => {
2931                    std.mem.writeInt(
2932                        u32,
2933                        contents[dwarf.unitLengthBytes()..][0..4],
2934                        unit.header_len + entry.off + dwarf.unitLengthBytes(),
2935                        dwarf.endian,
2936                    );
2937                    std.mem.writeInt(u32, contents[dwarf.unitLengthBytes() + 4 + 4 ..][0..4], @intCast(code_size), dwarf.endian);
2938                },
2939            }
2940            try entry.replace(unit, &dwarf.debug_frame.section, dwarf, contents);
2941        },
2942    }
2943    {
2944        std.mem.writeInt(u32, wip_nav.debug_info.written()[wip_nav.func_high_pc..][0..4], @intCast(code_size), dwarf.endian);
2945        if (wip_nav.any_children) {
2946            const diw = &wip_nav.debug_info.writer;
2947            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
2948        } else {
2949            const abbrev_code_buf = wip_nav.debug_info.written()[0..AbbrevCode.decl_bytes];
2950            var abbrev_code_fr: std.Io.Reader = .fixed(abbrev_code_buf);
2951            const abbrev_code: AbbrevCode = @enumFromInt(
2952                abbrev_code_fr.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable,
2953            );
2954            std.leb.writeUnsignedFixed(
2955                AbbrevCode.decl_bytes,
2956                abbrev_code_buf,
2957                @intCast(try dwarf.refAbbrevCode(switch (abbrev_code) {
2958                    else => unreachable,
2959                    .decl_func => .decl_nullary_func,
2960                    .decl_instance_func => .decl_instance_nullary_func,
2961                })),
2962            );
2963        }
2964    }
2965    {
2966        try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.appendSlice(dwarf.gpa, &.{
2967            .{
2968                .source_off = 1,
2969                .target_sym = wip_nav.func_sym_index,
2970            },
2971            .{
2972                .source_off = 1 + @intFromEnum(dwarf.address_size),
2973                .target_sym = wip_nav.func_sym_index,
2974                .target_off = code_size,
2975            },
2976        });
2977        try dwarf.debug_rnglists.section.replaceEntry(
2978            wip_nav.unit,
2979            wip_nav.entry,
2980            dwarf,
2981            ([1]u8{DW.RLE.start_end} ++ [1]u8{0} ** (8 + 8))[0 .. 1 + @intFromEnum(dwarf.address_size) + @intFromEnum(dwarf.address_size)],
2982        );
2983    }
2984
2985    try dwarf.finishWipNav(pt, nav_index, wip_nav);
2986}
2987
2988pub fn finishWipNav(
2989    dwarf: *Dwarf,
2990    pt: Zcu.PerThread,
2991    nav_index: InternPool.Nav.Index,
2992    wip_nav: *WipNav,
2993) UpdateError!void {
2994    return dwarf.finishWipNavWriterError(pt, nav_index, wip_nav) catch |err| switch (err) {
2995        error.WriteFailed => error.OutOfMemory,
2996        else => |e| e,
2997    };
2998}
2999fn finishWipNavWriterError(
3000    dwarf: *Dwarf,
3001    pt: Zcu.PerThread,
3002    nav_index: InternPool.Nav.Index,
3003    wip_nav: *WipNav,
3004) (UpdateError || Writer.Error)!void {
3005    const zcu = pt.zcu;
3006    const ip = &zcu.intern_pool;
3007    const nav = ip.getNav(nav_index);
3008    log.debug("finishWipNav({f})", .{nav.fqn.fmt(ip)});
3009
3010    try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
3011    const dlw = &wip_nav.debug_line.writer;
3012    if (dlw.end > 0) {
3013        try dlw.writeByte(DW.LNS.extended_op);
3014        try dlw.writeUleb128(1);
3015        try dlw.writeByte(DW.LNE.end_sequence);
3016        try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.written());
3017    }
3018    try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written());
3019
3020    try wip_nav.updateLazy(zcu.navSrcLoc(nav_index));
3021}
3022
3023pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error{ OutOfMemory, CodegenFail }!void {
3024    return updateComptimeNavInner(dwarf, pt, nav_index) catch |err| switch (err) {
3025        error.OutOfMemory => error.OutOfMemory,
3026        else => |e| pt.zcu.codegenFail(nav_index, "failed to update dwarf: {s}", .{@errorName(e)}),
3027    };
3028}
3029
3030fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
3031    const zcu = pt.zcu;
3032    const ip = &zcu.intern_pool;
3033    const nav_src_loc = zcu.navSrcLoc(nav_index);
3034    const nav_val = zcu.navValue(nav_index);
3035
3036    const nav = ip.getNav(nav_index);
3037    const inst_info = nav.srcInst(ip).resolveFull(ip).?;
3038    const file = zcu.fileByIndex(inst_info.file);
3039    const decl = file.zir.?.getDeclaration(inst_info.inst);
3040    log.debug("updateComptimeNav({s}:{d}:{d} %{d} = {f})", .{
3041        file.sub_file_path,
3042        decl.src_line + 1,
3043        decl.src_column + 1,
3044        @intFromEnum(inst_info.inst),
3045        nav.fqn.fmt(ip),
3046    });
3047
3048    const is_test = switch (decl.kind) {
3049        .unnamed_test, .@"test", .decltest => true,
3050        .@"comptime", .@"const", .@"var" => false,
3051    };
3052    if (is_test) {
3053        // This isn't actually a comptime Nav! It's a test, so it'll definitely never be referenced at comptime.
3054        return;
3055    }
3056
3057    var wip_nav: WipNav = .{
3058        .dwarf = dwarf,
3059        .pt = pt,
3060        .unit = try dwarf.getUnit(file.mod.?),
3061        .entry = undefined,
3062        .any_children = false,
3063        .func = .none,
3064        .func_sym_index = undefined,
3065        .func_high_pc = undefined,
3066        .blocks = undefined,
3067        .cfi = undefined,
3068        .debug_frame = .init(dwarf.gpa),
3069        .debug_info = .init(dwarf.gpa),
3070        .debug_line = .init(dwarf.gpa),
3071        .debug_loclists = .init(dwarf.gpa),
3072        .pending_lazy = .empty,
3073    };
3074    defer wip_nav.deinit();
3075
3076    const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
3077    errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
3078
3079    const tag: union(enum) {
3080        done,
3081        decl_alias,
3082        decl_var,
3083        decl_const,
3084        decl_func_alias: InternPool.Nav.Index,
3085    } = switch (ip.indexToKey(nav_val.toIntern())) {
3086        .int_type,
3087        .ptr_type,
3088        .array_type,
3089        .vector_type,
3090        .opt_type,
3091        .error_union_type,
3092        .anyframe_type,
3093        .simple_type,
3094        .tuple_type,
3095        .func_type,
3096        .error_set_type,
3097        .inferred_error_set_type,
3098        => .decl_alias,
3099        .struct_type => tag: {
3100            const loaded_struct = ip.loadStructType(nav_val.toIntern());
3101            if (loaded_struct.zir_index.resolveFile(ip) != inst_info.file) break :tag .decl_alias;
3102
3103            const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
3104            if (type_gop.found_existing) {
3105                if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias;
3106                assert(!nav_gop.found_existing);
3107                nav_gop.value_ptr.* = type_gop.value_ptr.*;
3108            } else {
3109                if (nav_gop.found_existing)
3110                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
3111                else
3112                    nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
3113                type_gop.value_ptr.* = nav_gop.value_ptr.*;
3114            }
3115            wip_nav.entry = nav_gop.value_ptr.*;
3116
3117            const diw = &wip_nav.debug_info.writer;
3118
3119            switch (loaded_struct.layout) {
3120                .auto, .@"extern" => {
3121                    try wip_nav.declCommon(if (loaded_struct.field_types.len == 0) .{
3122                        .decl = .decl_namespace_struct,
3123                        .generic_decl = .generic_decl_const,
3124                        .decl_instance = .decl_instance_namespace_struct,
3125                    } else .{
3126                        .decl = .decl_struct,
3127                        .generic_decl = .generic_decl_const,
3128                        .decl_instance = .decl_instance_struct,
3129                    }, &nav, inst_info.file, &decl);
3130                    if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
3131                        try diw.writeUleb128(nav_val.toType().abiSize(zcu));
3132                        try diw.writeUleb128(nav_val.toType().abiAlignment(zcu).toByteUnits().?);
3133                        for (0..loaded_struct.field_types.len) |field_index| {
3134                            const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
3135                            const field_init = loaded_struct.fieldInit(ip, field_index);
3136                            assert(!(is_comptime and field_init == .none));
3137                            const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
3138                            const has_runtime_bits, const has_comptime_state = switch (field_init) {
3139                                .none => .{ false, false },
3140                                else => .{
3141                                    field_type.hasRuntimeBits(zcu),
3142                                    field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,
3143                                },
3144                            };
3145                            try wip_nav.abbrevCode(if (is_comptime)
3146                                if (has_comptime_state)
3147                                    .struct_field_comptime_comptime_state
3148                                else if (has_runtime_bits)
3149                                    .struct_field_comptime_runtime_bits
3150                                else
3151                                    .struct_field_comptime
3152                            else if (field_init != .none)
3153                                if (has_comptime_state)
3154                                    .struct_field_default_comptime_state
3155                                else if (has_runtime_bits)
3156                                    .struct_field_default_runtime_bits
3157                                else
3158                                    .struct_field
3159                            else
3160                                .struct_field);
3161                            try wip_nav.strp(loaded_struct.fieldName(ip, field_index).toSlice(ip));
3162                            try wip_nav.refType(field_type);
3163                            if (!is_comptime) {
3164                                try diw.writeUleb128(loaded_struct.offsets.get(ip)[field_index]);
3165                                try diw.writeUleb128(loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
3166                                    field_type.abiAlignment(zcu).toByteUnits().?);
3167                            }
3168                            if (has_comptime_state)
3169                                try wip_nav.refValue(.fromInterned(field_init))
3170                            else if (has_runtime_bits)
3171                                try wip_nav.blockValue(nav_src_loc, .fromInterned(field_init));
3172                        }
3173                        try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3174                    }
3175                },
3176                .@"packed" => {
3177                    try wip_nav.declCommon(.{
3178                        .decl = .decl_packed_struct,
3179                        .generic_decl = .generic_decl_const,
3180                        .decl_instance = .decl_instance_packed_struct,
3181                    }, &nav, inst_info.file, &decl);
3182                    try wip_nav.refType(.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
3183                    var field_bit_offset: u16 = 0;
3184                    for (0..loaded_struct.field_types.len) |field_index| {
3185                        try wip_nav.abbrevCode(.packed_struct_field);
3186                        try wip_nav.strp(loaded_struct.fieldName(ip, field_index).toSlice(ip));
3187                        const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
3188                        try wip_nav.refType(field_type);
3189                        try diw.writeUleb128(field_bit_offset);
3190                        field_bit_offset += @intCast(field_type.bitSize(zcu));
3191                    }
3192                    try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3193                },
3194            }
3195            break :tag .done;
3196        },
3197        .enum_type => tag: {
3198            const loaded_enum = ip.loadEnumType(nav_val.toIntern());
3199            const type_zir_index = loaded_enum.zir_index.unwrap() orelse break :tag .decl_alias;
3200            if (type_zir_index.resolveFile(ip) != inst_info.file) break :tag .decl_alias;
3201
3202            const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
3203            if (type_gop.found_existing) {
3204                if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias;
3205                assert(!nav_gop.found_existing);
3206                nav_gop.value_ptr.* = type_gop.value_ptr.*;
3207            } else {
3208                if (nav_gop.found_existing)
3209                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
3210                else
3211                    nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
3212                type_gop.value_ptr.* = nav_gop.value_ptr.*;
3213            }
3214            wip_nav.entry = nav_gop.value_ptr.*;
3215            const diw = &wip_nav.debug_info.writer;
3216            try wip_nav.declCommon(if (loaded_enum.names.len > 0) .{
3217                .decl = .decl_enum,
3218                .generic_decl = .generic_decl_const,
3219                .decl_instance = .decl_instance_enum,
3220            } else .{
3221                .decl = .decl_empty_enum,
3222                .generic_decl = .generic_decl_const,
3223                .decl_instance = .decl_instance_empty_enum,
3224            }, &nav, inst_info.file, &decl);
3225            try wip_nav.refType(.fromInterned(loaded_enum.tag_ty));
3226            for (0..loaded_enum.names.len) |field_index| {
3227                try wip_nav.enumConstValue(loaded_enum, .{
3228                    .sdata = .signed_enum_field,
3229                    .udata = .unsigned_enum_field,
3230                    .block = .big_enum_field,
3231                }, field_index);
3232                try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
3233            }
3234            if (loaded_enum.names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3235            break :tag .done;
3236        },
3237        .union_type => tag: {
3238            const loaded_union = ip.loadUnionType(nav_val.toIntern());
3239            if (loaded_union.zir_index.resolveFile(ip) != inst_info.file) break :tag .decl_alias;
3240
3241            const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
3242            if (type_gop.found_existing) {
3243                if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias;
3244                assert(!nav_gop.found_existing);
3245                nav_gop.value_ptr.* = type_gop.value_ptr.*;
3246            } else {
3247                if (nav_gop.found_existing)
3248                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
3249                else
3250                    nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
3251                type_gop.value_ptr.* = nav_gop.value_ptr.*;
3252            }
3253            wip_nav.entry = nav_gop.value_ptr.*;
3254            const diw = &wip_nav.debug_info.writer;
3255            try wip_nav.declCommon(.{
3256                .decl = .decl_union,
3257                .generic_decl = .generic_decl_const,
3258                .decl_instance = .decl_instance_union,
3259            }, &nav, inst_info.file, &decl);
3260            const union_layout = Type.getUnionLayout(loaded_union, zcu);
3261            try diw.writeUleb128(union_layout.abi_size);
3262            try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
3263            const loaded_tag = loaded_union.loadTagType(ip);
3264            if (loaded_union.hasTag(ip)) {
3265                try wip_nav.abbrevCode(.tagged_union);
3266                try wip_nav.infoSectionOffset(
3267                    .debug_info,
3268                    wip_nav.unit,
3269                    wip_nav.entry,
3270                    @intCast(diw.end + dwarf.sectionOffsetBytes()),
3271                );
3272                {
3273                    try wip_nav.abbrevCode(.generated_field);
3274                    try wip_nav.strp("tag");
3275                    try wip_nav.refType(.fromInterned(loaded_union.enum_tag_ty));
3276                    try diw.writeUleb128(union_layout.tagOffset());
3277
3278                    for (0..loaded_union.field_types.len) |field_index| {
3279                        try wip_nav.enumConstValue(loaded_tag, .{
3280                            .sdata = .signed_tagged_union_field,
3281                            .udata = .unsigned_tagged_union_field,
3282                            .block = .big_tagged_union_field,
3283                        }, field_index);
3284                        {
3285                            try wip_nav.abbrevCode(.struct_field);
3286                            try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
3287                            const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
3288                            try wip_nav.refType(field_type);
3289                            try diw.writeUleb128(union_layout.payloadOffset());
3290                            try diw.writeUleb128(loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
3291                                if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
3292                        }
3293                        try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3294                    }
3295                }
3296                try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3297            } else for (0..loaded_union.field_types.len) |field_index| {
3298                try wip_nav.abbrevCode(.untagged_union_field);
3299                try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
3300                const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
3301                try wip_nav.refType(field_type);
3302                try diw.writeUleb128(loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
3303                    if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
3304            }
3305            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3306            break :tag .done;
3307        },
3308        .opaque_type => tag: {
3309            const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
3310            if (loaded_opaque.zir_index.resolveFile(ip) != inst_info.file) break :tag .decl_alias;
3311
3312            const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
3313            if (type_gop.found_existing) {
3314                if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias;
3315                assert(!nav_gop.found_existing);
3316                nav_gop.value_ptr.* = type_gop.value_ptr.*;
3317            } else {
3318                if (nav_gop.found_existing)
3319                    dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
3320                else
3321                    nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
3322                type_gop.value_ptr.* = nav_gop.value_ptr.*;
3323            }
3324            wip_nav.entry = nav_gop.value_ptr.*;
3325            const diw = &wip_nav.debug_info.writer;
3326            try wip_nav.declCommon(.{
3327                .decl = .decl_namespace_struct,
3328                .generic_decl = .generic_decl_const,
3329                .decl_instance = .decl_instance_namespace_struct,
3330            }, &nav, inst_info.file, &decl);
3331            try diw.writeByte(@intFromBool(true));
3332            break :tag .done;
3333        },
3334        .undef,
3335        .simple_value,
3336        .int,
3337        .err,
3338        .error_union,
3339        .enum_literal,
3340        .enum_tag,
3341        .empty_enum_value,
3342        .float,
3343        .ptr,
3344        .slice,
3345        .opt,
3346        .aggregate,
3347        .un,
3348        => .decl_const,
3349        .variable => .decl_var,
3350        .@"extern" => unreachable,
3351        .func => |func| tag: {
3352            if (func.owner_nav != nav_index) break :tag .{ .decl_func_alias = func.owner_nav };
3353            if (nav_gop.found_existing) switch (try dwarf.debug_info.declAbbrevCode(wip_nav.unit, nav_gop.value_ptr.*)) {
3354                .null => {},
3355                else => unreachable,
3356                .decl_nullary_func, .decl_func, .decl_instance_nullary_func, .decl_instance_func => return,
3357                .decl_nullary_func_generic,
3358                .decl_func_generic,
3359                .decl_instance_nullary_func_generic,
3360                .decl_instance_func_generic,
3361                => dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear(),
3362            } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
3363            wip_nav.entry = nav_gop.value_ptr.*;
3364
3365            const func_type = ip.indexToKey(func.ty).func_type;
3366            const is_nullary = !func_type.is_var_args and for (0..func_type.param_types.len) |param_index| {
3367                if (!func_type.paramIsComptime(std.math.cast(u5, param_index) orelse break false)) break false;
3368            } else true;
3369            const diw = &wip_nav.debug_info.writer;
3370            try wip_nav.declCommon(if (is_nullary) .{
3371                .decl = .decl_nullary_func_generic,
3372                .generic_decl = .generic_decl_func,
3373                .decl_instance = .decl_instance_nullary_func_generic,
3374            } else .{
3375                .decl = .decl_func_generic,
3376                .generic_decl = .generic_decl_func,
3377                .decl_instance = .decl_instance_func_generic,
3378            }, &nav, inst_info.file, &decl);
3379            try wip_nav.refType(.fromInterned(func_type.return_type));
3380            if (!is_nullary) {
3381                for (0..func_type.param_types.len) |param_index| {
3382                    if (std.math.cast(u5, param_index)) |small_param_index|
3383                        if (func_type.paramIsComptime(small_param_index)) continue;
3384                    try wip_nav.abbrevCode(.func_type_param);
3385                    try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
3386                }
3387                if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
3388                try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3389            }
3390            break :tag .done;
3391        },
3392        // memoization, not types
3393        .memoized_call => unreachable,
3394    };
3395    if (tag != .done) {
3396        if (nav_gop.found_existing)
3397            dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
3398        else
3399            nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
3400        wip_nav.entry = nav_gop.value_ptr.*;
3401    }
3402    switch (tag) {
3403        .done => {},
3404        .decl_alias => {
3405            try wip_nav.declCommon(.{
3406                .decl = .decl_alias,
3407                .generic_decl = .generic_decl_const,
3408                .decl_instance = .decl_instance_alias,
3409            }, &nav, inst_info.file, &decl);
3410            try wip_nav.refType(nav_val.toType());
3411        },
3412        .decl_var => {
3413            const diw = &wip_nav.debug_info.writer;
3414            try wip_nav.declCommon(.{
3415                .decl = .decl_var,
3416                .generic_decl = .generic_decl_var,
3417                .decl_instance = .decl_instance_var,
3418            }, &nav, inst_info.file, &decl);
3419            try wip_nav.strp(switch (decl.linkage) {
3420                .normal => nav.fqn,
3421                .@"extern", .@"export" => nav.name,
3422            }.toSlice(ip));
3423            const nav_ty = nav_val.typeOf(zcu);
3424            try wip_nav.refType(nav_ty);
3425            try wip_nav.blockValue(nav_src_loc, nav_val);
3426            try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
3427                nav_ty.abiAlignment(zcu).toByteUnits().?);
3428            try diw.writeByte(@intFromBool(decl.linkage != .normal));
3429        },
3430        .decl_const => {
3431            const diw = &wip_nav.debug_info.writer;
3432            const nav_ty = nav_val.typeOf(zcu);
3433            const has_runtime_bits = nav_ty.hasRuntimeBits(zcu);
3434            const has_comptime_state = nav_ty.comptimeOnly(zcu) and try nav_ty.onePossibleValue(pt) == null;
3435            try wip_nav.declCommon(if (has_runtime_bits and has_comptime_state) .{
3436                .decl = .decl_const_runtime_bits_comptime_state,
3437                .generic_decl = .generic_decl_const,
3438                .decl_instance = .decl_instance_const_runtime_bits_comptime_state,
3439            } else if (has_comptime_state) .{
3440                .decl = .decl_const_comptime_state,
3441                .generic_decl = .generic_decl_const,
3442                .decl_instance = .decl_instance_const_comptime_state,
3443            } else if (has_runtime_bits) .{
3444                .decl = .decl_const_runtime_bits,
3445                .generic_decl = .generic_decl_const,
3446                .decl_instance = .decl_instance_const_runtime_bits,
3447            } else .{
3448                .decl = .decl_const,
3449                .generic_decl = .generic_decl_const,
3450                .decl_instance = .decl_instance_const,
3451            }, &nav, inst_info.file, &decl);
3452            try wip_nav.strp(switch (decl.linkage) {
3453                .normal => nav.fqn,
3454                .@"extern", .@"export" => nav.name,
3455            }.toSlice(ip));
3456            const nav_ty_reloc_index = try wip_nav.refForward();
3457            try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
3458                nav_ty.abiAlignment(zcu).toByteUnits().?);
3459            try diw.writeByte(@intFromBool(decl.linkage != .normal));
3460            if (has_runtime_bits) try wip_nav.blockValue(nav_src_loc, nav_val);
3461            if (has_comptime_state) try wip_nav.refValue(nav_val);
3462            wip_nav.finishForward(nav_ty_reloc_index);
3463            try wip_nav.abbrevCode(.is_const);
3464            try wip_nav.refType(nav_ty);
3465        },
3466        .decl_func_alias => |owner_nav| {
3467            try wip_nav.declCommon(.{
3468                .decl = .decl_alias,
3469                .generic_decl = .generic_decl_const,
3470                .decl_instance = .decl_instance_alias,
3471            }, &nav, inst_info.file, &decl);
3472            try wip_nav.refNav(owner_nav);
3473        },
3474    }
3475    try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
3476    try wip_nav.updateLazy(nav_src_loc);
3477}
3478
3479fn updateLazyType(
3480    dwarf: *Dwarf,
3481    pt: Zcu.PerThread,
3482    src_loc: Zcu.LazySrcLoc,
3483    type_index: InternPool.Index,
3484    pending_lazy: *WipNav.PendingLazy,
3485) (UpdateError || Writer.Error)!void {
3486    const zcu = pt.zcu;
3487    const ip = &zcu.intern_pool;
3488    assert(ip.typeOf(type_index) == .type_type);
3489    const ty: Type = .fromInterned(type_index);
3490    switch (type_index) {
3491        .generic_poison_type => log.debug("updateLazyType({s})", .{"anytype"}),
3492        else => log.debug("updateLazyType({f})", .{ty.fmt(pt)}),
3493    }
3494
3495    var wip_nav: WipNav = .{
3496        .dwarf = dwarf,
3497        .pt = pt,
3498        .unit = .main,
3499        .entry = dwarf.types.get(type_index).?,
3500        .any_children = false,
3501        .func = .none,
3502        .func_sym_index = undefined,
3503        .func_high_pc = undefined,
3504        .blocks = undefined,
3505        .cfi = undefined,
3506        .debug_frame = .init(dwarf.gpa),
3507        .debug_info = .init(dwarf.gpa),
3508        .debug_line = .init(dwarf.gpa),
3509        .debug_loclists = .init(dwarf.gpa),
3510        .pending_lazy = pending_lazy.*,
3511    };
3512    defer {
3513        pending_lazy.* = wip_nav.pending_lazy;
3514        wip_nav.pending_lazy = .empty;
3515        wip_nav.deinit();
3516    }
3517    const diw = &wip_nav.debug_info.writer;
3518    const name = switch (type_index) {
3519        .generic_poison_type => "",
3520        else => try std.fmt.allocPrint(dwarf.gpa, "{f}", .{ty.fmt(pt)}),
3521    };
3522    defer dwarf.gpa.free(name);
3523
3524    switch (ip.indexToKey(type_index)) {
3525        .undef => {
3526            try wip_nav.abbrevCode(.undefined_comptime_value);
3527            try wip_nav.refType(.type);
3528        },
3529        .int_type => |int_type| {
3530            try wip_nav.abbrevCode(.numeric_type);
3531            try wip_nav.strp(name);
3532            try diw.writeByte(switch (int_type.signedness) {
3533                inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)),
3534            });
3535            try diw.writeUleb128(int_type.bits);
3536            try diw.writeUleb128(ty.abiSize(zcu));
3537            try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
3538        },
3539        .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
3540            .one, .many, .c => {
3541                const ptr_child_type: Type = .fromInterned(ptr_type.child);
3542                try wip_nav.abbrevCode(if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type);
3543                try wip_nav.strp(name);
3544                if (ptr_type.sentinel != .none) try wip_nav.blockValue(src_loc, .fromInterned(ptr_type.sentinel));
3545                try diw.writeUleb128(ptr_type.flags.alignment.toByteUnits() orelse
3546                    ptr_child_type.abiAlignment(zcu).toByteUnits().?);
3547                try diw.writeByte(@intFromEnum(ptr_type.flags.address_space));
3548                if (ptr_type.flags.is_const or ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
3549                    .debug_info,
3550                    wip_nav.unit,
3551                    wip_nav.entry,
3552                    @intCast(diw.end + dwarf.sectionOffsetBytes()),
3553                ) else try wip_nav.refType(ptr_child_type);
3554                if (ptr_type.flags.is_const) {
3555                    try wip_nav.abbrevCode(.is_const);
3556                    if (ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
3557                        .debug_info,
3558                        wip_nav.unit,
3559                        wip_nav.entry,
3560                        @intCast(diw.end + dwarf.sectionOffsetBytes()),
3561                    ) else try wip_nav.refType(ptr_child_type);
3562                }
3563                if (ptr_type.flags.is_volatile) {
3564                    try wip_nav.abbrevCode(.is_volatile);
3565                    try wip_nav.refType(ptr_child_type);
3566                }
3567            },
3568            .slice => {
3569                try wip_nav.abbrevCode(.generated_struct_type);
3570                try wip_nav.strp(name);
3571                try diw.writeUleb128(ty.abiSize(zcu));
3572                try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
3573                try wip_nav.abbrevCode(.generated_field);
3574                try wip_nav.strp("ptr");
3575                const ptr_field_type = ty.slicePtrFieldType(zcu);
3576                try wip_nav.refType(ptr_field_type);
3577                try diw.writeUleb128(0);
3578                try wip_nav.abbrevCode(.generated_field);
3579                try wip_nav.strp("len");
3580                const len_field_type: Type = .usize;
3581                try wip_nav.refType(len_field_type);
3582                try diw.writeUleb128(len_field_type.abiAlignment(zcu).forward(ptr_field_type.abiSize(zcu)));
3583                try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3584            },
3585        },
3586        .array_type => |array_type| {
3587            const array_child_type: Type = .fromInterned(array_type.child);
3588            try wip_nav.abbrevCode(if (array_type.sentinel == .none) .array_type else .array_sentinel_type);
3589            try wip_nav.strp(name);
3590            if (array_type.sentinel != .none) try wip_nav.blockValue(src_loc, .fromInterned(array_type.sentinel));
3591            try wip_nav.refType(array_child_type);
3592            try wip_nav.abbrevCode(.array_index);
3593            try wip_nav.refType(.usize);
3594            try diw.writeUleb128(array_type.len);
3595            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3596        },
3597        .vector_type => |vector_type| {
3598            try wip_nav.abbrevCode(.vector_type);
3599            try wip_nav.strp(name);
3600            try wip_nav.refType(.fromInterned(vector_type.child));
3601            try wip_nav.abbrevCode(.array_index);
3602            try wip_nav.refType(.usize);
3603            try diw.writeUleb128(vector_type.len);
3604            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3605        },
3606        .opt_type => |opt_child_type_index| {
3607            const opt_child_type: Type = .fromInterned(opt_child_type_index);
3608            const opt_repr = optRepr(opt_child_type, zcu);
3609            try wip_nav.abbrevCode(.generated_union_type);
3610            try wip_nav.strp(name);
3611            try diw.writeUleb128(ty.abiSize(zcu));
3612            try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
3613            switch (opt_repr) {
3614                .opv_null => {
3615                    try wip_nav.abbrevCode(.generated_field);
3616                    try wip_nav.strp("null");
3617                    try wip_nav.refType(.null);
3618                    try diw.writeUleb128(0);
3619                },
3620                .unpacked, .error_set, .pointer => {
3621                    try wip_nav.abbrevCode(.tagged_union);
3622                    try wip_nav.infoSectionOffset(
3623                        .debug_info,
3624                        wip_nav.unit,
3625                        wip_nav.entry,
3626                        @intCast(diw.end + dwarf.sectionOffsetBytes()),
3627                    );
3628                    {
3629                        try wip_nav.abbrevCode(.generated_field);
3630                        try wip_nav.strp("has_value");
3631                        switch (opt_repr) {
3632                            .opv_null => unreachable,
3633                            .unpacked => {
3634                                try wip_nav.refType(.bool);
3635                                try diw.writeUleb128(if (opt_child_type.hasRuntimeBits(zcu))
3636                                    opt_child_type.abiSize(zcu)
3637                                else
3638                                    0);
3639                            },
3640                            .error_set => {
3641                                try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
3642                                    .signedness = .unsigned,
3643                                    .bits = zcu.errorSetBits(),
3644                                } })));
3645                                try diw.writeUleb128(0);
3646                            },
3647                            .pointer => {
3648                                try wip_nav.refType(.usize);
3649                                try diw.writeUleb128(0);
3650                            },
3651                        }
3652
3653                        try wip_nav.abbrevCode(.unsigned_tagged_union_field);
3654                        try diw.writeUleb128(0);
3655                        {
3656                            try wip_nav.abbrevCode(.generated_field);
3657                            try wip_nav.strp("null");
3658                            try wip_nav.refType(.null);
3659                            try diw.writeUleb128(0);
3660                        }
3661                        try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3662
3663                        try wip_nav.abbrevCode(.tagged_union_default_field);
3664                        {
3665                            try wip_nav.abbrevCode(.generated_field);
3666                            try wip_nav.strp("?");
3667                            try wip_nav.refType(opt_child_type);
3668                            try diw.writeUleb128(0);
3669                        }
3670                        try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3671                    }
3672                    try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3673                },
3674            }
3675            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3676        },
3677        .anyframe_type => unreachable,
3678        .error_union_type => |error_union_type| {
3679            const error_union_error_set_type: Type = .fromInterned(error_union_type.error_set_type);
3680            const error_union_payload_type: Type = .fromInterned(error_union_type.payload_type);
3681            const error_union_error_set_offset, const error_union_payload_offset = switch (error_union_type.payload_type) {
3682                .generic_poison_type => .{ 0, 0 },
3683                else => .{
3684                    codegen.errUnionErrorOffset(error_union_payload_type, zcu),
3685                    codegen.errUnionPayloadOffset(error_union_payload_type, zcu),
3686                },
3687            };
3688
3689            try wip_nav.abbrevCode(.generated_union_type);
3690            try wip_nav.strp(name);
3691            if (error_union_type.error_set_type != .generic_poison_type and
3692                error_union_type.payload_type != .generic_poison_type)
3693            {
3694                try diw.writeUleb128(ty.abiSize(zcu));
3695                try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
3696            } else {
3697                try diw.writeUleb128(0);
3698                try diw.writeUleb128(1);
3699            }
3700            {
3701                try wip_nav.abbrevCode(.tagged_union);
3702                try wip_nav.infoSectionOffset(
3703                    .debug_info,
3704                    wip_nav.unit,
3705                    wip_nav.entry,
3706                    @intCast(diw.end + dwarf.sectionOffsetBytes()),
3707                );
3708                {
3709                    try wip_nav.abbrevCode(.generated_field);
3710                    try wip_nav.strp("is_error");
3711                    try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
3712                        .signedness = .unsigned,
3713                        .bits = zcu.errorSetBits(),
3714                    } })));
3715                    try diw.writeUleb128(error_union_error_set_offset);
3716
3717                    try wip_nav.abbrevCode(.unsigned_tagged_union_field);
3718                    try diw.writeUleb128(0);
3719                    {
3720                        try wip_nav.abbrevCode(.generated_field);
3721                        try wip_nav.strp("value");
3722                        try wip_nav.refType(error_union_payload_type);
3723                        try diw.writeUleb128(error_union_payload_offset);
3724                    }
3725                    try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3726
3727                    try wip_nav.abbrevCode(.tagged_union_default_field);
3728                    {
3729                        try wip_nav.abbrevCode(.generated_field);
3730                        try wip_nav.strp("error");
3731                        try wip_nav.refType(error_union_error_set_type);
3732                        try diw.writeUleb128(error_union_error_set_offset);
3733                    }
3734                    try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3735                }
3736                try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3737            }
3738            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3739        },
3740        .simple_type => |simple_type| switch (simple_type) {
3741            .f16,
3742            .f32,
3743            .f64,
3744            .f80,
3745            .f128,
3746            .usize,
3747            .isize,
3748            .c_char,
3749            .c_short,
3750            .c_ushort,
3751            .c_int,
3752            .c_uint,
3753            .c_long,
3754            .c_ulong,
3755            .c_longlong,
3756            .c_ulonglong,
3757            .c_longdouble,
3758            .bool,
3759            => {
3760                try wip_nav.abbrevCode(.numeric_type);
3761                try wip_nav.strp(name);
3762                try diw.writeByte(if (type_index == .bool_type)
3763                    DW.ATE.boolean
3764                else if (ty.isRuntimeFloat())
3765                    DW.ATE.float
3766                else if (ty.isSignedInt(zcu))
3767                    DW.ATE.signed
3768                else if (ty.isUnsignedInt(zcu))
3769                    DW.ATE.unsigned
3770                else
3771                    unreachable);
3772                try diw.writeUleb128(ty.bitSize(zcu));
3773                try diw.writeUleb128(ty.abiSize(zcu));
3774                try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
3775            },
3776            .anyopaque,
3777            .void,
3778            .type,
3779            .comptime_int,
3780            .comptime_float,
3781            .noreturn,
3782            .null,
3783            .undefined,
3784            .enum_literal,
3785            .generic_poison,
3786            => {
3787                try wip_nav.abbrevCode(.void_type);
3788                try wip_nav.strp(if (type_index == .generic_poison_type) "anytype" else name);
3789            },
3790            .anyerror => return, // delay until flush
3791            .adhoc_inferred_error_set => unreachable,
3792        },
3793        .struct_type,
3794        .union_type,
3795        .opaque_type,
3796        => unreachable,
3797        .tuple_type => |tuple_type| if (tuple_type.types.len == 0) {
3798            try wip_nav.abbrevCode(.generated_empty_struct_type);
3799            try wip_nav.strp(name);
3800            try diw.writeByte(@intFromBool(false));
3801        } else {
3802            try wip_nav.abbrevCode(.generated_struct_type);
3803            try wip_nav.strp(name);
3804            try diw.writeUleb128(ty.abiSize(zcu));
3805            try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
3806            var field_byte_offset: u64 = 0;
3807            for (0..tuple_type.types.len) |field_index| {
3808                const comptime_value = tuple_type.values.get(ip)[field_index];
3809                const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);
3810                const has_runtime_bits, const has_comptime_state = switch (comptime_value) {
3811                    .none => .{ false, false },
3812                    else => .{
3813                        field_type.hasRuntimeBits(zcu),
3814                        field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,
3815                    },
3816                };
3817                try wip_nav.abbrevCode(if (has_comptime_state)
3818                    .struct_field_comptime_comptime_state
3819                else if (has_runtime_bits)
3820                    .struct_field_comptime_runtime_bits
3821                else if (comptime_value != .none)
3822                    .struct_field_comptime
3823                else
3824                    .struct_field);
3825                {
3826                    var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined;
3827                    const field_name = std.fmt.bufPrint(&field_name_buf, "{d}", .{field_index}) catch unreachable;
3828                    try wip_nav.strp(field_name);
3829                }
3830                try wip_nav.refType(field_type);
3831                if (comptime_value == .none) {
3832                    const field_align = field_type.abiAlignment(zcu);
3833                    field_byte_offset = field_align.forward(field_byte_offset);
3834                    try diw.writeUleb128(field_byte_offset);
3835                    try diw.writeUleb128(field_type.abiAlignment(zcu).toByteUnits().?);
3836                    field_byte_offset += field_type.abiSize(zcu);
3837                }
3838                if (has_comptime_state)
3839                    try wip_nav.refValue(.fromInterned(comptime_value))
3840                else if (has_runtime_bits)
3841                    try wip_nav.blockValue(src_loc, .fromInterned(comptime_value));
3842            }
3843            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3844        },
3845        .enum_type => {
3846            const loaded_enum = ip.loadEnumType(type_index);
3847            try wip_nav.abbrevCode(if (loaded_enum.names.len == 0) .generated_empty_enum_type else .generated_enum_type);
3848            try wip_nav.strp(name);
3849            try wip_nav.refType(.fromInterned(loaded_enum.tag_ty));
3850            for (0..loaded_enum.names.len) |field_index| {
3851                try wip_nav.enumConstValue(loaded_enum, .{
3852                    .sdata = .signed_enum_field,
3853                    .udata = .unsigned_enum_field,
3854                    .block = .big_enum_field,
3855                }, field_index);
3856                try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
3857            }
3858            if (loaded_enum.names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3859        },
3860        .func_type => |func_type| {
3861            const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
3862            try wip_nav.abbrevCode(if (is_nullary) .nullary_func_type else .func_type);
3863            try wip_nav.strp(name);
3864            const cc: DW.CC = cc: {
3865                if (zcu.getTarget().cCallingConvention()) |cc| {
3866                    if (@as(std.builtin.CallingConvention.Tag, cc) == func_type.cc) {
3867                        break :cc .normal;
3868                    }
3869                }
3870                // For better or worse, we try to match what Clang emits.
3871                break :cc switch (func_type.cc) {
3872                    .@"inline" => .nocall,
3873                    .async, .auto, .naked => .normal,
3874                    .x86_64_sysv => .LLVM_X86_64SysV,
3875                    .x86_64_win => .LLVM_Win64,
3876                    .x86_64_regcall_v3_sysv => .LLVM_X86RegCall,
3877                    .x86_64_regcall_v4_win => .LLVM_X86RegCall,
3878                    .x86_64_vectorcall => .LLVM_vectorcall,
3879                    .x86_sysv => .normal,
3880                    .x86_win => .normal,
3881                    .x86_stdcall => .BORLAND_stdcall,
3882                    .x86_fastcall => .BORLAND_msfastcall,
3883                    .x86_thiscall => .BORLAND_thiscall,
3884                    .x86_thiscall_mingw => .BORLAND_thiscall,
3885                    .x86_regcall_v3 => .LLVM_X86RegCall,
3886                    .x86_regcall_v4_win => .LLVM_X86RegCall,
3887                    .x86_vectorcall => .LLVM_vectorcall,
3888
3889                    .aarch64_aapcs => .normal,
3890                    .aarch64_aapcs_darwin => .normal,
3891                    .aarch64_aapcs_win => .normal,
3892                    .aarch64_vfabi => .LLVM_AAPCS,
3893                    .aarch64_vfabi_sve => .LLVM_AAPCS,
3894
3895                    .arm_aapcs => .LLVM_AAPCS,
3896                    .arm_aapcs_vfp => .LLVM_AAPCS_VFP,
3897
3898                    .riscv64_lp64_v,
3899                    .riscv32_ilp32_v,
3900                    => .LLVM_RISCVVectorCall,
3901
3902                    .m68k_rtd => .LLVM_M68kRTD,
3903
3904                    .sh_renesas => .GNU_renesas_sh,
3905
3906                    .amdgcn_kernel => .LLVM_OpenCLKernel,
3907                    .nvptx_kernel,
3908                    .spirv_kernel,
3909                    => .nocall,
3910
3911                    .x86_64_interrupt,
3912                    .x86_interrupt,
3913                    .arm_interrupt,
3914                    .mips64_interrupt,
3915                    .mips_interrupt,
3916                    .riscv64_interrupt,
3917                    .riscv32_interrupt,
3918                    .sh_interrupt,
3919                    .arc_interrupt,
3920                    .avr_builtin,
3921                    .avr_signal,
3922                    .avr_interrupt,
3923                    .csky_interrupt,
3924                    .m68k_interrupt,
3925                    .microblaze_interrupt,
3926                    .msp430_interrupt,
3927                    => .normal,
3928
3929                    else => .nocall,
3930                };
3931            };
3932            try diw.writeByte(@intFromEnum(cc));
3933            try wip_nav.refType(.fromInterned(func_type.return_type));
3934            if (!is_nullary) {
3935                for (0..func_type.param_types.len) |param_index| {
3936                    try wip_nav.abbrevCode(.func_type_param);
3937                    try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
3938                }
3939                if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
3940                try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3941            }
3942        },
3943        .error_set_type => |error_set_type| {
3944            try wip_nav.abbrevCode(if (error_set_type.names.len == 0) .generated_empty_enum_type else .generated_enum_type);
3945            try wip_nav.strp(name);
3946            try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
3947                .signedness = .unsigned,
3948                .bits = zcu.errorSetBits(),
3949            } })));
3950            for (0..error_set_type.names.len) |field_index| {
3951                const field_name = error_set_type.names.get(ip)[field_index];
3952                try wip_nav.abbrevCode(.unsigned_enum_field);
3953                try diw.writeUleb128(ip.getErrorValueIfExists(field_name).?);
3954                try wip_nav.strp(field_name.toSlice(ip));
3955            }
3956            if (error_set_type.names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3957        },
3958        .inferred_error_set_type => |func| {
3959            try wip_nav.abbrevCode(.inferred_error_set_type);
3960            try wip_nav.strp(name);
3961            try wip_nav.refType(.fromInterned(switch (ip.funcIesResolvedUnordered(func)) {
3962                .none => .anyerror_type,
3963                else => |ies| ies,
3964            }));
3965        },
3966
3967        // values, not types
3968        .simple_value,
3969        .variable,
3970        .@"extern",
3971        .func,
3972        .int,
3973        .err,
3974        .error_union,
3975        .enum_literal,
3976        .enum_tag,
3977        .empty_enum_value,
3978        .float,
3979        .ptr,
3980        .slice,
3981        .opt,
3982        .aggregate,
3983        .un,
3984        // memoization, not types
3985        .memoized_call,
3986        => unreachable,
3987    }
3988    try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
3989}
3990
3991fn updateLazyValue(
3992    dwarf: *Dwarf,
3993    pt: Zcu.PerThread,
3994    src_loc: Zcu.LazySrcLoc,
3995    value_index: InternPool.Index,
3996    pending_lazy: *WipNav.PendingLazy,
3997) (UpdateError || Writer.Error)!void {
3998    const zcu = pt.zcu;
3999    const ip = &zcu.intern_pool;
4000    assert(ip.typeOf(value_index) != .type_type);
4001    log.debug("updateLazyValue(@as({f}, {f}))", .{
4002        Value.fromInterned(value_index).typeOf(zcu).fmt(pt),
4003        Value.fromInterned(value_index).fmtValue(pt),
4004    });
4005    var wip_nav: WipNav = .{
4006        .dwarf = dwarf,
4007        .pt = pt,
4008        .unit = .main,
4009        .entry = dwarf.values.get(value_index).?,
4010        .any_children = false,
4011        .func = .none,
4012        .func_sym_index = undefined,
4013        .func_high_pc = undefined,
4014        .blocks = undefined,
4015        .cfi = undefined,
4016        .debug_frame = .init(dwarf.gpa),
4017        .debug_info = .init(dwarf.gpa),
4018        .debug_line = .init(dwarf.gpa),
4019        .debug_loclists = .init(dwarf.gpa),
4020        .pending_lazy = pending_lazy.*,
4021    };
4022    defer {
4023        pending_lazy.* = wip_nav.pending_lazy;
4024        wip_nav.pending_lazy = .empty;
4025        wip_nav.deinit();
4026    }
4027    const diw = &wip_nav.debug_info.writer;
4028    var big_int_space: Value.BigIntSpace = undefined;
4029    switch (ip.indexToKey(value_index)) {
4030        .int_type,
4031        .ptr_type,
4032        .array_type,
4033        .vector_type,
4034        .opt_type,
4035        .anyframe_type,
4036        .error_union_type,
4037        .simple_type,
4038        .struct_type,
4039        .tuple_type,
4040        .union_type,
4041        .opaque_type,
4042        .enum_type,
4043        .func_type,
4044        .error_set_type,
4045        .inferred_error_set_type,
4046        => unreachable, // already handled
4047        .undef => |ty| {
4048            try wip_nav.abbrevCode(.undefined_comptime_value);
4049            try wip_nav.refType(.fromInterned(ty));
4050        },
4051        .simple_value => unreachable, // opv state
4052        .variable, .@"extern" => unreachable, // not a value
4053        .func => unreachable, // already handled
4054        .int => |int| {
4055            try wip_nav.bigIntConstValue(.{
4056                .sdata = .sdata_comptime_value,
4057                .udata = .udata_comptime_value,
4058                .block = .block_comptime_value,
4059            }, .fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu));
4060            try wip_nav.refType(.fromInterned(int.ty));
4061        },
4062        .err => |err| {
4063            try wip_nav.abbrevCode(.udata_comptime_value);
4064            try wip_nav.refType(.fromInterned(err.ty));
4065            try diw.writeUleb128(try pt.getErrorValue(err.name));
4066        },
4067        .error_union => |error_union| {
4068            try wip_nav.abbrevCode(.aggregate_comptime_value);
4069            try wip_nav.refType(.fromInterned(error_union.ty));
4070            var err_buf: [4]u8 = undefined;
4071            const err_bytes = err_buf[0 .. std.math.divCeil(u17, zcu.errorSetBits(), 8) catch unreachable];
4072            dwarf.writeInt(err_bytes, switch (error_union.val) {
4073                .err_name => |err_name| try pt.getErrorValue(err_name),
4074                .payload => 0,
4075            });
4076            {
4077                try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
4078                try wip_nav.strp("is_error");
4079                try diw.writeUleb128(err_bytes.len);
4080                try diw.writeAll(err_bytes);
4081            }
4082            payload_field: switch (error_union.val) {
4083                .err_name => {},
4084                .payload => |payload_val| {
4085                    const payload_type: Type = .fromInterned(ip.typeOf(payload_val));
4086                    const has_runtime_bits = payload_type.hasRuntimeBits(zcu);
4087                    const has_comptime_state = payload_type.comptimeOnly(zcu) and try payload_type.onePossibleValue(pt) == null;
4088                    try wip_nav.abbrevCode(if (has_comptime_state)
4089                        .comptime_value_field_comptime_state
4090                    else if (has_runtime_bits)
4091                        .comptime_value_field_runtime_bits
4092                    else
4093                        break :payload_field);
4094                    try wip_nav.strp("value");
4095                    if (has_comptime_state)
4096                        try wip_nav.refValue(.fromInterned(payload_val))
4097                    else
4098                        try wip_nav.blockValue(src_loc, .fromInterned(payload_val));
4099                },
4100            }
4101            {
4102                try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
4103                try wip_nav.strp("error");
4104                try diw.writeUleb128(err_bytes.len);
4105                try diw.writeAll(err_bytes);
4106            }
4107            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4108        },
4109        .enum_literal => |enum_literal| {
4110            try wip_nav.abbrevCode(.string_comptime_value);
4111            try wip_nav.strp(enum_literal.toSlice(ip));
4112            try wip_nav.refType(.enum_literal);
4113        },
4114        .enum_tag => |enum_tag| {
4115            const int = ip.indexToKey(enum_tag.int).int;
4116            try wip_nav.bigIntConstValue(.{
4117                .sdata = .sdata_comptime_value,
4118                .udata = .udata_comptime_value,
4119                .block = .block_comptime_value,
4120            }, .fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu));
4121            try wip_nav.refType(.fromInterned(enum_tag.ty));
4122        },
4123        .empty_enum_value => unreachable,
4124        .float => |float| {
4125            switch (float.storage) {
4126                .f16 => |f16_val| {
4127                    try wip_nav.abbrevCode(.data2_comptime_value);
4128                    try diw.writeInt(u16, @bitCast(f16_val), dwarf.endian);
4129                },
4130                .f32 => |f32_val| {
4131                    try wip_nav.abbrevCode(.data4_comptime_value);
4132                    try diw.writeInt(u32, @bitCast(f32_val), dwarf.endian);
4133                },
4134                .f64 => |f64_val| {
4135                    try wip_nav.abbrevCode(.data8_comptime_value);
4136                    try diw.writeInt(u64, @bitCast(f64_val), dwarf.endian);
4137                },
4138                .f80 => |f80_val| {
4139                    try wip_nav.abbrevCode(.block_comptime_value);
4140                    try diw.writeUleb128(@divExact(80, 8));
4141                    try diw.writeInt(u80, @bitCast(f80_val), dwarf.endian);
4142                },
4143                .f128 => |f128_val| {
4144                    try wip_nav.abbrevCode(.data16_comptime_value);
4145                    try diw.writeInt(u128, @bitCast(f128_val), dwarf.endian);
4146                },
4147            }
4148            try wip_nav.refType(.fromInterned(float.ty));
4149        },
4150        .ptr => |ptr| {
4151            location: {
4152                var base_addr = ptr.base_addr;
4153                var byte_offset = ptr.byte_offset;
4154                const base_unit, const base_entry = while (true) {
4155                    const base_ptr = base_ptr: switch (base_addr) {
4156                        .nav => |nav_index| break try wip_nav.getNavEntry(nav_index),
4157                        .comptime_alloc, .comptime_field => unreachable,
4158                        .uav => |uav| {
4159                            const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));
4160                            if (try uav_ty.onePossibleValue(pt)) |_| {
4161                                try wip_nav.abbrevCode(.udata_comptime_value);
4162                                try diw.writeUleb128(ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment.toByteUnits() orelse
4163                                    uav_ty.abiAlignment(zcu).toByteUnits().?);
4164                                break :location;
4165                            } else break try wip_nav.getValueEntry(.fromInterned(uav.val));
4166                        },
4167                        .int => {
4168                            try wip_nav.abbrevCode(.udata_comptime_value);
4169                            try diw.writeUleb128(byte_offset);
4170                            break :location;
4171                        },
4172                        .eu_payload => |eu_ptr| {
4173                            const base_ptr = ip.indexToKey(eu_ptr).ptr;
4174                            byte_offset += codegen.errUnionPayloadOffset(.fromInterned(ip.indexToKey(
4175                                ip.indexToKey(base_ptr.ty).ptr_type.child,
4176                            ).error_union_type.payload_type), zcu);
4177                            break :base_ptr base_ptr;
4178                        },
4179                        .opt_payload => |opt_ptr| ip.indexToKey(opt_ptr).ptr,
4180                        .field => unreachable,
4181                        .arr_elem => unreachable,
4182                    };
4183                    base_addr = base_ptr.base_addr;
4184                    byte_offset += base_ptr.byte_offset;
4185                };
4186                try wip_nav.abbrevCode(.location_comptime_value);
4187                try wip_nav.infoExprLoc(.{ .implicit_pointer = .{
4188                    .unit = base_unit,
4189                    .entry = base_entry,
4190                    .offset = byte_offset,
4191                } });
4192            }
4193            try wip_nav.refType(.fromInterned(ptr.ty));
4194        },
4195        .slice => |slice| {
4196            try wip_nav.abbrevCode(.aggregate_comptime_value);
4197            try wip_nav.refType(.fromInterned(slice.ty));
4198            {
4199                try wip_nav.abbrevCode(.comptime_value_field_comptime_state);
4200                try wip_nav.strp("ptr");
4201                try wip_nav.refValue(.fromInterned(slice.ptr));
4202            }
4203            {
4204                try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
4205                try wip_nav.strp("len");
4206                try wip_nav.blockValue(src_loc, .fromInterned(slice.len));
4207            }
4208            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4209        },
4210        .opt => |opt| {
4211            const opt_child_type: Type = .fromInterned(ip.indexToKey(opt.ty).opt_type);
4212            try wip_nav.abbrevCode(.aggregate_comptime_value);
4213            try wip_nav.refType(.fromInterned(opt.ty));
4214            {
4215                try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
4216                try wip_nav.strp("has_value");
4217                switch (optRepr(opt_child_type, zcu)) {
4218                    .opv_null => try diw.writeUleb128(0),
4219                    .unpacked => try wip_nav.blockValue(src_loc, .makeBool(opt.val != .none)),
4220                    .error_set => try wip_nav.blockValue(src_loc, .fromInterned(value_index)),
4221                    .pointer => if (opt_child_type.comptimeOnly(zcu)) {
4222                        var buf: [8]u8 = undefined;
4223                        const bytes = buf[0..@divExact(zcu.getTarget().ptrBitWidth(), 8)];
4224                        dwarf.writeInt(bytes, switch (opt.val) {
4225                            .none => 0,
4226                            else => opt_child_type.ptrAlignment(zcu).toByteUnits().?,
4227                        });
4228                        try diw.writeUleb128(bytes.len);
4229                        try diw.writeAll(bytes);
4230                    } else try wip_nav.blockValue(src_loc, .fromInterned(value_index)),
4231                }
4232            }
4233            if (opt.val != .none) child_field: {
4234                const has_runtime_bits = opt_child_type.hasRuntimeBits(zcu);
4235                const has_comptime_state = opt_child_type.comptimeOnly(zcu) and try opt_child_type.onePossibleValue(pt) == null;
4236                try wip_nav.abbrevCode(if (has_comptime_state)
4237                    .comptime_value_field_comptime_state
4238                else if (has_runtime_bits)
4239                    .comptime_value_field_runtime_bits
4240                else
4241                    break :child_field);
4242                try wip_nav.strp("?");
4243                if (has_comptime_state)
4244                    try wip_nav.refValue(.fromInterned(opt.val))
4245                else
4246                    try wip_nav.blockValue(src_loc, .fromInterned(opt.val));
4247            }
4248            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4249        },
4250        .aggregate => |aggregate| {
4251            try wip_nav.abbrevCode(.aggregate_comptime_value);
4252            try wip_nav.refType(.fromInterned(aggregate.ty));
4253            switch (ip.indexToKey(aggregate.ty)) {
4254                .struct_type => {
4255                    const loaded_struct_type = ip.loadStructType(aggregate.ty);
4256                    assert(loaded_struct_type.layout == .auto);
4257                    for (0..loaded_struct_type.field_types.len) |field_index| {
4258                        if (loaded_struct_type.fieldIsComptime(ip, field_index)) continue;
4259                        const field_type: Type = .fromInterned(loaded_struct_type.field_types.get(ip)[field_index]);
4260                        const has_runtime_bits = field_type.hasRuntimeBits(zcu);
4261                        const has_comptime_state = field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null;
4262                        try wip_nav.abbrevCode(if (has_comptime_state)
4263                            .comptime_value_field_comptime_state
4264                        else if (has_runtime_bits)
4265                            .comptime_value_field_runtime_bits
4266                        else
4267                            continue);
4268                        try wip_nav.strp(loaded_struct_type.fieldName(ip, field_index).toSlice(ip));
4269                        const field_value: Value = .fromInterned(switch (aggregate.storage) {
4270                            .bytes => unreachable,
4271                            .elems => |elems| elems[field_index],
4272                            .repeated_elem => |repeated_elem| repeated_elem,
4273                        });
4274                        if (has_comptime_state)
4275                            try wip_nav.refValue(field_value)
4276                        else
4277                            try wip_nav.blockValue(src_loc, field_value);
4278                    }
4279                },
4280                .tuple_type => |tuple_type| for (0..tuple_type.types.len) |field_index| {
4281                    if (tuple_type.values.get(ip)[field_index] != .none) continue;
4282                    const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);
4283                    const has_runtime_bits = field_type.hasRuntimeBits(zcu);
4284                    const has_comptime_state = field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null;
4285                    try wip_nav.abbrevCode(if (has_comptime_state)
4286                        .comptime_value_field_comptime_state
4287                    else if (has_runtime_bits)
4288                        .comptime_value_field_runtime_bits
4289                    else
4290                        continue);
4291                    {
4292                        var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined;
4293                        const field_name = std.fmt.bufPrint(&field_name_buf, "{d}", .{field_index}) catch unreachable;
4294                        try wip_nav.strp(field_name);
4295                    }
4296                    const field_value: Value = .fromInterned(switch (aggregate.storage) {
4297                        .bytes => unreachable,
4298                        .elems => |elems| elems[field_index],
4299                        .repeated_elem => |repeated_elem| repeated_elem,
4300                    });
4301                    if (has_comptime_state)
4302                        try wip_nav.refValue(field_value)
4303                    else
4304                        try wip_nav.blockValue(src_loc, field_value);
4305                },
4306                inline .array_type, .vector_type => |sequence_type| {
4307                    const child_type: Type = .fromInterned(sequence_type.child);
4308                    const has_runtime_bits = child_type.hasRuntimeBits(zcu);
4309                    const has_comptime_state = child_type.comptimeOnly(zcu) and try child_type.onePossibleValue(pt) == null;
4310                    for (switch (aggregate.storage) {
4311                        .bytes => unreachable,
4312                        .elems => |elems| elems,
4313                        .repeated_elem => |*repeated_elem| repeated_elem[0..1],
4314                    }) |elem| {
4315                        try wip_nav.abbrevCode(if (has_comptime_state)
4316                            .comptime_value_elem_comptime_state
4317                        else if (has_runtime_bits)
4318                            .comptime_value_elem_runtime_bits
4319                        else
4320                            break);
4321                        if (has_comptime_state)
4322                            try wip_nav.refValue(.fromInterned(elem))
4323                        else
4324                            try wip_nav.blockValue(src_loc, .fromInterned(elem));
4325                    }
4326                },
4327                else => unreachable,
4328            }
4329            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4330        },
4331        .un => |un| {
4332            try wip_nav.abbrevCode(.aggregate_comptime_value);
4333            try wip_nav.refType(.fromInterned(un.ty));
4334            field: {
4335                const loaded_union_type = ip.loadUnionType(un.ty);
4336                assert(loaded_union_type.flagsUnordered(ip).layout == .auto);
4337                const field_index = zcu.unionTagFieldIndex(loaded_union_type, Value.fromInterned(un.tag)).?;
4338                const field_ty: Type = .fromInterned(loaded_union_type.field_types.get(ip)[field_index]);
4339                const field_name = loaded_union_type.loadTagType(ip).names.get(ip)[field_index];
4340                const has_runtime_bits = field_ty.hasRuntimeBits(zcu);
4341                const has_comptime_state = field_ty.comptimeOnly(zcu) and try field_ty.onePossibleValue(pt) == null;
4342                try wip_nav.abbrevCode(if (has_comptime_state)
4343                    .comptime_value_field_comptime_state
4344                else if (has_runtime_bits)
4345                    .comptime_value_field_runtime_bits
4346                else
4347                    break :field);
4348                try wip_nav.strp(field_name.toSlice(ip));
4349                if (has_comptime_state)
4350                    try wip_nav.refValue(.fromInterned(un.val))
4351                else
4352                    try wip_nav.blockValue(src_loc, .fromInterned(un.val));
4353            }
4354            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4355        },
4356        .memoized_call => unreachable, // not a value
4357    }
4358    try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
4359}
4360
4361fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum {
4362    unpacked,
4363    opv_null,
4364    error_set,
4365    pointer,
4366} {
4367    if (opt_child_type.isNoReturn(zcu)) return .opv_null;
4368    return switch (opt_child_type.toIntern()) {
4369        .anyerror_type => .error_set,
4370        else => switch (zcu.intern_pool.indexToKey(opt_child_type.toIntern())) {
4371            else => .unpacked,
4372            .error_set_type, .inferred_error_set_type => .error_set,
4373            .ptr_type => |ptr_type| if (ptr_type.flags.is_allowzero) .unpacked else .pointer,
4374        },
4375    };
4376}
4377
4378pub fn updateContainerType(
4379    dwarf: *Dwarf,
4380    pt: Zcu.PerThread,
4381    type_index: InternPool.Index,
4382) UpdateError!void {
4383    return dwarf.updateContainerTypeWriterError(pt, type_index) catch |err| switch (err) {
4384        error.WriteFailed => error.OutOfMemory,
4385        else => |e| e,
4386    };
4387}
4388fn updateContainerTypeWriterError(
4389    dwarf: *Dwarf,
4390    pt: Zcu.PerThread,
4391    type_index: InternPool.Index,
4392) (UpdateError || Writer.Error)!void {
4393    const zcu = pt.zcu;
4394    const ip = &zcu.intern_pool;
4395    const ty: Type = .fromInterned(type_index);
4396    const ty_src_loc = ty.srcLoc(zcu);
4397    log.debug("updateContainerType({f})", .{ty.fmt(pt)});
4398
4399    const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip).?;
4400    const file = zcu.fileByIndex(inst_info.file);
4401    const unit = try dwarf.getUnit(file.mod.?);
4402    const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
4403    if (inst_info.inst == .main_struct_inst) {
4404        const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
4405        if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
4406        var wip_nav: WipNav = .{
4407            .dwarf = dwarf,
4408            .pt = pt,
4409            .unit = unit,
4410            .entry = type_gop.value_ptr.*,
4411            .any_children = false,
4412            .func = .none,
4413            .func_sym_index = undefined,
4414            .func_high_pc = undefined,
4415            .blocks = undefined,
4416            .cfi = undefined,
4417            .debug_frame = .init(dwarf.gpa),
4418            .debug_info = .init(dwarf.gpa),
4419            .debug_line = .init(dwarf.gpa),
4420            .debug_loclists = .init(dwarf.gpa),
4421            .pending_lazy = .empty,
4422        };
4423        defer wip_nav.deinit();
4424
4425        const loaded_struct = ip.loadStructType(type_index);
4426
4427        const diw = &wip_nav.debug_info.writer;
4428        try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .empty_file else .file);
4429        try diw.writeUleb128(file_gop.index);
4430        try wip_nav.strp(loaded_struct.name.toSlice(ip));
4431        if (loaded_struct.field_types.len > 0) {
4432            try diw.writeUleb128(ty.abiSize(zcu));
4433            try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
4434            for (0..loaded_struct.field_types.len) |field_index| {
4435                const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
4436                const field_init = loaded_struct.fieldInit(ip, field_index);
4437                assert(!(is_comptime and field_init == .none));
4438                const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
4439                const has_runtime_bits, const has_comptime_state = switch (field_init) {
4440                    .none => .{ false, false },
4441                    else => .{
4442                        field_type.hasRuntimeBits(zcu),
4443                        field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,
4444                    },
4445                };
4446                try wip_nav.abbrevCode(if (is_comptime)
4447                    if (has_comptime_state)
4448                        .struct_field_comptime_comptime_state
4449                    else if (has_runtime_bits)
4450                        .struct_field_comptime_runtime_bits
4451                    else
4452                        .struct_field_comptime
4453                else if (field_init != .none)
4454                    if (has_comptime_state)
4455                        .struct_field_default_comptime_state
4456                    else if (has_runtime_bits)
4457                        .struct_field_default_runtime_bits
4458                    else
4459                        .struct_field
4460                else
4461                    .struct_field);
4462                try wip_nav.strp(loaded_struct.fieldName(ip, field_index).toSlice(ip));
4463                try wip_nav.refType(field_type);
4464                if (!is_comptime) {
4465                    try diw.writeUleb128(loaded_struct.offsets.get(ip)[field_index]);
4466                    try diw.writeUleb128(loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
4467                        field_type.abiAlignment(zcu).toByteUnits().?);
4468                }
4469                if (has_comptime_state)
4470                    try wip_nav.refValue(.fromInterned(field_init))
4471                else if (has_runtime_bits)
4472                    try wip_nav.blockValue(ty_src_loc, .fromInterned(field_init));
4473            }
4474            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4475        }
4476
4477        try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
4478        try wip_nav.updateLazy(ty_src_loc);
4479    } else {
4480        {
4481            // Note that changes to ZIR instruction tracking only need to update this code
4482            // if a newly-tracked instruction can be a type's owner `zir_index`.
4483            comptime assert(Zir.inst_tracking_version == 0);
4484
4485            const decl_inst = file.zir.?.instructions.get(@intFromEnum(inst_info.inst));
4486            const name_strat: Zir.Inst.NameStrategy = switch (decl_inst.tag) {
4487                .struct_init, .struct_init_ref, .struct_init_anon => .anon,
4488                .extended => switch (decl_inst.data.extended.opcode) {
4489                    .struct_decl => @as(Zir.Inst.StructDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
4490                    .enum_decl => @as(Zir.Inst.EnumDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
4491                    .union_decl => @as(Zir.Inst.UnionDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
4492                    .opaque_decl => @as(Zir.Inst.OpaqueDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
4493
4494                    .reify_enum,
4495                    .reify_struct,
4496                    .reify_union,
4497                    => @enumFromInt(decl_inst.data.extended.small),
4498
4499                    else => unreachable,
4500                },
4501                else => unreachable,
4502            };
4503            if (name_strat == .parent) return;
4504        }
4505
4506        const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
4507        if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
4508        var wip_nav: WipNav = .{
4509            .dwarf = dwarf,
4510            .pt = pt,
4511            .unit = unit,
4512            .entry = type_gop.value_ptr.*,
4513            .any_children = false,
4514            .func = .none,
4515            .func_sym_index = undefined,
4516            .func_high_pc = undefined,
4517            .blocks = undefined,
4518            .cfi = undefined,
4519            .debug_frame = .init(dwarf.gpa),
4520            .debug_info = .init(dwarf.gpa),
4521            .debug_line = .init(dwarf.gpa),
4522            .debug_loclists = .init(dwarf.gpa),
4523            .pending_lazy = .empty,
4524        };
4525        defer wip_nav.deinit();
4526        const diw = &wip_nav.debug_info.writer;
4527        const name = try std.fmt.allocPrint(dwarf.gpa, "{f}", .{ty.fmt(pt)});
4528        defer dwarf.gpa.free(name);
4529
4530        switch (ip.indexToKey(type_index)) {
4531            .struct_type => {
4532                const loaded_struct = ip.loadStructType(type_index);
4533                switch (loaded_struct.layout) {
4534                    .auto, .@"extern" => {
4535                        try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .empty_struct_type else .struct_type);
4536                        try diw.writeUleb128(file_gop.index);
4537                        try wip_nav.strp(name);
4538                        if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
4539                            try diw.writeUleb128(ty.abiSize(zcu));
4540                            try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
4541                            for (0..loaded_struct.field_types.len) |field_index| {
4542                                const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
4543                                const field_init = loaded_struct.fieldInit(ip, field_index);
4544                                assert(!(is_comptime and field_init == .none));
4545                                const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
4546                                const has_runtime_bits, const has_comptime_state = switch (field_init) {
4547                                    .none => .{ false, false },
4548                                    else => .{
4549                                        field_type.hasRuntimeBits(zcu),
4550                                        field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,
4551                                    },
4552                                };
4553                                try wip_nav.abbrevCode(if (is_comptime)
4554                                    if (has_comptime_state)
4555                                        .struct_field_comptime_comptime_state
4556                                    else if (has_runtime_bits)
4557                                        .struct_field_comptime_runtime_bits
4558                                    else
4559                                        .struct_field_comptime
4560                                else if (field_init != .none)
4561                                    if (has_comptime_state)
4562                                        .struct_field_default_comptime_state
4563                                    else if (has_runtime_bits)
4564                                        .struct_field_default_runtime_bits
4565                                    else
4566                                        .struct_field
4567                                else
4568                                    .struct_field);
4569                                try wip_nav.strp(loaded_struct.fieldName(ip, field_index).toSlice(ip));
4570                                try wip_nav.refType(field_type);
4571                                if (!is_comptime) {
4572                                    try diw.writeUleb128(loaded_struct.offsets.get(ip)[field_index]);
4573                                    try diw.writeUleb128(loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
4574                                        field_type.abiAlignment(zcu).toByteUnits().?);
4575                                }
4576                                if (has_comptime_state)
4577                                    try wip_nav.refValue(.fromInterned(field_init))
4578                                else if (has_runtime_bits)
4579                                    try wip_nav.blockValue(ty_src_loc, .fromInterned(field_init));
4580                            }
4581                            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4582                        }
4583                    },
4584                    .@"packed" => {
4585                        try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type);
4586                        try diw.writeUleb128(file_gop.index);
4587                        try wip_nav.strp(name);
4588                        try wip_nav.refType(.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
4589                        var field_bit_offset: u16 = 0;
4590                        for (0..loaded_struct.field_types.len) |field_index| {
4591                            try wip_nav.abbrevCode(.packed_struct_field);
4592                            try wip_nav.strp(loaded_struct.fieldName(ip, field_index).toSlice(ip));
4593                            const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
4594                            try wip_nav.refType(field_type);
4595                            try diw.writeUleb128(field_bit_offset);
4596                            field_bit_offset += @intCast(field_type.bitSize(zcu));
4597                        }
4598                        if (loaded_struct.field_types.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4599                    },
4600                }
4601            },
4602            .enum_type => {
4603                const loaded_enum = ip.loadEnumType(type_index);
4604                try wip_nav.abbrevCode(if (loaded_enum.names.len > 0) .enum_type else .empty_enum_type);
4605                try diw.writeUleb128(file_gop.index);
4606                try wip_nav.strp(name);
4607                try wip_nav.refType(.fromInterned(loaded_enum.tag_ty));
4608                for (0..loaded_enum.names.len) |field_index| {
4609                    try wip_nav.enumConstValue(loaded_enum, .{
4610                        .sdata = .signed_enum_field,
4611                        .udata = .unsigned_enum_field,
4612                        .block = .big_enum_field,
4613                    }, field_index);
4614                    try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
4615                }
4616                if (loaded_enum.names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4617            },
4618            .union_type => {
4619                const loaded_union = ip.loadUnionType(type_index);
4620                try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);
4621                try diw.writeUleb128(file_gop.index);
4622                try wip_nav.strp(name);
4623                const union_layout = Type.getUnionLayout(loaded_union, zcu);
4624                try diw.writeUleb128(union_layout.abi_size);
4625                try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
4626                const loaded_tag = loaded_union.loadTagType(ip);
4627                if (loaded_union.hasTag(ip)) {
4628                    try wip_nav.abbrevCode(.tagged_union);
4629                    try wip_nav.infoSectionOffset(
4630                        .debug_info,
4631                        wip_nav.unit,
4632                        wip_nav.entry,
4633                        @intCast(diw.end + dwarf.sectionOffsetBytes()),
4634                    );
4635                    {
4636                        try wip_nav.abbrevCode(.generated_field);
4637                        try wip_nav.strp("tag");
4638                        try wip_nav.refType(.fromInterned(loaded_union.enum_tag_ty));
4639                        try diw.writeUleb128(union_layout.tagOffset());
4640
4641                        for (0..loaded_union.field_types.len) |field_index| {
4642                            try wip_nav.enumConstValue(loaded_tag, .{
4643                                .sdata = .signed_tagged_union_field,
4644                                .udata = .unsigned_tagged_union_field,
4645                                .block = .big_tagged_union_field,
4646                            }, field_index);
4647                            {
4648                                try wip_nav.abbrevCode(.struct_field);
4649                                try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
4650                                const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
4651                                try wip_nav.refType(field_type);
4652                                try diw.writeUleb128(union_layout.payloadOffset());
4653                                try diw.writeUleb128(loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
4654                                    if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
4655                            }
4656                            try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4657                        }
4658                    }
4659                    try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4660                } else for (0..loaded_union.field_types.len) |field_index| {
4661                    try wip_nav.abbrevCode(.untagged_union_field);
4662                    try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
4663                    const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
4664                    try wip_nav.refType(field_type);
4665                    try diw.writeUleb128(loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
4666                        if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
4667                }
4668                if (loaded_union.field_types.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4669            },
4670            .opaque_type => {
4671                try wip_nav.abbrevCode(.empty_struct_type);
4672                try diw.writeUleb128(file_gop.index);
4673                try wip_nav.strp(name);
4674                try diw.writeByte(@intFromBool(true));
4675            },
4676            else => unreachable,
4677        }
4678        try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
4679        try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written());
4680        try wip_nav.updateLazy(ty_src_loc);
4681    }
4682}
4683
4684pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedInst.Index) UpdateError!void {
4685    const ip = &zcu.intern_pool;
4686
4687    const inst_info = zir_index.resolveFull(ip).?;
4688    assert(inst_info.inst != .main_struct_inst);
4689    const file = zcu.fileByIndex(inst_info.file);
4690    const decl = file.zir.?.getDeclaration(inst_info.inst);
4691    log.debug("updateLineNumber({s}:{d}:{d} %{d} = {s})", .{
4692        file.sub_file_path,
4693        decl.src_line + 1,
4694        decl.src_column + 1,
4695        @intFromEnum(inst_info.inst),
4696        file.zir.?.nullTerminatedString(decl.name),
4697    });
4698
4699    var line_buf: [4]u8 = undefined;
4700    std.mem.writeInt(u32, &line_buf, decl.src_line + 1, dwarf.endian);
4701
4702    const unit = dwarf.debug_info.section.getUnit(dwarf.getUnitIfExists(file.mod.?) orelse return);
4703    const entry = unit.getEntry(dwarf.decls.get(zir_index) orelse return);
4704    try dwarf.getFile().?.pwriteAll(&line_buf, dwarf.debug_info.section.off(dwarf) + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf));
4705}
4706
4707pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void {
4708    _ = dwarf;
4709    _ = nav_index;
4710}
4711
4712fn refAbbrevCode(
4713    dwarf: *Dwarf,
4714    abbrev_code: AbbrevCode,
4715) (UpdateError || Writer.Error)!@typeInfo(AbbrevCode).@"enum".tag_type {
4716    assert(abbrev_code != .null);
4717    const entry: Entry.Index = @enumFromInt(@intFromEnum(abbrev_code));
4718    if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @intFromEnum(abbrev_code);
4719    var debug_abbrev_aw: Writer.Allocating = .init(dwarf.gpa);
4720    defer debug_abbrev_aw.deinit();
4721    const daw = &debug_abbrev_aw.writer;
4722    const abbrev = AbbrevCode.abbrevs.get(abbrev_code);
4723    try daw.writeUleb128(@intFromEnum(abbrev_code));
4724    try daw.writeUleb128(@intFromEnum(abbrev.tag));
4725    try daw.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no);
4726    for (abbrev.attrs) |*attr| inline for (attr) |info| try daw.writeUleb128(@intFromEnum(info));
4727    for (0..2) |_| try daw.writeUleb128(0);
4728    try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, entry, dwarf, debug_abbrev_aw.written());
4729    return @intFromEnum(abbrev_code);
4730}
4731
4732pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
4733    return dwarf.flushWriterError(pt) catch |err| switch (err) {
4734        error.WriteFailed => error.OutOfMemory,
4735        else => |e| e,
4736    };
4737}
4738fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (FlushError || Writer.Error)!void {
4739    const zcu = pt.zcu;
4740    const ip = &zcu.intern_pool;
4741
4742    {
4743        const type_gop = try dwarf.types.getOrPut(dwarf.gpa, .anyerror_type);
4744        if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(.main);
4745        var wip_nav: WipNav = .{
4746            .dwarf = dwarf,
4747            .pt = pt,
4748            .unit = .main,
4749            .entry = type_gop.value_ptr.*,
4750            .any_children = false,
4751            .func = .none,
4752            .func_sym_index = undefined,
4753            .func_high_pc = undefined,
4754            .blocks = undefined,
4755            .cfi = undefined,
4756            .debug_frame = .init(dwarf.gpa),
4757            .debug_info = .init(dwarf.gpa),
4758            .debug_line = .init(dwarf.gpa),
4759            .debug_loclists = .init(dwarf.gpa),
4760            .pending_lazy = .empty,
4761        };
4762        defer wip_nav.deinit();
4763        const diw = &wip_nav.debug_info.writer;
4764        const global_error_set_names = ip.global_error_set.getNamesFromMainThread();
4765        try wip_nav.abbrevCode(if (global_error_set_names.len == 0) .generated_empty_enum_type else .generated_enum_type);
4766        try wip_nav.strp("anyerror");
4767        try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
4768            .signedness = .unsigned,
4769            .bits = zcu.errorSetBits(),
4770        } })));
4771        for (global_error_set_names, 1..) |name, value| {
4772            try wip_nav.abbrevCode(.unsigned_enum_field);
4773            try diw.writeUleb128(value);
4774            try wip_nav.strp(name.toSlice(ip));
4775        }
4776        if (global_error_set_names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4777        try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
4778        try wip_nav.updateLazy(.unneeded);
4779    }
4780
4781    for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {
4782        const root_dir_path = try mod.root.toAbsolute(zcu.comp.dirs, dwarf.gpa);
4783        defer dwarf.gpa.free(root_dir_path);
4784        mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);
4785    }
4786
4787    var header_aw: Writer.Allocating = .init(dwarf.gpa);
4788    defer header_aw.deinit();
4789    const hw = &header_aw.writer;
4790    if (dwarf.debug_aranges.section.dirty) {
4791        for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| {
4792            const unit: Unit.Index = @enumFromInt(unit_index);
4793            unit_ptr.clear();
4794            try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 1);
4795            header_aw.clearRetainingCapacity();
4796            try header_aw.ensureTotalCapacity(unit_ptr.header_len);
4797            const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
4798                dwarf.debug_aranges.section.getUnit(next_unit).off
4799            else
4800                dwarf.debug_aranges.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
4801            switch (dwarf.format) {
4802                .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
4803                .@"64" => {
4804                    hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
4805                    hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
4806                },
4807            }
4808            hw.writeInt(u16, 2, dwarf.endian) catch unreachable;
4809            unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4810                .source_off = @intCast(hw.end),
4811                .target_sec = .debug_info,
4812                .target_unit = unit,
4813            });
4814            hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4815            hw.writeByte(@intFromEnum(dwarf.address_size)) catch unreachable;
4816            hw.writeByte(0) catch unreachable;
4817            hw.splatByteAll(0, unit_ptr.header_len - hw.end) catch unreachable;
4818            try unit_ptr.replaceHeader(&dwarf.debug_aranges.section, dwarf, header_aw.written());
4819            try unit_ptr.writeTrailer(&dwarf.debug_aranges.section, dwarf);
4820        }
4821        dwarf.debug_aranges.section.dirty = false;
4822    }
4823    if (dwarf.debug_frame.section.dirty) {
4824        const target = &dwarf.bin_file.comp.root_mod.resolved_target.result;
4825        switch (dwarf.debug_frame.header.format) {
4826            .none => {},
4827            .debug_frame => unreachable,
4828            .eh_frame => switch (target.cpu.arch) {
4829                .x86_64 => {
4830                    dev.check(.x86_64_backend);
4831                    const Register = @import("../codegen/x86_64/bits.zig").Register;
4832                    for (dwarf.debug_frame.section.units.items) |*unit| {
4833                        header_aw.clearRetainingCapacity();
4834                        try header_aw.ensureTotalCapacity(unit.header_len);
4835                        const unit_len = unit.header_len - dwarf.unitLengthBytes();
4836                        switch (dwarf.format) {
4837                            .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
4838                            .@"64" => {
4839                                hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
4840                                hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
4841                            },
4842                        }
4843                        hw.splatByteAll(0, 4) catch unreachable;
4844                        hw.writeByte(1) catch unreachable;
4845                        hw.writeAll("zR\x00") catch unreachable;
4846                        hw.writeUleb128(dwarf.debug_frame.header.code_alignment_factor) catch unreachable;
4847                        hw.writeSleb128(dwarf.debug_frame.header.data_alignment_factor) catch unreachable;
4848                        hw.writeUleb128(dwarf.debug_frame.header.return_address_register) catch unreachable;
4849                        hw.writeUleb128(1) catch unreachable;
4850                        hw.writeByte(@bitCast(@as(DW.EH.PE, .{ .type = .sdata4, .rel = .pcrel }))) catch unreachable;
4851                        hw.writeByte(DW.CFA.def_cfa_sf) catch unreachable;
4852                        hw.writeUleb128(Register.rsp.dwarfNum()) catch unreachable;
4853                        hw.writeSleb128(-1) catch unreachable;
4854                        hw.writeByte(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum()) catch unreachable;
4855                        hw.writeUleb128(1) catch unreachable;
4856                        hw.splatByteAll(DW.CFA.nop, unit.header_len - hw.end) catch unreachable;
4857                        try unit.replaceHeader(&dwarf.debug_frame.section, dwarf, header_aw.written());
4858                        try unit.writeTrailer(&dwarf.debug_frame.section, dwarf);
4859                    }
4860                },
4861                else => unreachable,
4862            },
4863        }
4864        dwarf.debug_frame.section.dirty = false;
4865    }
4866    if (dwarf.debug_info.section.dirty) {
4867        for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| {
4868            const unit: Unit.Index = @enumFromInt(unit_index);
4869            unit_ptr.clear();
4870            try unit_ptr.cross_unit_relocs.ensureTotalCapacity(dwarf.gpa, 1);
4871            try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 7);
4872            header_aw.clearRetainingCapacity();
4873            try header_aw.ensureTotalCapacity(unit_ptr.header_len);
4874            const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
4875                dwarf.debug_info.section.getUnit(next_unit).off
4876            else
4877                dwarf.debug_info.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
4878            switch (dwarf.format) {
4879                .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
4880                .@"64" => {
4881                    hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
4882                    hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
4883                },
4884            }
4885            hw.writeInt(u16, 5, dwarf.endian) catch unreachable;
4886            hw.writeByte(DW.UT.compile) catch unreachable;
4887            hw.writeByte(@intFromEnum(dwarf.address_size)) catch unreachable;
4888            unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4889                .source_off = @intCast(hw.end),
4890                .target_sec = .debug_abbrev,
4891                .target_unit = DebugAbbrev.unit,
4892            });
4893            hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4894            const compile_unit_off: u32 = @intCast(hw.end);
4895            hw.writeUleb128(try dwarf.refAbbrevCode(.compile_unit)) catch unreachable;
4896            hw.writeByte(DW.LANG.Zig) catch unreachable;
4897            unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4898                .source_off = @intCast(hw.end),
4899                .target_sec = .debug_line_str,
4900                .target_unit = StringSection.unit,
4901                .target_entry = (try dwarf.debug_line_str.addString(dwarf, "zig " ++ @import("build_options").version)).toOptional(),
4902            });
4903            hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4904            unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4905                .source_off = @intCast(hw.end),
4906                .target_sec = .debug_line_str,
4907                .target_unit = StringSection.unit,
4908                .target_entry = mod_info.root_dir_path.toOptional(),
4909            });
4910            hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4911            unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4912                .source_off = @intCast(hw.end),
4913                .target_sec = .debug_line_str,
4914                .target_unit = StringSection.unit,
4915                .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod.root_src_path)).toOptional(),
4916            });
4917            hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4918            unit_ptr.cross_unit_relocs.appendAssumeCapacity(.{
4919                .source_off = @intCast(hw.end),
4920                .target_unit = .main,
4921                .target_off = compile_unit_off,
4922            });
4923            hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4924            unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4925                .source_off = @intCast(hw.end),
4926                .target_sec = .debug_line,
4927                .target_unit = unit,
4928            });
4929            hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4930            unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4931                .source_off = @intCast(hw.end),
4932                .target_sec = .debug_rnglists,
4933                .target_unit = unit,
4934                .target_off = DebugRngLists.baseOffset(dwarf),
4935            });
4936            hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4937            hw.writeUleb128(0) catch unreachable;
4938            hw.writeUleb128(try dwarf.refAbbrevCode(.module)) catch unreachable;
4939            unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4940                .source_off = @intCast(hw.end),
4941                .target_sec = .debug_str,
4942                .target_unit = StringSection.unit,
4943                .target_entry = (try dwarf.debug_str.addString(dwarf, mod.fully_qualified_name)).toOptional(),
4944            });
4945            hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4946            hw.writeUleb128(0) catch unreachable;
4947            try unit_ptr.replaceHeader(&dwarf.debug_info.section, dwarf, header_aw.written());
4948            try unit_ptr.writeTrailer(&dwarf.debug_info.section, dwarf);
4949        }
4950        dwarf.debug_info.section.dirty = false;
4951    }
4952    if (dwarf.debug_abbrev.section.dirty) {
4953        assert(!dwarf.debug_info.section.dirty);
4954        try dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).writeTrailer(&dwarf.debug_abbrev.section, dwarf);
4955        dwarf.debug_abbrev.section.dirty = false;
4956    }
4957    if (dwarf.debug_str.section.dirty) {
4958        const contents = dwarf.debug_str.contents.items;
4959        try dwarf.debug_str.section.resize(dwarf, contents.len);
4960        try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_str.section.off(dwarf));
4961        dwarf.debug_str.section.dirty = false;
4962    }
4963    if (dwarf.debug_line.section.dirty) {
4964        for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| try unit.resizeHeader(
4965            &dwarf.debug_line.section,
4966            dwarf,
4967            DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count())),
4968        );
4969        for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| {
4970            unit.clear();
4971            try unit.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, mod_info.dirs.count() + 2 * (mod_info.files.count()));
4972            header_aw.clearRetainingCapacity();
4973            try header_aw.ensureTotalCapacity(unit.header_len);
4974            const unit_len = (if (unit.next.unwrap()) |next_unit|
4975                dwarf.debug_line.section.getUnit(next_unit).off
4976            else
4977                dwarf.debug_line.section.len) - unit.off - dwarf.unitLengthBytes();
4978            switch (dwarf.format) {
4979                .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
4980                .@"64" => {
4981                    hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
4982                    hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
4983                },
4984            }
4985            hw.writeInt(u16, 5, dwarf.endian) catch unreachable;
4986            hw.writeByte(@intFromEnum(dwarf.address_size)) catch unreachable;
4987            hw.writeByte(0) catch unreachable;
4988            switch (dwarf.format) {
4989                .@"32" => hw.writeInt(u32, @intCast(unit.header_len - hw.end - 4), dwarf.endian) catch unreachable,
4990                .@"64" => hw.writeInt(u64, @intCast(unit.header_len - hw.end - 8), dwarf.endian) catch unreachable,
4991            }
4992            const StandardOpcode = DeclValEnum(DW.LNS);
4993            hw.writeAll(&.{
4994                dwarf.debug_line.header.minimum_instruction_length,
4995                dwarf.debug_line.header.maximum_operations_per_instruction,
4996                @intFromBool(dwarf.debug_line.header.default_is_stmt),
4997                @bitCast(dwarf.debug_line.header.line_base),
4998                dwarf.debug_line.header.line_range,
4999                dwarf.debug_line.header.opcode_base,
5000            }) catch unreachable;
5001            hw.writeAll(std.enums.EnumArray(StandardOpcode, u8).init(.{
5002                .extended_op = undefined,
5003                .copy = 0,
5004                .advance_pc = 1,
5005                .advance_line = 1,
5006                .set_file = 1,
5007                .set_column = 1,
5008                .negate_stmt = 0,
5009                .set_basic_block = 0,
5010                .const_add_pc = 0,
5011                .fixed_advance_pc = 1,
5012                .set_prologue_end = 0,
5013                .set_epilogue_begin = 0,
5014                .set_isa = 1,
5015            }).values[1..dwarf.debug_line.header.opcode_base]) catch unreachable;
5016            hw.writeByte(1) catch unreachable;
5017            hw.writeUleb128(DW.LNCT.path) catch unreachable;
5018            hw.writeUleb128(DW.FORM.line_strp) catch unreachable;
5019            hw.writeUleb128(mod_info.dirs.count()) catch unreachable;
5020            for (mod_info.dirs.keys()) |dir_unit| {
5021                unit.cross_section_relocs.appendAssumeCapacity(.{
5022                    .source_off = @intCast(hw.end),
5023                    .target_sec = .debug_line_str,
5024                    .target_unit = StringSection.unit,
5025                    .target_entry = dwarf.getModInfo(dir_unit).root_dir_path.toOptional(),
5026                });
5027                hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
5028            }
5029            const dir_index_info = DebugLine.dirIndexInfo(@intCast(mod_info.dirs.count()));
5030            hw.writeByte(3) catch unreachable;
5031            hw.writeUleb128(DW.LNCT.path) catch unreachable;
5032            hw.writeUleb128(DW.FORM.line_strp) catch unreachable;
5033            hw.writeUleb128(DW.LNCT.directory_index) catch unreachable;
5034            hw.writeUleb128(@intFromEnum(dir_index_info.form)) catch unreachable;
5035            hw.writeUleb128(DW.LNCT.LLVM_source) catch unreachable;
5036            hw.writeUleb128(DW.FORM.line_strp) catch unreachable;
5037            hw.writeUleb128(mod_info.files.count()) catch unreachable;
5038            for (mod_info.files.keys()) |file_index| {
5039                const file = zcu.fileByIndex(file_index);
5040                unit.cross_section_relocs.appendAssumeCapacity(.{
5041                    .source_off = @intCast(hw.end),
5042                    .target_sec = .debug_line_str,
5043                    .target_unit = StringSection.unit,
5044                    .target_entry = (try dwarf.debug_line_str.addString(dwarf, file.sub_file_path)).toOptional(),
5045                });
5046                hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
5047                const dir_index = mod_info.dirs.getIndex(dwarf.getUnitIfExists(file.mod.?).?) orelse 0;
5048                switch (dir_index_info.bytes) {
5049                    else => unreachable,
5050                    1 => hw.writeByte(@intCast(dir_index)) catch unreachable,
5051                    2 => hw.writeInt(u16, @intCast(dir_index), dwarf.endian) catch unreachable,
5052                }
5053                unit.cross_section_relocs.appendAssumeCapacity(.{
5054                    .source_off = @intCast(hw.end),
5055                    .target_sec = .debug_line_str,
5056                    .target_unit = StringSection.unit,
5057                    .target_entry = (try dwarf.debug_line_str.addString(
5058                        dwarf,
5059                        if (file.is_builtin) file.source.? else "",
5060                    )).toOptional(),
5061                });
5062                hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
5063            }
5064            try unit.replaceHeader(&dwarf.debug_line.section, dwarf, header_aw.written());
5065            try unit.writeTrailer(&dwarf.debug_line.section, dwarf);
5066        }
5067        dwarf.debug_line.section.dirty = false;
5068    }
5069    if (dwarf.debug_line_str.section.dirty) {
5070        const contents = dwarf.debug_line_str.contents.items;
5071        try dwarf.debug_line_str.section.resize(dwarf, contents.len);
5072        try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off(dwarf));
5073        dwarf.debug_line_str.section.dirty = false;
5074    }
5075    if (dwarf.debug_loclists.section.dirty) {
5076        dwarf.debug_loclists.section.dirty = false;
5077    }
5078    if (dwarf.debug_rnglists.section.dirty) {
5079        for (dwarf.debug_rnglists.section.units.items) |*unit| {
5080            header_aw.clearRetainingCapacity();
5081            try header_aw.ensureTotalCapacity(unit.header_len);
5082            const unit_len = (if (unit.next.unwrap()) |next_unit|
5083                dwarf.debug_rnglists.section.getUnit(next_unit).off
5084            else
5085                dwarf.debug_rnglists.section.len) - unit.off - dwarf.unitLengthBytes();
5086            switch (dwarf.format) {
5087                .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
5088                .@"64" => {
5089                    hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
5090                    hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
5091                },
5092            }
5093            hw.writeInt(u16, 5, dwarf.endian) catch unreachable;
5094            hw.writeByte(@intFromEnum(dwarf.address_size)) catch unreachable;
5095            hw.writeByte(0) catch unreachable;
5096            hw.writeInt(u32, 1, dwarf.endian) catch unreachable;
5097            switch (dwarf.format) {
5098                .@"32" => hw.writeInt(u32, dwarf.sectionOffsetBytes() * 1, dwarf.endian) catch unreachable,
5099                .@"64" => hw.writeInt(u64, dwarf.sectionOffsetBytes() * 1, dwarf.endian) catch unreachable,
5100            }
5101            try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header_aw.written());
5102            try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf);
5103        }
5104        dwarf.debug_rnglists.section.dirty = false;
5105    }
5106    assert(!dwarf.debug_abbrev.section.dirty);
5107    assert(!dwarf.debug_aranges.section.dirty);
5108    assert(!dwarf.debug_frame.section.dirty);
5109    assert(!dwarf.debug_info.section.dirty);
5110    assert(!dwarf.debug_line.section.dirty);
5111    assert(!dwarf.debug_line_str.section.dirty);
5112    assert(!dwarf.debug_loclists.section.dirty);
5113    assert(!dwarf.debug_rnglists.section.dirty);
5114    assert(!dwarf.debug_str.section.dirty);
5115}
5116
5117pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void {
5118    for ([_]*Section{
5119        &dwarf.debug_abbrev.section,
5120        &dwarf.debug_aranges.section,
5121        &dwarf.debug_frame.section,
5122        &dwarf.debug_info.section,
5123        &dwarf.debug_line.section,
5124        &dwarf.debug_line_str.section,
5125        &dwarf.debug_loclists.section,
5126        &dwarf.debug_rnglists.section,
5127        &dwarf.debug_str.section,
5128    }) |sec| try sec.resolveRelocs(dwarf);
5129}
5130
5131fn DeclValEnum(comptime T: type) type {
5132    const decls = @typeInfo(T).@"struct".decls;
5133    @setEvalBranchQuota(10 * decls.len);
5134    var field_names: [decls.len][]const u8 = undefined;
5135    var fields_len = 0;
5136    var min_value: ?comptime_int = null;
5137    var max_value: ?comptime_int = null;
5138    for (decls) |decl| {
5139        if (std.mem.startsWith(u8, decl.name, "HP_") or std.mem.endsWith(u8, decl.name, "_user")) continue;
5140        const value = @field(T, decl.name);
5141        field_names[fields_len] = decl.name;
5142        fields_len += 1;
5143        if (min_value == null or min_value.? > value) min_value = value;
5144        if (max_value == null or max_value.? < value) max_value = value;
5145    }
5146    const TagInt = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0);
5147    var field_vals: [fields_len]TagInt = undefined;
5148    for (field_names[0..fields_len], &field_vals) |name, *val| val.* = @field(T, name);
5149    return @Enum(TagInt, .exhaustive, field_names[0..fields_len], &field_vals);
5150}
5151
5152const AbbrevCode = enum {
5153    null,
5154    // padding codes must be one byte uleb128 values to function
5155    pad_1,
5156    pad_n,
5157    // decl, generic decl, and instance codes are assumed to all have the same uleb128 length
5158    decl_alias,
5159    decl_empty_enum,
5160    decl_enum,
5161    decl_namespace_struct,
5162    decl_struct,
5163    decl_packed_struct,
5164    decl_union,
5165    decl_var,
5166    decl_const,
5167    decl_const_runtime_bits,
5168    decl_const_comptime_state,
5169    decl_const_runtime_bits_comptime_state,
5170    decl_nullary_func,
5171    decl_func,
5172    decl_nullary_func_generic,
5173    decl_func_generic,
5174    decl_extern_nullary_func,
5175    decl_extern_func,
5176    generic_decl_var,
5177    generic_decl_const,
5178    generic_decl_func,
5179    decl_instance_alias,
5180    decl_instance_empty_enum,
5181    decl_instance_enum,
5182    decl_instance_namespace_struct,
5183    decl_instance_struct,
5184    decl_instance_packed_struct,
5185    decl_instance_union,
5186    decl_instance_var,
5187    decl_instance_const,
5188    decl_instance_const_runtime_bits,
5189    decl_instance_const_comptime_state,
5190    decl_instance_const_runtime_bits_comptime_state,
5191    decl_instance_nullary_func,
5192    decl_instance_func,
5193    decl_instance_nullary_func_generic,
5194    decl_instance_func_generic,
5195    decl_instance_extern_nullary_func,
5196    decl_instance_extern_func,
5197    // the rest are unrestricted other than empty variants must not be longer
5198    // than the non-empty variant, and so should appear first
5199    compile_unit,
5200    module,
5201    empty_file,
5202    file,
5203    signed_enum_field,
5204    unsigned_enum_field,
5205    big_enum_field,
5206    generated_field,
5207    struct_field,
5208    struct_field_default_runtime_bits,
5209    struct_field_default_comptime_state,
5210    struct_field_comptime,
5211    struct_field_comptime_runtime_bits,
5212    struct_field_comptime_comptime_state,
5213    packed_struct_field,
5214    untagged_union_field,
5215    tagged_union,
5216    signed_tagged_union_field,
5217    unsigned_tagged_union_field,
5218    big_tagged_union_field,
5219    tagged_union_default_field,
5220    void_type,
5221    numeric_type,
5222    inferred_error_set_type,
5223    ptr_type,
5224    ptr_sentinel_type,
5225    is_const,
5226    is_volatile,
5227    array_type,
5228    array_sentinel_type,
5229    vector_type,
5230    array_index,
5231    nullary_func_type,
5232    func_type,
5233    func_type_param,
5234    is_var_args,
5235    generated_empty_enum_type,
5236    generated_enum_type,
5237    generated_empty_struct_type,
5238    generated_struct_type,
5239    generated_union_type,
5240    empty_enum_type,
5241    enum_type,
5242    empty_struct_type,
5243    struct_type,
5244    empty_packed_struct_type,
5245    packed_struct_type,
5246    empty_union_type,
5247    union_type,
5248    builtin_extern_nullary_func,
5249    builtin_extern_func,
5250    builtin_extern_var,
5251    empty_block,
5252    block,
5253    empty_inlined_func,
5254    inlined_func,
5255    arg,
5256    unnamed_arg,
5257    comptime_arg,
5258    unnamed_comptime_arg,
5259    comptime_arg_runtime_bits,
5260    unnamed_comptime_arg_runtime_bits,
5261    comptime_arg_comptime_state,
5262    unnamed_comptime_arg_comptime_state,
5263    comptime_arg_runtime_bits_comptime_state,
5264    unnamed_comptime_arg_runtime_bits_comptime_state,
5265    extern_param,
5266    local_var,
5267    local_const,
5268    local_const_runtime_bits,
5269    local_const_comptime_state,
5270    local_const_runtime_bits_comptime_state,
5271    undefined_comptime_value,
5272    data2_comptime_value,
5273    data4_comptime_value,
5274    data8_comptime_value,
5275    data16_comptime_value,
5276    sdata_comptime_value,
5277    udata_comptime_value,
5278    block_comptime_value,
5279    string_comptime_value,
5280    location_comptime_value,
5281    aggregate_comptime_value,
5282    comptime_value_field_runtime_bits,
5283    comptime_value_field_comptime_state,
5284    comptime_value_elem_runtime_bits,
5285    comptime_value_elem_comptime_state,
5286
5287    const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_instance_extern_func));
5288    comptime {
5289        assert(uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)) == 1);
5290        assert(uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) == 1);
5291        assert(uleb128Bytes(@intFromEnum(AbbrevCode.decl_alias)) == decl_bytes);
5292    }
5293
5294    const Attr = struct {
5295        DeclValEnum(DW.AT),
5296        DeclValEnum(DW.FORM),
5297    };
5298    const decl_abbrev_common_attrs = &[_]Attr{
5299        .{ .ZIG_parent, .ref_addr },
5300        .{ .decl_line, .data4 },
5301        .{ .decl_column, .udata },
5302        .{ .accessibility, .data1 },
5303        .{ .name, .strp },
5304    };
5305    const generic_decl_abbrev_common_attrs = decl_abbrev_common_attrs ++ &[_]Attr{
5306        .{ .declaration, .flag_present },
5307    };
5308    const decl_instance_abbrev_common_attrs = &[_]Attr{
5309        .{ .ZIG_parent, .ref_addr },
5310        .{ .abstract_origin, .ref_addr },
5311    };
5312    const abbrevs = std.EnumArray(AbbrevCode, struct {
5313        tag: DeclValEnum(DW.TAG),
5314        children: bool = false,
5315        attrs: []const Attr = &.{},
5316    }).init(.{
5317        .pad_1 = .{
5318            .tag = .ZIG_padding,
5319        },
5320        .pad_n = .{
5321            .tag = .ZIG_padding,
5322            .attrs = &.{
5323                .{ .ZIG_padding, .block },
5324            },
5325        },
5326        .decl_alias = .{
5327            .tag = .imported_declaration,
5328            .attrs = decl_abbrev_common_attrs ++ .{
5329                .{ .import, .ref_addr },
5330            },
5331        },
5332        .decl_empty_enum = .{
5333            .tag = .enumeration_type,
5334            .attrs = decl_abbrev_common_attrs ++ .{
5335                .{ .type, .ref_addr },
5336            },
5337        },
5338        .decl_enum = .{
5339            .tag = .enumeration_type,
5340            .children = true,
5341            .attrs = decl_abbrev_common_attrs ++ .{
5342                .{ .type, .ref_addr },
5343            },
5344        },
5345        .decl_namespace_struct = .{
5346            .tag = .structure_type,
5347            .attrs = decl_abbrev_common_attrs ++ .{
5348                .{ .declaration, .flag },
5349            },
5350        },
5351        .decl_struct = .{
5352            .tag = .structure_type,
5353            .children = true,
5354            .attrs = decl_abbrev_common_attrs ++ .{
5355                .{ .byte_size, .udata },
5356                .{ .alignment, .udata },
5357            },
5358        },
5359        .decl_packed_struct = .{
5360            .tag = .structure_type,
5361            .children = true,
5362            .attrs = decl_abbrev_common_attrs ++ .{
5363                .{ .type, .ref_addr },
5364            },
5365        },
5366        .decl_union = .{
5367            .tag = .union_type,
5368            .children = true,
5369            .attrs = decl_abbrev_common_attrs ++ .{
5370                .{ .byte_size, .udata },
5371                .{ .alignment, .udata },
5372            },
5373        },
5374        .decl_var = .{
5375            .tag = .variable,
5376            .attrs = decl_abbrev_common_attrs ++ .{
5377                .{ .linkage_name, .strp },
5378                .{ .type, .ref_addr },
5379                .{ .location, .exprloc },
5380                .{ .alignment, .udata },
5381                .{ .external, .flag },
5382            },
5383        },
5384        .decl_const = .{
5385            .tag = .constant,
5386            .attrs = decl_abbrev_common_attrs ++ .{
5387                .{ .linkage_name, .strp },
5388                .{ .type, .ref_addr },
5389                .{ .alignment, .udata },
5390                .{ .external, .flag },
5391            },
5392        },
5393        .decl_const_runtime_bits = .{
5394            .tag = .constant,
5395            .attrs = decl_abbrev_common_attrs ++ .{
5396                .{ .linkage_name, .strp },
5397                .{ .type, .ref_addr },
5398                .{ .alignment, .udata },
5399                .{ .external, .flag },
5400                .{ .const_value, .block },
5401            },
5402        },
5403        .decl_const_comptime_state = .{
5404            .tag = .constant,
5405            .attrs = decl_abbrev_common_attrs ++ .{
5406                .{ .linkage_name, .strp },
5407                .{ .type, .ref_addr },
5408                .{ .alignment, .udata },
5409                .{ .external, .flag },
5410                .{ .ZIG_comptime_value, .ref_addr },
5411            },
5412        },
5413        .decl_const_runtime_bits_comptime_state = .{
5414            .tag = .constant,
5415            .attrs = decl_abbrev_common_attrs ++ .{
5416                .{ .linkage_name, .strp },
5417                .{ .type, .ref_addr },
5418                .{ .alignment, .udata },
5419                .{ .external, .flag },
5420                .{ .const_value, .block },
5421                .{ .ZIG_comptime_value, .ref_addr },
5422            },
5423        },
5424        .decl_nullary_func = .{
5425            .tag = .subprogram,
5426            .attrs = decl_abbrev_common_attrs ++ .{
5427                .{ .linkage_name, .strp },
5428                .{ .type, .ref_addr },
5429                .{ .low_pc, .addr },
5430                .{ .high_pc, .data4 },
5431                .{ .alignment, .udata },
5432                .{ .external, .flag },
5433                .{ .noreturn, .flag },
5434            },
5435        },
5436        .decl_func = .{
5437            .tag = .subprogram,
5438            .children = true,
5439            .attrs = decl_abbrev_common_attrs ++ .{
5440                .{ .linkage_name, .strp },
5441                .{ .type, .ref_addr },
5442                .{ .low_pc, .addr },
5443                .{ .high_pc, .data4 },
5444                .{ .alignment, .udata },
5445                .{ .external, .flag },
5446                .{ .noreturn, .flag },
5447            },
5448        },
5449        .decl_nullary_func_generic = .{
5450            .tag = .subprogram,
5451            .attrs = decl_abbrev_common_attrs ++ .{
5452                .{ .type, .ref_addr },
5453            },
5454        },
5455        .decl_func_generic = .{
5456            .tag = .subprogram,
5457            .children = true,
5458            .attrs = decl_abbrev_common_attrs ++ .{
5459                .{ .type, .ref_addr },
5460            },
5461        },
5462        .decl_extern_nullary_func = .{
5463            .tag = .subprogram,
5464            .attrs = decl_abbrev_common_attrs ++ .{
5465                .{ .linkage_name, .strp },
5466                .{ .type, .ref_addr },
5467                .{ .low_pc, .addr },
5468                .{ .external, .flag_present },
5469                .{ .noreturn, .flag },
5470            },
5471        },
5472        .decl_extern_func = .{
5473            .tag = .subprogram,
5474            .children = true,
5475            .attrs = decl_abbrev_common_attrs ++ .{
5476                .{ .linkage_name, .strp },
5477                .{ .type, .ref_addr },
5478                .{ .low_pc, .addr },
5479                .{ .external, .flag_present },
5480                .{ .noreturn, .flag },
5481            },
5482        },
5483        .generic_decl_var = .{
5484            .tag = .variable,
5485            .attrs = generic_decl_abbrev_common_attrs,
5486        },
5487        .generic_decl_const = .{
5488            .tag = .constant,
5489            .attrs = generic_decl_abbrev_common_attrs,
5490        },
5491        .generic_decl_func = .{
5492            .tag = .subprogram,
5493            .attrs = generic_decl_abbrev_common_attrs,
5494        },
5495        .decl_instance_alias = .{
5496            .tag = .imported_declaration,
5497            .attrs = decl_instance_abbrev_common_attrs ++ .{
5498                .{ .import, .ref_addr },
5499            },
5500        },
5501        .decl_instance_empty_enum = .{
5502            .tag = .enumeration_type,
5503            .attrs = decl_instance_abbrev_common_attrs ++ .{
5504                .{ .type, .ref_addr },
5505            },
5506        },
5507        .decl_instance_enum = .{
5508            .tag = .enumeration_type,
5509            .children = true,
5510            .attrs = decl_instance_abbrev_common_attrs ++ .{
5511                .{ .type, .ref_addr },
5512            },
5513        },
5514        .decl_instance_namespace_struct = .{
5515            .tag = .structure_type,
5516            .attrs = decl_instance_abbrev_common_attrs ++ .{
5517                .{ .declaration, .flag },
5518            },
5519        },
5520        .decl_instance_struct = .{
5521            .tag = .structure_type,
5522            .children = true,
5523            .attrs = decl_instance_abbrev_common_attrs ++ .{
5524                .{ .byte_size, .udata },
5525                .{ .alignment, .udata },
5526            },
5527        },
5528        .decl_instance_packed_struct = .{
5529            .tag = .structure_type,
5530            .children = true,
5531            .attrs = decl_instance_abbrev_common_attrs ++ .{
5532                .{ .type, .ref_addr },
5533            },
5534        },
5535        .decl_instance_union = .{
5536            .tag = .union_type,
5537            .children = true,
5538            .attrs = decl_instance_abbrev_common_attrs ++ .{
5539                .{ .byte_size, .udata },
5540                .{ .alignment, .udata },
5541            },
5542        },
5543        .decl_instance_var = .{
5544            .tag = .variable,
5545            .attrs = decl_instance_abbrev_common_attrs ++ .{
5546                .{ .linkage_name, .strp },
5547                .{ .type, .ref_addr },
5548                .{ .location, .exprloc },
5549                .{ .alignment, .udata },
5550                .{ .external, .flag },
5551            },
5552        },
5553        .decl_instance_const = .{
5554            .tag = .constant,
5555            .attrs = decl_instance_abbrev_common_attrs ++ .{
5556                .{ .linkage_name, .strp },
5557                .{ .type, .ref_addr },
5558                .{ .alignment, .udata },
5559                .{ .external, .flag },
5560            },
5561        },
5562        .decl_instance_const_runtime_bits = .{
5563            .tag = .constant,
5564            .attrs = decl_instance_abbrev_common_attrs ++ .{
5565                .{ .linkage_name, .strp },
5566                .{ .type, .ref_addr },
5567                .{ .alignment, .udata },
5568                .{ .external, .flag },
5569                .{ .const_value, .block },
5570            },
5571        },
5572        .decl_instance_const_comptime_state = .{
5573            .tag = .constant,
5574            .attrs = decl_instance_abbrev_common_attrs ++ .{
5575                .{ .linkage_name, .strp },
5576                .{ .type, .ref_addr },
5577                .{ .alignment, .udata },
5578                .{ .external, .flag },
5579                .{ .ZIG_comptime_value, .ref_addr },
5580            },
5581        },
5582        .decl_instance_const_runtime_bits_comptime_state = .{
5583            .tag = .constant,
5584            .attrs = decl_instance_abbrev_common_attrs ++ .{
5585                .{ .linkage_name, .strp },
5586                .{ .type, .ref_addr },
5587                .{ .alignment, .udata },
5588                .{ .external, .flag },
5589                .{ .const_value, .block },
5590                .{ .ZIG_comptime_value, .ref_addr },
5591            },
5592        },
5593        .decl_instance_nullary_func = .{
5594            .tag = .subprogram,
5595            .attrs = decl_instance_abbrev_common_attrs ++ .{
5596                .{ .linkage_name, .strp },
5597                .{ .type, .ref_addr },
5598                .{ .low_pc, .addr },
5599                .{ .high_pc, .data4 },
5600                .{ .alignment, .udata },
5601                .{ .external, .flag },
5602                .{ .noreturn, .flag },
5603            },
5604        },
5605        .decl_instance_func = .{
5606            .tag = .subprogram,
5607            .children = true,
5608            .attrs = decl_instance_abbrev_common_attrs ++ .{
5609                .{ .linkage_name, .strp },
5610                .{ .type, .ref_addr },
5611                .{ .low_pc, .addr },
5612                .{ .high_pc, .data4 },
5613                .{ .alignment, .udata },
5614                .{ .external, .flag },
5615                .{ .noreturn, .flag },
5616            },
5617        },
5618        .decl_instance_nullary_func_generic = .{
5619            .tag = .subprogram,
5620            .attrs = decl_instance_abbrev_common_attrs ++ .{
5621                .{ .type, .ref_addr },
5622            },
5623        },
5624        .decl_instance_func_generic = .{
5625            .tag = .subprogram,
5626            .children = true,
5627            .attrs = decl_instance_abbrev_common_attrs ++ .{
5628                .{ .type, .ref_addr },
5629            },
5630        },
5631        .decl_instance_extern_nullary_func = .{
5632            .tag = .subprogram,
5633            .attrs = decl_instance_abbrev_common_attrs ++ .{
5634                .{ .linkage_name, .strp },
5635                .{ .type, .ref_addr },
5636                .{ .low_pc, .addr },
5637                .{ .external, .flag_present },
5638                .{ .noreturn, .flag },
5639            },
5640        },
5641        .decl_instance_extern_func = .{
5642            .tag = .subprogram,
5643            .children = true,
5644            .attrs = decl_instance_abbrev_common_attrs ++ .{
5645                .{ .linkage_name, .strp },
5646                .{ .type, .ref_addr },
5647                .{ .low_pc, .addr },
5648                .{ .external, .flag_present },
5649                .{ .noreturn, .flag },
5650            },
5651        },
5652        .compile_unit = .{
5653            .tag = .compile_unit,
5654            .children = true,
5655            .attrs = &.{
5656                .{ .language, .data1 },
5657                .{ .producer, .line_strp },
5658                .{ .comp_dir, .line_strp },
5659                .{ .name, .line_strp },
5660                .{ .base_types, .ref_addr },
5661                .{ .stmt_list, .sec_offset },
5662                .{ .rnglists_base, .sec_offset },
5663                .{ .ranges, .rnglistx },
5664            },
5665        },
5666        .module = .{
5667            .tag = .module,
5668            .children = true,
5669            .attrs = &.{
5670                .{ .name, .strp },
5671                .{ .ranges, .rnglistx },
5672            },
5673        },
5674        .empty_file = .{
5675            .tag = .structure_type,
5676            .attrs = &.{
5677                .{ .decl_file, .udata },
5678                .{ .name, .strp },
5679            },
5680        },
5681        .file = .{
5682            .tag = .structure_type,
5683            .children = true,
5684            .attrs = &.{
5685                .{ .decl_file, .udata },
5686                .{ .name, .strp },
5687                .{ .byte_size, .udata },
5688                .{ .alignment, .udata },
5689            },
5690        },
5691        .signed_enum_field = .{
5692            .tag = .enumerator,
5693            .attrs = &.{
5694                .{ .const_value, .sdata },
5695                .{ .name, .strp },
5696            },
5697        },
5698        .unsigned_enum_field = .{
5699            .tag = .enumerator,
5700            .attrs = &.{
5701                .{ .const_value, .udata },
5702                .{ .name, .strp },
5703            },
5704        },
5705        .big_enum_field = .{
5706            .tag = .enumerator,
5707            .attrs = &.{
5708                .{ .const_value, .block },
5709                .{ .name, .strp },
5710            },
5711        },
5712        .generated_field = .{
5713            .tag = .member,
5714            .attrs = &.{
5715                .{ .name, .strp },
5716                .{ .type, .ref_addr },
5717                .{ .data_member_location, .udata },
5718                .{ .artificial, .flag_present },
5719            },
5720        },
5721        .struct_field = .{
5722            .tag = .member,
5723            .attrs = &.{
5724                .{ .name, .strp },
5725                .{ .type, .ref_addr },
5726                .{ .data_member_location, .udata },
5727                .{ .alignment, .udata },
5728            },
5729        },
5730        .struct_field_default_runtime_bits = .{
5731            .tag = .member,
5732            .attrs = &.{
5733                .{ .name, .strp },
5734                .{ .type, .ref_addr },
5735                .{ .data_member_location, .udata },
5736                .{ .alignment, .udata },
5737                .{ .default_value, .block },
5738            },
5739        },
5740        .struct_field_default_comptime_state = .{
5741            .tag = .member,
5742            .attrs = &.{
5743                .{ .name, .strp },
5744                .{ .type, .ref_addr },
5745                .{ .data_member_location, .udata },
5746                .{ .alignment, .udata },
5747                .{ .ZIG_comptime_value, .ref_addr },
5748            },
5749        },
5750        .struct_field_comptime = .{
5751            .tag = .member,
5752            .attrs = &.{
5753                .{ .const_expr, .flag_present },
5754                .{ .name, .strp },
5755                .{ .type, .ref_addr },
5756            },
5757        },
5758        .struct_field_comptime_runtime_bits = .{
5759            .tag = .member,
5760            .attrs = &.{
5761                .{ .const_expr, .flag_present },
5762                .{ .name, .strp },
5763                .{ .type, .ref_addr },
5764                .{ .const_value, .block },
5765            },
5766        },
5767        .struct_field_comptime_comptime_state = .{
5768            .tag = .member,
5769            .attrs = &.{
5770                .{ .const_expr, .flag_present },
5771                .{ .name, .strp },
5772                .{ .type, .ref_addr },
5773                .{ .ZIG_comptime_value, .ref_addr },
5774            },
5775        },
5776        .packed_struct_field = .{
5777            .tag = .member,
5778            .attrs = &.{
5779                .{ .name, .strp },
5780                .{ .type, .ref_addr },
5781                .{ .data_bit_offset, .udata },
5782            },
5783        },
5784        .untagged_union_field = .{
5785            .tag = .member,
5786            .attrs = &.{
5787                .{ .name, .strp },
5788                .{ .type, .ref_addr },
5789                .{ .alignment, .udata },
5790            },
5791        },
5792        .tagged_union = .{
5793            .tag = .variant_part,
5794            .children = true,
5795            .attrs = &.{
5796                .{ .discr, .ref_addr },
5797            },
5798        },
5799        .signed_tagged_union_field = .{
5800            .tag = .variant,
5801            .children = true,
5802            .attrs = &.{
5803                .{ .discr_value, .sdata },
5804            },
5805        },
5806        .unsigned_tagged_union_field = .{
5807            .tag = .variant,
5808            .children = true,
5809            .attrs = &.{
5810                .{ .discr_value, .udata },
5811            },
5812        },
5813        .big_tagged_union_field = .{
5814            .tag = .variant,
5815            .children = true,
5816            .attrs = &.{
5817                .{ .discr_value, .block },
5818            },
5819        },
5820        .tagged_union_default_field = .{
5821            .tag = .variant,
5822            .children = true,
5823            .attrs = &.{},
5824        },
5825        .void_type = .{
5826            .tag = .unspecified_type,
5827            .attrs = &.{
5828                .{ .name, .strp },
5829            },
5830        },
5831        .numeric_type = .{
5832            .tag = .base_type,
5833            .attrs = &.{
5834                .{ .name, .strp },
5835                .{ .encoding, .data1 },
5836                .{ .bit_size, .udata },
5837                .{ .byte_size, .udata },
5838                .{ .alignment, .udata },
5839            },
5840        },
5841        .inferred_error_set_type = .{
5842            .tag = .typedef,
5843            .attrs = &.{
5844                .{ .name, .strp },
5845                .{ .type, .ref_addr },
5846            },
5847        },
5848        .ptr_type = .{
5849            .tag = .pointer_type,
5850            .attrs = &.{
5851                .{ .name, .strp },
5852                .{ .alignment, .udata },
5853                .{ .address_class, .data1 },
5854                .{ .type, .ref_addr },
5855            },
5856        },
5857        .ptr_sentinel_type = .{
5858            .tag = .pointer_type,
5859            .attrs = &.{
5860                .{ .name, .strp },
5861                .{ .ZIG_sentinel, .block },
5862                .{ .alignment, .udata },
5863                .{ .address_class, .data1 },
5864                .{ .type, .ref_addr },
5865            },
5866        },
5867        .is_const = .{
5868            .tag = .const_type,
5869            .attrs = &.{
5870                .{ .type, .ref_addr },
5871            },
5872        },
5873        .is_volatile = .{
5874            .tag = .volatile_type,
5875            .attrs = &.{
5876                .{ .type, .ref_addr },
5877            },
5878        },
5879        .array_type = .{
5880            .tag = .array_type,
5881            .children = true,
5882            .attrs = &.{
5883                .{ .name, .strp },
5884                .{ .type, .ref_addr },
5885            },
5886        },
5887        .array_sentinel_type = .{
5888            .tag = .array_type,
5889            .children = true,
5890            .attrs = &.{
5891                .{ .name, .strp },
5892                .{ .ZIG_sentinel, .block },
5893                .{ .type, .ref_addr },
5894            },
5895        },
5896        .vector_type = .{
5897            .tag = .array_type,
5898            .children = true,
5899            .attrs = &.{
5900                .{ .name, .strp },
5901                .{ .type, .ref_addr },
5902                .{ .GNU_vector, .flag_present },
5903            },
5904        },
5905        .array_index = .{
5906            .tag = .subrange_type,
5907            .attrs = &.{
5908                .{ .type, .ref_addr },
5909                .{ .count, .udata },
5910            },
5911        },
5912        .nullary_func_type = .{
5913            .tag = .subroutine_type,
5914            .attrs = &.{
5915                .{ .name, .strp },
5916                .{ .calling_convention, .data1 },
5917                .{ .type, .ref_addr },
5918            },
5919        },
5920        .func_type = .{
5921            .tag = .subroutine_type,
5922            .children = true,
5923            .attrs = &.{
5924                .{ .name, .strp },
5925                .{ .calling_convention, .data1 },
5926                .{ .type, .ref_addr },
5927            },
5928        },
5929        .func_type_param = .{
5930            .tag = .formal_parameter,
5931            .attrs = &.{
5932                .{ .type, .ref_addr },
5933            },
5934        },
5935        .is_var_args = .{
5936            .tag = .unspecified_parameters,
5937        },
5938        .generated_empty_enum_type = .{
5939            .tag = .enumeration_type,
5940            .attrs = &.{
5941                .{ .name, .strp },
5942                .{ .type, .ref_addr },
5943            },
5944        },
5945        .generated_enum_type = .{
5946            .tag = .enumeration_type,
5947            .children = true,
5948            .attrs = &.{
5949                .{ .name, .strp },
5950                .{ .type, .ref_addr },
5951            },
5952        },
5953        .generated_empty_struct_type = .{
5954            .tag = .structure_type,
5955            .attrs = &.{
5956                .{ .name, .strp },
5957                .{ .declaration, .flag },
5958            },
5959        },
5960        .generated_struct_type = .{
5961            .tag = .structure_type,
5962            .children = true,
5963            .attrs = &.{
5964                .{ .name, .strp },
5965                .{ .byte_size, .udata },
5966                .{ .alignment, .udata },
5967            },
5968        },
5969        .generated_union_type = .{
5970            .tag = .union_type,
5971            .children = true,
5972            .attrs = &.{
5973                .{ .name, .strp },
5974                .{ .byte_size, .udata },
5975                .{ .alignment, .udata },
5976            },
5977        },
5978        .empty_enum_type = .{
5979            .tag = .enumeration_type,
5980            .attrs = &.{
5981                .{ .decl_file, .udata },
5982                .{ .name, .strp },
5983                .{ .type, .ref_addr },
5984            },
5985        },
5986        .enum_type = .{
5987            .tag = .enumeration_type,
5988            .children = true,
5989            .attrs = &.{
5990                .{ .decl_file, .udata },
5991                .{ .name, .strp },
5992                .{ .type, .ref_addr },
5993            },
5994        },
5995        .empty_struct_type = .{
5996            .tag = .structure_type,
5997            .attrs = &.{
5998                .{ .decl_file, .udata },
5999                .{ .name, .strp },
6000                .{ .declaration, .flag },
6001            },
6002        },
6003        .struct_type = .{
6004            .tag = .structure_type,
6005            .children = true,
6006            .attrs = &.{
6007                .{ .decl_file, .udata },
6008                .{ .name, .strp },
6009                .{ .byte_size, .udata },
6010                .{ .alignment, .udata },
6011            },
6012        },
6013        .empty_packed_struct_type = .{
6014            .tag = .structure_type,
6015            .attrs = &.{
6016                .{ .decl_file, .udata },
6017                .{ .name, .strp },
6018                .{ .type, .ref_addr },
6019            },
6020        },
6021        .packed_struct_type = .{
6022            .tag = .structure_type,
6023            .children = true,
6024            .attrs = &.{
6025                .{ .decl_file, .udata },
6026                .{ .name, .strp },
6027                .{ .type, .ref_addr },
6028            },
6029        },
6030        .empty_union_type = .{
6031            .tag = .union_type,
6032            .attrs = &.{
6033                .{ .decl_file, .udata },
6034                .{ .name, .strp },
6035                .{ .byte_size, .udata },
6036                .{ .alignment, .udata },
6037            },
6038        },
6039        .union_type = .{
6040            .tag = .union_type,
6041            .children = true,
6042            .attrs = &.{
6043                .{ .decl_file, .udata },
6044                .{ .name, .strp },
6045                .{ .byte_size, .udata },
6046                .{ .alignment, .udata },
6047            },
6048        },
6049        .builtin_extern_nullary_func = .{
6050            .tag = .subprogram,
6051            .attrs = &.{
6052                .{ .ZIG_parent, .ref_addr },
6053                .{ .linkage_name, .strp },
6054                .{ .type, .ref_addr },
6055                .{ .low_pc, .addr },
6056                .{ .external, .flag_present },
6057                .{ .noreturn, .flag },
6058            },
6059        },
6060        .builtin_extern_func = .{
6061            .tag = .subprogram,
6062            .children = true,
6063            .attrs = &.{
6064                .{ .ZIG_parent, .ref_addr },
6065                .{ .linkage_name, .strp },
6066                .{ .type, .ref_addr },
6067                .{ .low_pc, .addr },
6068                .{ .external, .flag_present },
6069                .{ .noreturn, .flag },
6070            },
6071        },
6072        .builtin_extern_var = .{
6073            .tag = .variable,
6074            .attrs = &.{
6075                .{ .ZIG_parent, .ref_addr },
6076                .{ .linkage_name, .strp },
6077                .{ .type, .ref_addr },
6078                .{ .location, .exprloc },
6079                .{ .external, .flag_present },
6080            },
6081        },
6082        .empty_block = .{
6083            .tag = .lexical_block,
6084            .attrs = &.{
6085                .{ .low_pc, .addr },
6086                .{ .high_pc, .data4 },
6087            },
6088        },
6089        .block = .{
6090            .tag = .lexical_block,
6091            .children = true,
6092            .attrs = &.{
6093                .{ .low_pc, .addr },
6094                .{ .high_pc, .data4 },
6095            },
6096        },
6097        .empty_inlined_func = .{
6098            .tag = .inlined_subroutine,
6099            .attrs = &.{
6100                .{ .abstract_origin, .ref_addr },
6101                .{ .call_line, .udata },
6102                .{ .call_column, .udata },
6103                .{ .low_pc, .addr },
6104                .{ .high_pc, .data4 },
6105            },
6106        },
6107        .inlined_func = .{
6108            .tag = .inlined_subroutine,
6109            .children = true,
6110            .attrs = &.{
6111                .{ .abstract_origin, .ref_addr },
6112                .{ .call_line, .udata },
6113                .{ .call_column, .udata },
6114                .{ .low_pc, .addr },
6115                .{ .high_pc, .data4 },
6116            },
6117        },
6118        .arg = .{
6119            .tag = .formal_parameter,
6120            .attrs = &.{
6121                .{ .name, .strp },
6122                .{ .type, .ref_addr },
6123                .{ .location, .exprloc },
6124            },
6125        },
6126        .unnamed_arg = .{
6127            .tag = .formal_parameter,
6128            .attrs = &.{
6129                .{ .type, .ref_addr },
6130                .{ .location, .exprloc },
6131            },
6132        },
6133        .comptime_arg = .{
6134            .tag = .formal_parameter,
6135            .attrs = &.{
6136                .{ .const_expr, .flag_present },
6137                .{ .name, .strp },
6138                .{ .type, .ref_addr },
6139            },
6140        },
6141        .unnamed_comptime_arg = .{
6142            .tag = .formal_parameter,
6143            .attrs = &.{
6144                .{ .const_expr, .flag_present },
6145                .{ .type, .ref_addr },
6146            },
6147        },
6148        .comptime_arg_runtime_bits = .{
6149            .tag = .formal_parameter,
6150            .attrs = &.{
6151                .{ .const_expr, .flag_present },
6152                .{ .name, .strp },
6153                .{ .type, .ref_addr },
6154                .{ .const_value, .block },
6155            },
6156        },
6157        .unnamed_comptime_arg_runtime_bits = .{
6158            .tag = .formal_parameter,
6159            .attrs = &.{
6160                .{ .const_expr, .flag_present },
6161                .{ .type, .ref_addr },
6162                .{ .const_value, .block },
6163            },
6164        },
6165        .comptime_arg_comptime_state = .{
6166            .tag = .formal_parameter,
6167            .attrs = &.{
6168                .{ .const_expr, .flag_present },
6169                .{ .name, .strp },
6170                .{ .type, .ref_addr },
6171                .{ .ZIG_comptime_value, .ref_addr },
6172            },
6173        },
6174        .unnamed_comptime_arg_comptime_state = .{
6175            .tag = .formal_parameter,
6176            .attrs = &.{
6177                .{ .const_expr, .flag_present },
6178                .{ .type, .ref_addr },
6179                .{ .ZIG_comptime_value, .ref_addr },
6180            },
6181        },
6182        .comptime_arg_runtime_bits_comptime_state = .{
6183            .tag = .formal_parameter,
6184            .attrs = &.{
6185                .{ .const_expr, .flag_present },
6186                .{ .name, .strp },
6187                .{ .type, .ref_addr },
6188                .{ .const_value, .block },
6189                .{ .ZIG_comptime_value, .ref_addr },
6190            },
6191        },
6192        .unnamed_comptime_arg_runtime_bits_comptime_state = .{
6193            .tag = .formal_parameter,
6194            .attrs = &.{
6195                .{ .const_expr, .flag_present },
6196                .{ .type, .ref_addr },
6197                .{ .const_value, .block },
6198                .{ .ZIG_comptime_value, .ref_addr },
6199            },
6200        },
6201        .extern_param = .{
6202            .tag = .formal_parameter,
6203            .attrs = &.{
6204                .{ .type, .ref_addr },
6205            },
6206        },
6207        .local_var = .{
6208            .tag = .variable,
6209            .attrs = &.{
6210                .{ .name, .strp },
6211                .{ .type, .ref_addr },
6212                .{ .location, .exprloc },
6213            },
6214        },
6215        .local_const = .{
6216            .tag = .constant,
6217            .attrs = &.{
6218                .{ .name, .strp },
6219                .{ .type, .ref_addr },
6220            },
6221        },
6222        .local_const_runtime_bits = .{
6223            .tag = .constant,
6224            .attrs = &.{
6225                .{ .name, .strp },
6226                .{ .type, .ref_addr },
6227                .{ .const_value, .block },
6228            },
6229        },
6230        .local_const_comptime_state = .{
6231            .tag = .constant,
6232            .attrs = &.{
6233                .{ .name, .strp },
6234                .{ .type, .ref_addr },
6235                .{ .ZIG_comptime_value, .ref_addr },
6236            },
6237        },
6238        .local_const_runtime_bits_comptime_state = .{
6239            .tag = .constant,
6240            .attrs = &.{
6241                .{ .name, .strp },
6242                .{ .type, .ref_addr },
6243                .{ .const_value, .block },
6244                .{ .ZIG_comptime_value, .ref_addr },
6245            },
6246        },
6247        .undefined_comptime_value = .{
6248            .tag = .ZIG_comptime_value,
6249            .attrs = &.{
6250                .{ .type, .ref_addr },
6251            },
6252        },
6253        .data2_comptime_value = .{
6254            .tag = .ZIG_comptime_value,
6255            .attrs = &.{
6256                .{ .const_value, .data2 },
6257                .{ .type, .ref_addr },
6258            },
6259        },
6260        .data4_comptime_value = .{
6261            .tag = .ZIG_comptime_value,
6262            .attrs = &.{
6263                .{ .const_value, .data4 },
6264                .{ .type, .ref_addr },
6265            },
6266        },
6267        .data8_comptime_value = .{
6268            .tag = .ZIG_comptime_value,
6269            .attrs = &.{
6270                .{ .const_value, .data8 },
6271                .{ .type, .ref_addr },
6272            },
6273        },
6274        .data16_comptime_value = .{
6275            .tag = .ZIG_comptime_value,
6276            .attrs = &.{
6277                .{ .const_value, .data16 },
6278                .{ .type, .ref_addr },
6279            },
6280        },
6281        .sdata_comptime_value = .{
6282            .tag = .ZIG_comptime_value,
6283            .attrs = &.{
6284                .{ .const_value, .sdata },
6285                .{ .type, .ref_addr },
6286            },
6287        },
6288        .udata_comptime_value = .{
6289            .tag = .ZIG_comptime_value,
6290            .attrs = &.{
6291                .{ .const_value, .udata },
6292                .{ .type, .ref_addr },
6293            },
6294        },
6295        .block_comptime_value = .{
6296            .tag = .ZIG_comptime_value,
6297            .attrs = &.{
6298                .{ .const_value, .block },
6299                .{ .type, .ref_addr },
6300            },
6301        },
6302        .string_comptime_value = .{
6303            .tag = .ZIG_comptime_value,
6304            .attrs = &.{
6305                .{ .const_value, .strp },
6306                .{ .type, .ref_addr },
6307            },
6308        },
6309        .location_comptime_value = .{
6310            .tag = .ZIG_comptime_value,
6311            .attrs = &.{
6312                .{ .location, .exprloc },
6313                .{ .type, .ref_addr },
6314            },
6315        },
6316        .aggregate_comptime_value = .{
6317            .tag = .ZIG_comptime_value,
6318            .children = true,
6319            .attrs = &.{
6320                .{ .type, .ref_addr },
6321            },
6322        },
6323        .comptime_value_field_runtime_bits = .{
6324            .tag = .member,
6325            .attrs = &.{
6326                .{ .name, .strp },
6327                .{ .const_value, .block },
6328            },
6329        },
6330        .comptime_value_field_comptime_state = .{
6331            .tag = .member,
6332            .attrs = &.{
6333                .{ .name, .strp },
6334                .{ .ZIG_comptime_value, .ref_addr },
6335            },
6336        },
6337        .comptime_value_elem_runtime_bits = .{
6338            .tag = .member,
6339            .attrs = &.{
6340                .{ .const_value, .block },
6341            },
6342        },
6343        .comptime_value_elem_comptime_state = .{
6344            .tag = .member,
6345            .attrs = &.{
6346                .{ .ZIG_comptime_value, .ref_addr },
6347            },
6348        },
6349        .null = undefined,
6350    });
6351};
6352
6353fn getFile(dwarf: *Dwarf) ?std.fs.File {
6354    if (dwarf.bin_file.cast(.macho)) |macho_file| if (macho_file.d_sym) |*d_sym| return d_sym.file;
6355    return dwarf.bin_file.file;
6356}
6357
6358fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {
6359    const entry = try dwarf.debug_aranges.section.getUnit(unit).addEntry(dwarf.gpa);
6360    assert(try dwarf.debug_frame.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6361    assert(try dwarf.debug_info.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6362    assert(try dwarf.debug_line.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6363    assert(try dwarf.debug_loclists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6364    assert(try dwarf.debug_rnglists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6365    return entry;
6366}
6367
6368fn freeCommonEntry(
6369    dwarf: *Dwarf,
6370    unit: Unit.Index,
6371    entry: Entry.Index,
6372) (UpdateError || Writer.Error)!void {
6373    try dwarf.debug_aranges.section.freeEntry(unit, entry, dwarf);
6374    try dwarf.debug_frame.section.freeEntry(unit, entry, dwarf);
6375    try dwarf.debug_info.section.freeEntry(unit, entry, dwarf);
6376    try dwarf.debug_line.section.freeEntry(unit, entry, dwarf);
6377    try dwarf.debug_loclists.section.freeEntry(unit, entry, dwarf);
6378    try dwarf.debug_rnglists.section.freeEntry(unit, entry, dwarf);
6379}
6380
6381fn writeInt(dwarf: *Dwarf, buf: []u8, int: u64) void {
6382    switch (buf.len) {
6383        inline 0...8 => |len| std.mem.writeInt(
6384            @Int(.unsigned, len * 8),
6385            buf[0..len],
6386            @intCast(int),
6387            dwarf.endian,
6388        ),
6389        else => unreachable,
6390    }
6391}
6392
6393fn resolveReloc(dwarf: *Dwarf, source: u64, target: u64, size: u32) RelocError!void {
6394    var buf: [8]u8 = undefined;
6395    dwarf.writeInt(buf[0..size], target);
6396    try dwarf.getFile().?.pwriteAll(buf[0..size], source);
6397}
6398
6399fn unitLengthBytes(dwarf: *Dwarf) u32 {
6400    return switch (dwarf.format) {
6401        .@"32" => 4,
6402        .@"64" => 4 + 8,
6403    };
6404}
6405
6406fn sectionOffsetBytes(dwarf: *Dwarf) u32 {
6407    return switch (dwarf.format) {
6408        .@"32" => 4,
6409        .@"64" => 8,
6410    };
6411}
6412
6413fn uleb128Bytes(value: anytype) u32 {
6414    var buf: [64]u8 = undefined;
6415    var dw: Writer.Discarding = .init(&buf);
6416    dw.writer.writeUleb128(value) catch unreachable;
6417    return @intCast(dw.count + dw.writer.end);
6418}
6419
6420fn sleb128Bytes(value: anytype) u32 {
6421    var buf: [64]u8 = undefined;
6422    var dw: Writer.Discarding = .init(&buf);
6423    dw.writer.writeSleb128(value) catch unreachable;
6424    return @intCast(dw.count + dw.writer.end);
6425}
6426
6427/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
6428const force_incremental = false;
6429inline fn incremental(dwarf: Dwarf) bool {
6430    return force_incremental or dwarf.bin_file.comp.config.incremental;
6431}
6432
6433const Allocator = std.mem.Allocator;
6434const DW = std.dwarf;
6435const Dwarf = @This();
6436const InternPool = @import("../InternPool.zig");
6437const Module = @import("../Package.zig").Module;
6438const Type = @import("../Type.zig");
6439const Value = @import("../Value.zig");
6440const Zcu = @import("../Zcu.zig");
6441const Zir = std.zig.Zir;
6442const assert = std.debug.assert;
6443const codegen = @import("../codegen.zig");
6444const dev = @import("../dev.zig");
6445const link = @import("../link.zig");
6446const log = std.log.scoped(.dwarf);
6447const std = @import("std");
6448const target_info = @import("../target.zig");
6449const Writer = std.Io.Writer;