Commit e046977354

Jacob Young <jacobly0@users.noreply.github.com>
2024-09-09 02:08:44
codegen: implement output to the `.debug_info` section
1 parent 6459212
src/arch/aarch64/CodeGen.zig
@@ -25,7 +25,6 @@ const Alignment = InternPool.Alignment;
 
 const CodeGenError = codegen.CodeGenError;
 const Result = codegen.Result;
-const DebugInfoOutput = codegen.DebugInfoOutput;
 
 const bits = @import("bits.zig");
 const abi = @import("abi.zig");
@@ -48,7 +47,7 @@ pt: Zcu.PerThread,
 air: Air,
 liveness: Liveness,
 bin_file: *link.File,
-debug_output: DebugInfoOutput,
+debug_output: link.File.DebugInfoOutput,
 target: *const std.Target,
 func_index: InternPool.Index,
 owner_nav: InternPool.Nav.Index,
@@ -327,7 +326,7 @@ pub fn generate(
     air: Air,
     liveness: Liveness,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
+    debug_output: link.File.DebugInfoOutput,
 ) CodeGenError!Result {
     const zcu = pt.zcu;
     const gpa = zcu.gpa;
src/arch/aarch64/Emit.zig
@@ -13,11 +13,10 @@ const assert = std.debug.assert;
 const Instruction = bits.Instruction;
 const Register = bits.Register;
 const log = std.log.scoped(.aarch64_emit);
-const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
 
 mir: Mir,
 bin_file: *link.File,
-debug_output: DebugInfoOutput,
+debug_output: link.File.DebugInfoOutput,
 target: *const std.Target,
 err_msg: ?*ErrorMsg = null,
 src_loc: Zcu.LazySrcLoc,
src/arch/arm/CodeGen.zig
@@ -25,7 +25,6 @@ const Alignment = InternPool.Alignment;
 
 const Result = codegen.Result;
 const CodeGenError = codegen.CodeGenError;
-const DebugInfoOutput = codegen.DebugInfoOutput;
 
 const bits = @import("bits.zig");
 const abi = @import("abi.zig");
@@ -49,7 +48,7 @@ pt: Zcu.PerThread,
 air: Air,
 liveness: Liveness,
 bin_file: *link.File,
-debug_output: DebugInfoOutput,
+debug_output: link.File.DebugInfoOutput,
 target: *const std.Target,
 func_index: InternPool.Index,
 err_msg: ?*ErrorMsg,
@@ -335,7 +334,7 @@ pub fn generate(
     air: Air,
     liveness: Liveness,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
+    debug_output: link.File.DebugInfoOutput,
 ) CodeGenError!Result {
     const zcu = pt.zcu;
     const gpa = zcu.gpa;
src/arch/arm/Emit.zig
@@ -16,12 +16,11 @@ const assert = std.debug.assert;
 const Instruction = bits.Instruction;
 const Register = bits.Register;
 const log = std.log.scoped(.aarch32_emit);
-const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
 const CodeGen = @import("CodeGen.zig");
 
 mir: Mir,
 bin_file: *link.File,
-debug_output: DebugInfoOutput,
+debug_output: link.File.DebugInfoOutput,
 target: *const std.Target,
 err_msg: ?*ErrorMsg = null,
 src_loc: Zcu.LazySrcLoc,
src/arch/riscv64/CodeGen.zig
@@ -32,7 +32,6 @@ const Alignment = InternPool.Alignment;
 
 const CodeGenError = codegen.CodeGenError;
 const Result = codegen.Result;
-const DebugInfoOutput = codegen.DebugInfoOutput;
 
 const bits = @import("bits.zig");
 const abi = @import("abi.zig");
@@ -61,7 +60,7 @@ gpa: Allocator,
 
 mod: *Package.Module,
 target: *const std.Target,
-debug_output: DebugInfoOutput,
+debug_output: link.File.DebugInfoOutput,
 err_msg: ?*ErrorMsg,
 args: []MCValue,
 ret_mcv: InstTracking,
@@ -760,7 +759,7 @@ pub fn generate(
     air: Air,
     liveness: Liveness,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
+    debug_output: link.File.DebugInfoOutput,
 ) CodeGenError!Result {
     const zcu = pt.zcu;
     const comp = zcu.comp;
@@ -928,7 +927,7 @@ pub fn generateLazy(
     src_loc: Zcu.LazySrcLoc,
     lazy_sym: link.File.LazySymbol,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
+    debug_output: link.File.DebugInfoOutput,
 ) CodeGenError!Result {
     const comp = bin_file.comp;
     const gpa = comp.gpa;
src/arch/riscv64/Emit.zig
@@ -2,7 +2,7 @@
 
 bin_file: *link.File,
 lower: Lower,
-debug_output: DebugInfoOutput,
+debug_output: link.File.DebugInfoOutput,
 code: *std.ArrayList(u8),
 
 prev_di_line: u32,
@@ -216,7 +216,6 @@ const log = std.log.scoped(.emit);
 const mem = std.mem;
 const std = @import("std");
 
-const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
 const Emit = @This();
 const Lower = @import("Lower.zig");
 const Mir = @import("Mir.zig");
src/arch/sparc64/CodeGen.zig
@@ -22,7 +22,6 @@ const Liveness = @import("../../Liveness.zig");
 const Type = @import("../../Type.zig");
 const CodeGenError = codegen.CodeGenError;
 const Result = @import("../../codegen.zig").Result;
-const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
 const Endian = std.builtin.Endian;
 const Alignment = InternPool.Alignment;
 
@@ -57,7 +56,7 @@ bin_file: *link.File,
 target: *const std.Target,
 func_index: InternPool.Index,
 code: *std.ArrayList(u8),
-debug_output: DebugInfoOutput,
+debug_output: link.File.DebugInfoOutput,
 err_msg: ?*ErrorMsg,
 args: []MCValue,
 ret_mcv: MCValue,
@@ -268,7 +267,7 @@ pub fn generate(
     air: Air,
     liveness: Liveness,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
+    debug_output: link.File.DebugInfoOutput,
 ) CodeGenError!Result {
     const zcu = pt.zcu;
     const gpa = zcu.gpa;
src/arch/sparc64/Emit.zig
@@ -9,7 +9,6 @@ const Zcu = @import("../../Zcu.zig");
 const ErrorMsg = Zcu.ErrorMsg;
 const Liveness = @import("../../Liveness.zig");
 const log = std.log.scoped(.sparcv9_emit);
-const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
 
 const Emit = @This();
 const Mir = @import("Mir.zig");
@@ -19,7 +18,7 @@ const Register = bits.Register;
 
 mir: Mir,
 bin_file: *link.File,
-debug_output: DebugInfoOutput,
+debug_output: link.File.DebugInfoOutput,
 target: *const std.Target,
 err_msg: ?*ErrorMsg = null,
 src_loc: Zcu.LazySrcLoc,
src/arch/wasm/CodeGen.zig
@@ -648,7 +648,7 @@ block_depth: u32 = 0,
 air: Air,
 liveness: Liveness,
 gpa: mem.Allocator,
-debug_output: codegen.DebugInfoOutput,
+debug_output: link.File.DebugInfoOutput,
 func_index: InternPool.Index,
 /// Contains a list of current branches.
 /// When we return from a branch, the branch will be popped from this list,
@@ -1211,7 +1211,7 @@ pub fn generate(
     air: Air,
     liveness: Liveness,
     code: *std.ArrayList(u8),
-    debug_output: codegen.DebugInfoOutput,
+    debug_output: link.File.DebugInfoOutput,
 ) codegen.CodeGenError!codegen.Result {
     const zcu = pt.zcu;
     const gpa = zcu.gpa;
src/arch/wasm/Emit.zig
@@ -26,7 +26,7 @@ owner_nav: InternPool.Nav.Index,
 
 // Debug information
 /// Holds the debug information for this emission
-dbg_output: codegen.DebugInfoOutput,
+dbg_output: link.File.DebugInfoOutput,
 /// Previous debug info line
 prev_di_line: u32,
 /// Previous debug info column
src/arch/x86_64/CodeGen.zig
@@ -17,7 +17,6 @@ const Air = @import("../../Air.zig");
 const Allocator = mem.Allocator;
 const CodeGenError = codegen.CodeGenError;
 const Compilation = @import("../../Compilation.zig");
-const DebugInfoOutput = codegen.DebugInfoOutput;
 const ErrorMsg = Zcu.ErrorMsg;
 const Result = codegen.Result;
 const Emit = @import("Emit.zig");
@@ -53,7 +52,7 @@ pt: Zcu.PerThread,
 air: Air,
 liveness: Liveness,
 bin_file: *link.File,
-debug_output: DebugInfoOutput,
+debug_output: link.File.DebugInfoOutput,
 target: *const std.Target,
 owner: Owner,
 inline_func: InternPool.Index,
@@ -819,7 +818,7 @@ pub fn generate(
     air: Air,
     liveness: Liveness,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
+    debug_output: link.File.DebugInfoOutput,
 ) CodeGenError!Result {
     const zcu = pt.zcu;
     const comp = zcu.comp;
@@ -1000,7 +999,7 @@ pub fn generateLazy(
     src_loc: Zcu.LazySrcLoc,
     lazy_sym: link.File.LazySymbol,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
+    debug_output: link.File.DebugInfoOutput,
 ) CodeGenError!Result {
     const comp = bin_file.comp;
     const gpa = comp.gpa;
src/arch/x86_64/Emit.zig
@@ -3,7 +3,7 @@
 air: Air,
 lower: Lower,
 atom_index: u32,
-debug_output: DebugInfoOutput,
+debug_output: link.File.DebugInfoOutput,
 code: *std.ArrayList(u8),
 
 prev_di_line: u32,
@@ -546,7 +546,6 @@ const log = std.log.scoped(.emit);
 const std = @import("std");
 
 const Air = @import("../../Air.zig");
-const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
 const Emit = @This();
 const Lower = @import("Lower.zig");
 const Mir = @import("Mir.zig");
src/link/Elf/ZigObject.zig
@@ -957,13 +957,26 @@ pub fn getNavVAddr(
     };
     const this_sym = self.symbol(this_sym_index);
     const vaddr = this_sym.address(.{}, elf_file);
-    const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
-    const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
-    try parent_atom.addReloc(elf_file.base.comp.gpa, .{
-        .r_offset = reloc_info.offset,
-        .r_info = (@as(u64, @intCast(this_sym_index)) << 32) | r_type,
-        .r_addend = reloc_info.addend,
-    }, self);
+    switch (reloc_info.parent) {
+        .atom_index => |atom_index| {
+            const parent_atom = self.symbol(atom_index).atom(elf_file).?;
+            const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
+            try parent_atom.addReloc(elf_file.base.comp.gpa, .{
+                .r_offset = reloc_info.offset,
+                .r_info = (@as(u64, @intCast(this_sym_index)) << 32) | r_type,
+                .r_addend = reloc_info.addend,
+            }, self);
+        },
+        .debug_output => |debug_output| switch (debug_output) {
+            .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
+                .source_off = @intCast(reloc_info.offset),
+                .target_sym = this_sym_index,
+                .target_off = reloc_info.addend,
+            }),
+            .plan9 => unreachable,
+            .none => unreachable,
+        },
+    }
     return @intCast(vaddr);
 }
 
@@ -976,13 +989,26 @@ pub fn getUavVAddr(
     const sym_index = self.uavs.get(uav).?.symbol_index;
     const sym = self.symbol(sym_index);
     const vaddr = sym.address(.{}, elf_file);
-    const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
-    const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
-    try parent_atom.addReloc(elf_file.base.comp.gpa, .{
-        .r_offset = reloc_info.offset,
-        .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
-        .r_addend = reloc_info.addend,
-    }, self);
+    switch (reloc_info.parent) {
+        .atom_index => |atom_index| {
+            const parent_atom = self.symbol(atom_index).atom(elf_file).?;
+            const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
+            try parent_atom.addReloc(elf_file.base.comp.gpa, .{
+                .r_offset = reloc_info.offset,
+                .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
+                .r_addend = reloc_info.addend,
+            }, self);
+        },
+        .debug_output => |debug_output| switch (debug_output) {
+            .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
+                .source_off = @intCast(reloc_info.offset),
+                .target_sym = sym_index,
+                .target_off = reloc_info.addend,
+            }),
+            .plan9 => unreachable,
+            .none => unreachable,
+        },
+    }
     return @intCast(vaddr);
 }
 
@@ -1600,15 +1626,13 @@ pub fn updateNav(
         var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null;
         defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
 
-        // TODO implement .debug_info for global variables
         const res = try codegen.generateSymbol(
             &elf_file.base,
             pt,
             zcu.navSrcLoc(nav_index),
             Value.fromInterned(nav_init),
             &code_buffer,
-            if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
-            .{ .parent_atom_index = sym_index },
+            .{ .atom_index = sym_index },
         );
 
         const code = switch (res) {
@@ -1691,7 +1715,7 @@ fn updateLazySymbol(
         &required_alignment,
         &code_buffer,
         .none,
-        .{ .parent_atom_index = symbol_index },
+        .{ .atom_index = symbol_index },
     );
     const code = switch (res) {
         .ok => code_buffer.items,
@@ -1780,8 +1804,7 @@ fn lowerConst(
         src_loc,
         val,
         &code_buffer,
-        .{ .none = {} },
-        .{ .parent_atom_index = sym_index },
+        .{ .atom_index = sym_index },
     );
     const code = switch (res) {
         .ok => code_buffer.items,
src/link/MachO/ZigObject.zig
@@ -633,20 +633,33 @@ pub fn getNavVAddr(
     };
     const sym = self.symbols.items[sym_index];
     const vaddr = sym.getAddress(.{}, macho_file);
-    const parent_atom = self.symbols.items[reloc_info.parent_atom_index].getAtom(macho_file).?;
-    try parent_atom.addReloc(macho_file, .{
-        .tag = .@"extern",
-        .offset = @intCast(reloc_info.offset),
-        .target = sym_index,
-        .addend = reloc_info.addend,
-        .type = .unsigned,
-        .meta = .{
-            .pcrel = false,
-            .has_subtractor = false,
-            .length = 3,
-            .symbolnum = @intCast(sym.nlist_idx),
+    switch (reloc_info.parent) {
+        .atom_index => |atom_index| {
+            const parent_atom = self.symbols.items[atom_index].getAtom(macho_file).?;
+            try parent_atom.addReloc(macho_file, .{
+                .tag = .@"extern",
+                .offset = @intCast(reloc_info.offset),
+                .target = sym_index,
+                .addend = reloc_info.addend,
+                .type = .unsigned,
+                .meta = .{
+                    .pcrel = false,
+                    .has_subtractor = false,
+                    .length = 3,
+                    .symbolnum = @intCast(sym.nlist_idx),
+                },
+            });
         },
-    });
+        .debug_output => |debug_output| switch (debug_output) {
+            .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
+                .source_off = @intCast(reloc_info.offset),
+                .target_sym = sym_index,
+                .target_off = reloc_info.addend,
+            }),
+            .plan9 => unreachable,
+            .none => unreachable,
+        },
+    }
     return vaddr;
 }
 
@@ -659,20 +672,33 @@ pub fn getUavVAddr(
     const sym_index = self.uavs.get(uav).?.symbol_index;
     const sym = self.symbols.items[sym_index];
     const vaddr = sym.getAddress(.{}, macho_file);
-    const parent_atom = self.symbols.items[reloc_info.parent_atom_index].getAtom(macho_file).?;
-    try parent_atom.addReloc(macho_file, .{
-        .tag = .@"extern",
-        .offset = @intCast(reloc_info.offset),
-        .target = sym_index,
-        .addend = reloc_info.addend,
-        .type = .unsigned,
-        .meta = .{
-            .pcrel = false,
-            .has_subtractor = false,
-            .length = 3,
-            .symbolnum = @intCast(sym.nlist_idx),
+    switch (reloc_info.parent) {
+        .atom_index => |atom_index| {
+            const parent_atom = self.symbols.items[atom_index].getAtom(macho_file).?;
+            try parent_atom.addReloc(macho_file, .{
+                .tag = .@"extern",
+                .offset = @intCast(reloc_info.offset),
+                .target = sym_index,
+                .addend = reloc_info.addend,
+                .type = .unsigned,
+                .meta = .{
+                    .pcrel = false,
+                    .has_subtractor = false,
+                    .length = 3,
+                    .symbolnum = @intCast(sym.nlist_idx),
+                },
+            });
         },
-    });
+        .debug_output => |debug_output| switch (debug_output) {
+            .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
+                .source_off = @intCast(reloc_info.offset),
+                .target_sym = sym_index,
+                .target_off = reloc_info.addend,
+            }),
+            .plan9 => unreachable,
+            .none => unreachable,
+        },
+    }
     return vaddr;
 }
 
@@ -903,8 +929,7 @@ pub fn updateNav(
             zcu.navSrcLoc(nav_index),
             Value.fromInterned(nav_init),
             &code_buffer,
-            if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
-            .{ .parent_atom_index = sym_index },
+            .{ .atom_index = sym_index },
         );
 
         const code = switch (res) {
@@ -1212,11 +1237,14 @@ fn lowerConst(
     const name_str = try self.addString(gpa, name);
     const sym_index = try self.newSymbolWithAtom(gpa, name_str, macho_file);
 
-    const res = try codegen.generateSymbol(&macho_file.base, pt, src_loc, val, &code_buffer, .{
-        .none = {},
-    }, .{
-        .parent_atom_index = sym_index,
-    });
+    const res = try codegen.generateSymbol(
+        &macho_file.base,
+        pt,
+        src_loc,
+        val,
+        &code_buffer,
+        .{ .atom_index = sym_index },
+    );
     const code = switch (res) {
         .ok => code_buffer.items,
         .fail => |em| return .{ .fail = em },
@@ -1378,7 +1406,7 @@ fn updateLazySymbol(
         &required_alignment,
         &code_buffer,
         .none,
-        .{ .parent_atom_index = symbol_index },
+        .{ .atom_index = symbol_index },
     );
     const code = switch (res) {
         .ok => code_buffer.items,
src/link/Wasm/ZigObject.zig
@@ -277,8 +277,7 @@ pub fn updateNav(
             zcu.navSrcLoc(nav_index),
             nav_init,
             &code_writer,
-            .none,
-            .{ .parent_atom_index = @intFromEnum(atom.sym_index) },
+            .{ .atom_index = @intFromEnum(atom.sym_index) },
         );
 
         const code = switch (res) {
@@ -520,10 +519,7 @@ fn lowerConst(
             src_loc,
             val,
             &value_bytes,
-            .none,
-            .{
-                .parent_atom_index = @intFromEnum(atom.sym_index),
-            },
+            .{ .atom_index = @intFromEnum(atom.sym_index) },
         );
         break :code switch (result) {
             .ok => value_bytes.items,
@@ -762,8 +758,11 @@ pub fn getNavVAddr(
         else => {},
     }
 
-    std.debug.assert(reloc_info.parent_atom_index != 0);
-    const atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = @enumFromInt(reloc_info.parent_atom_index) }).?;
+    std.debug.assert(reloc_info.parent.atom_index != 0);
+    const atom_index = wasm_file.symbol_atom.get(.{
+        .file = zig_object.index,
+        .index = @enumFromInt(reloc_info.parent.atom_index),
+    }).?;
     const atom = wasm_file.getAtomPtr(atom_index);
     const is_wasm32 = target.cpu.arch == .wasm32;
     if (ip.isFunctionType(ip.getNav(nav_index).typeOf(ip))) {
@@ -800,7 +799,10 @@ pub fn getUavVAddr(
     const atom_index = zig_object.uavs.get(uav).?;
     const target_symbol_index = @intFromEnum(wasm_file.getAtom(atom_index).sym_index);
 
-    const parent_atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = @enumFromInt(reloc_info.parent_atom_index) }).?;
+    const parent_atom_index = wasm_file.symbol_atom.get(.{
+        .file = zig_object.index,
+        .index = @enumFromInt(reloc_info.parent.atom_index),
+    }).?;
     const parent_atom = wasm_file.getAtomPtr(parent_atom_index);
     const is_wasm32 = target.cpu.arch == .wasm32;
     const zcu = wasm_file.base.comp.zcu.?;
src/link/Coff.zig
@@ -1163,8 +1163,8 @@ fn lowerConst(
     try self.setSymbolName(sym, name);
     sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_id + 1));
 
-    const res = try codegen.generateSymbol(&self.base, pt, src_loc, val, &code_buffer, .none, .{
-        .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,
+    const res = try codegen.generateSymbol(&self.base, pt, src_loc, val, &code_buffer, .{
+        .atom_index = self.getAtom(atom_index).getSymbolIndex().?,
     });
     const code = switch (res) {
         .ok => code_buffer.items,
@@ -1235,8 +1235,7 @@ pub fn updateNav(
             zcu.navSrcLoc(nav_index),
             nav_init,
             &code_buffer,
-            .none,
-            .{ .parent_atom_index = atom.getSymbolIndex().? },
+            .{ .atom_index = atom.getSymbolIndex().? },
         );
         const code = switch (res) {
             .ok => code_buffer.items,
@@ -1284,7 +1283,7 @@ fn updateLazySymbolAtom(
         &required_alignment,
         &code_buffer,
         .none,
-        .{ .parent_atom_index = local_sym_index },
+        .{ .atom_index = local_sym_index },
     );
     const code = switch (res) {
         .ok => code_buffer.items,
@@ -1823,7 +1822,10 @@ pub fn getNavVAddr(
         .@"extern" => |@"extern"| try self.getGlobalSymbol(nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip)),
         else => self.getAtom(try self.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?,
     };
-    const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
+    const atom_index = self.getAtomIndexForSymbol(.{
+        .sym_index = reloc_info.parent.atom_index,
+        .file = null,
+    }).?;
     const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
     try Atom.addRelocation(self, atom_index, .{
         .type = .direct,
@@ -1901,7 +1903,10 @@ pub fn getUavVAddr(
 
     const this_atom_index = self.uavs.get(uav).?.atom;
     const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
-    const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
+    const atom_index = self.getAtomIndexForSymbol(.{
+        .sym_index = reloc_info.parent.atom_index,
+        .file = null,
+    }).?;
     const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
     try Atom.addRelocation(self, atom_index, .{
         .type = .direct,
src/link/Dwarf.zig
@@ -19,8 +19,8 @@ debug_rnglists: DebugRngLists,
 debug_str: StringSection,
 
 pub const UpdateError = error{
+    CodegenFail,
     ReinterpretDeclRef,
-    IllDefinedMemoryLayout,
     Unimplemented,
     OutOfMemory,
     EndOfStream,
@@ -1584,6 +1584,18 @@ pub const WipNav = struct {
         wip_nav.func = func;
     }
 
+    fn externalReloc(wip_nav: *WipNav, sec: *Section, reloc: ExternalReloc) std.mem.Allocator.Error!void {
+        try sec.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(wip_nav.dwarf.gpa, reloc);
+    }
+
+    pub fn infoExternalReloc(wip_nav: *WipNav, reloc: ExternalReloc) std.mem.Allocator.Error!void {
+        try wip_nav.externalReloc(&wip_nav.dwarf.debug_info.section, reloc);
+    }
+
+    fn frameExternalReloc(wip_nav: *WipNav, reloc: ExternalReloc) std.mem.Allocator.Error!void {
+        try wip_nav.externalReloc(&wip_nav.dwarf.debug_frame.section, reloc);
+    }
+
     fn abbrevCode(wip_nav: *WipNav, abbrev_code: AbbrevCode) UpdateError!void {
         try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), try wip_nav.dwarf.refAbbrevCode(abbrev_code));
     }
@@ -1660,12 +1672,11 @@ pub const WipNav = struct {
     }
 
     fn infoAddrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void {
-        const dwarf = wip_nav.dwarf;
-        try dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
+        try wip_nav.infoExternalReloc(.{
             .source_off = @intCast(wip_nav.debug_info.items.len),
             .target_sym = sym_index,
         });
-        try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, @intFromEnum(dwarf.address_size));
+        try wip_nav.debug_info.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));
     }
 
     fn frameExprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
@@ -1692,12 +1703,11 @@ pub const WipNav = struct {
     }
 
     fn frameAddrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void {
-        const dwarf = wip_nav.dwarf;
-        try dwarf.debug_frame.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
+        try wip_nav.frameExternalReloc(.{
             .source_off = @intCast(wip_nav.debug_frame.items.len),
             .target_sym = sym_index,
         });
-        try wip_nav.debug_frame.appendNTimes(dwarf.gpa, 0, @intFromEnum(dwarf.address_size));
+        try wip_nav.debug_frame.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));
     }
 
     fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } {
@@ -1749,6 +1759,27 @@ pub const WipNav = struct {
         reloc.target_off = @intCast(wip_nav.debug_info.items.len);
     }
 
+    fn blockValue(wip_nav: *WipNav, src_loc: Zcu.LazySrcLoc, val: Value) UpdateError!void {
+        const ty = val.typeOf(wip_nav.pt.zcu);
+        const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
+        const bytes = ty.abiSize(wip_nav.pt.zcu);
+        try uleb128(diw, bytes);
+        if (bytes == 0) return;
+        var dim = wip_nav.debug_info.toManaged(wip_nav.dwarf.gpa);
+        defer wip_nav.debug_info = dim.moveToUnmanaged();
+        switch (try codegen.generateSymbol(
+            wip_nav.dwarf.bin_file,
+            wip_nav.pt,
+            src_loc,
+            val,
+            &dim,
+            .{ .debug_output = .{ .dwarf = wip_nav } },
+        )) {
+            .ok => assert(dim.items.len == wip_nav.debug_info.items.len + bytes),
+            .fail => unreachable,
+        }
+    }
+
     fn enumConstValue(
         wip_nav: *WipNav,
         loaded_enum: InternPool.LoadedEnumType,
@@ -1814,8 +1845,8 @@ pub const WipNav = struct {
         }
     }
 
-    fn flush(wip_nav: *WipNav) UpdateError!void {
-        while (wip_nav.pending_types.popOrNull()) |ty| try wip_nav.dwarf.updateType(wip_nav.pt, ty, &wip_nav.pending_types);
+    fn flush(wip_nav: *WipNav, src_loc: Zcu.LazySrcLoc) UpdateError!void {
+        while (wip_nav.pending_types.popOrNull()) |ty| try wip_nav.dwarf.updateType(wip_nav.pt, src_loc, ty, &wip_nav.pending_types);
     }
 };
 
@@ -2171,15 +2202,15 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
             try diw.writeByte(accessibility);
             try wip_nav.strp(nav.name.toSlice(ip));
             try wip_nav.strp(nav.fqn.toSlice(ip));
-            const ty = nav_val.typeOf(zcu);
-            const ty_reloc_index = try wip_nav.refForward();
+            const nav_ty = nav_val.typeOf(zcu);
+            const nav_ty_reloc_index = try wip_nav.refForward();
             try wip_nav.exprloc(.{ .addr = .{ .sym = sym_index } });
             try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
-                ty.abiAlignment(zcu).toByteUnits().?);
+                nav_ty.abiAlignment(zcu).toByteUnits().?);
             try diw.writeByte(@intFromBool(false));
-            wip_nav.finishForward(ty_reloc_index);
+            wip_nav.finishForward(nav_ty_reloc_index);
             try wip_nav.abbrevCode(.is_const);
-            try wip_nav.refType(ty);
+            try wip_nav.refType(nav_ty);
         },
         .variable => |variable| {
             assert(file.zir_loaded);
@@ -2288,20 +2319,16 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
                                 .source_off = @intCast(wip_nav.debug_frame.items.len),
                             });
                             try dfw.writeByteNTimes(0, dwarf.sectionOffsetBytes());
-                            try entry.external_relocs.append(dwarf.gpa, .{
-                                .source_off = @intCast(wip_nav.debug_frame.items.len),
-                                .target_sym = sym_index,
-                            });
-                            try dfw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
+                            try wip_nav.frameAddrSym(sym_index);
                             try dfw.writeByteNTimes(undefined, @intFromEnum(dwarf.address_size));
                         },
                         .eh_frame => {
                             try dfw.writeInt(u32, undefined, dwarf.endian);
-                            try entry.external_relocs.append(dwarf.gpa, .{
+                            try wip_nav.frameExternalReloc(.{
                                 .source_off = @intCast(wip_nav.debug_frame.items.len),
                                 .target_sym = sym_index,
                             });
-                            try dfw.writeByteNTimes(0, dwarf.sectionOffsetBytes());
+                            try dfw.writeInt(u32, 0, dwarf.endian);
                             try dfw.writeInt(u32, undefined, dwarf.endian);
                             try uleb128(dfw, 0);
                         },
@@ -2481,12 +2508,13 @@ pub fn finishWipNav(
     }
     try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items);
 
-    try wip_nav.flush();
+    try wip_nav.flush(zcu.navSrcLoc(nav_index));
 }
 
 pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateError!void {
     const zcu = pt.zcu;
     const ip = &zcu.intern_pool;
+    const nav_src_loc = zcu.navSrcLoc(nav_index);
     const nav_val = zcu.navValue(nav_index);
 
     const nav = ip.getNav(nav_index);
@@ -2548,7 +2576,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
     const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
     errdefer _ = dwarf.navs.pop();
 
-    const tag: enum { done, decl_alias } = switch (ip.indexToKey(nav_val.toIntern())) {
+    const tag: enum { done, decl_alias, decl_const } = switch (ip.indexToKey(nav_val.toIntern())) {
         .int_type,
         .ptr_type,
         .array_type,
@@ -2623,7 +2651,10 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                             }
                             const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
                             try wip_nav.refType(field_type);
-                            if (!is_comptime) {
+                            if (is_comptime) try wip_nav.blockValue(
+                                nav_src_loc,
+                                Value.fromInterned(loaded_struct.fieldInit(ip, field_index)),
+                            ) else {
                                 try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
                                 try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
                                     field_type.abiAlignment(zcu).toByteUnits().?);
@@ -2850,7 +2881,6 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
         },
         .undef,
         .simple_value,
-        .variable,
         .@"extern",
         .int,
         .err,
@@ -2864,10 +2894,8 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
         .opt,
         .aggregate,
         .un,
-        => {
-            _ = dwarf.navs.pop();
-            return;
-        },
+        => .decl_const,
+        .variable => unreachable,
         .func => |func| tag: {
             if (nav_gop.found_existing) {
                 const unit_ptr = dwarf.debug_info.section.getUnit(wip_nav.unit);
@@ -2918,14 +2946,16 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
         // memoization, not types
         .memoized_call => unreachable,
     };
+    if (tag != .done) {
+        if (nav_gop.found_existing)
+            dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+        else
+            nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
+        wip_nav.entry = nav_gop.value_ptr.*;
+    }
     switch (tag) {
         .done => {},
         .decl_alias => {
-            if (nav_gop.found_existing)
-                dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
-            else
-                nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
-            wip_nav.entry = nav_gop.value_ptr.*;
             const diw = wip_nav.debug_info.writer(dwarf.gpa);
             try wip_nav.abbrevCode(.decl_alias);
             try wip_nav.refType(Type.fromInterned(parent_type));
@@ -2936,14 +2966,35 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
             try wip_nav.strp(nav.name.toSlice(ip));
             try wip_nav.refType(nav_val.toType());
         },
+        .decl_const => {
+            const diw = wip_nav.debug_info.writer(dwarf.gpa);
+            try wip_nav.abbrevCode(.decl_const);
+            try wip_nav.refType(Type.fromInterned(parent_type));
+            assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
+            try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
+            try uleb128(diw, loc.column + 1);
+            try diw.writeByte(accessibility);
+            try wip_nav.strp(nav.name.toSlice(ip));
+            try wip_nav.strp(nav.fqn.toSlice(ip));
+            const nav_ty = nav_val.typeOf(zcu);
+            const nav_ty_reloc_index = try wip_nav.refForward();
+            try wip_nav.blockValue(nav_src_loc, nav_val);
+            try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
+                nav_ty.abiAlignment(zcu).toByteUnits().?);
+            try diw.writeByte(@intFromBool(false));
+            wip_nav.finishForward(nav_ty_reloc_index);
+            try wip_nav.abbrevCode(.is_const);
+            try wip_nav.refType(nav_ty);
+        },
     }
     try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
-    try wip_nav.flush();
+    try wip_nav.flush(nav_src_loc);
 }
 
 fn updateType(
     dwarf: *Dwarf,
     pt: Zcu.PerThread,
+    src_loc: Zcu.LazySrcLoc,
     type_index: InternPool.Index,
     pending_types: *std.ArrayListUnmanaged(InternPool.Index),
 ) UpdateError!void {
@@ -3000,15 +3051,10 @@ fn updateType(
                 const ptr_child_type = Type.fromInterned(ptr_type.child);
                 try wip_nav.abbrevCode(if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type);
                 try wip_nav.strp(name);
-                if (ptr_type.sentinel != .none) {
-                    const bytes = ptr_child_type.abiSize(zcu);
-                    try uleb128(diw, bytes);
-                    const mem = try wip_nav.debug_info.addManyAsSlice(dwarf.gpa, @intCast(bytes));
-                    Value.fromInterned(ptr_type.sentinel).writeToMemory(pt, mem) catch |err| switch (err) {
-                        error.IllDefinedMemoryLayout => @memset(mem, 0),
-                        else => |e| return e,
-                    };
-                }
+                if (ptr_type.sentinel != .none) try wip_nav.blockValue(
+                    src_loc,
+                    Value.fromInterned(ptr_type.sentinel),
+                );
                 try uleb128(diw, ptr_type.flags.alignment.toByteUnits() orelse
                     ptr_child_type.abiAlignment(zcu).toByteUnits().?);
                 try diw.writeByte(@intFromEnum(ptr_type.flags.address_space));
@@ -3054,15 +3100,10 @@ fn updateType(
             const array_child_type = Type.fromInterned(array_type.child);
             try wip_nav.abbrevCode(if (array_type.sentinel == .none) .array_type else .array_sentinel_type);
             try wip_nav.strp(name);
-            if (array_type.sentinel != .none) {
-                const bytes = array_child_type.abiSize(zcu);
-                try uleb128(diw, bytes);
-                const mem = try wip_nav.debug_info.addManyAsSlice(dwarf.gpa, @intCast(bytes));
-                Value.fromInterned(array_type.sentinel).writeToMemory(pt, mem) catch |err| switch (err) {
-                    error.IllDefinedMemoryLayout => @memset(mem, 0),
-                    else => |e| return e,
-                };
-            }
+            if (array_type.sentinel != .none) try wip_nav.blockValue(
+                src_loc,
+                Value.fromInterned(array_type.sentinel),
+            );
             try wip_nav.refType(array_child_type);
             try wip_nav.abbrevCode(.array_index);
             try wip_nav.refType(Type.usize);
@@ -3292,7 +3333,10 @@ fn updateType(
                 }
                 const field_type = Type.fromInterned(anon_struct_type.types.get(ip)[field_index]);
                 try wip_nav.refType(field_type);
-                if (comptime_value == .none) {
+                if (comptime_value != .none) try wip_nav.blockValue(
+                    src_loc,
+                    Value.fromInterned(comptime_value),
+                ) else {
                     const field_align = field_type.abiAlignment(zcu);
                     field_byte_offset = field_align.forward(field_byte_offset);
                     try uleb128(diw, field_byte_offset);
@@ -3359,16 +3403,13 @@ fn updateType(
             }
             if (error_set_type.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
         },
-        .inferred_error_set_type => |func| switch (ip.funcIesResolvedUnordered(func)) {
-            .none => {
-                try wip_nav.abbrevCode(.void_type);
-                try wip_nav.strp(name);
-            },
-            else => |ies| {
-                try wip_nav.abbrevCode(.inferred_error_set_type);
-                try wip_nav.strp(name);
-                try wip_nav.refType(Type.fromInterned(ies));
-            },
+        .inferred_error_set_type => |func| {
+            try wip_nav.abbrevCode(.inferred_error_set_type);
+            try wip_nav.strp(name);
+            try wip_nav.refType(Type.fromInterned(switch (ip.funcIesResolvedUnordered(func)) {
+                .none => .anyerror_type,
+                else => |ies| ies,
+            }));
         },
 
         // values, not types
@@ -3400,6 +3441,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
     const zcu = pt.zcu;
     const ip = &zcu.intern_pool;
     const ty = Type.fromInterned(type_index);
+    const ty_src_loc = ty.srcLoc(zcu);
     log.debug("updateContainerType({}({d}))", .{ ty.fmt(pt), @intFromEnum(type_index) });
 
     const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip).?;
@@ -3447,7 +3489,10 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
                 }
                 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
                 try wip_nav.refType(field_type);
-                if (!is_comptime) {
+                if (is_comptime) try wip_nav.blockValue(
+                    ty_src_loc,
+                    Value.fromInterned(loaded_struct.fieldInit(ip, field_index)),
+                ) else {
                     try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
                     try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
                         field_type.abiAlignment(zcu).toByteUnits().?);
@@ -3457,7 +3502,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
         }
 
         try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
-        try wip_nav.flush();
+        try wip_nav.flush(ty_src_loc);
     } else {
         const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
         assert(decl_inst.tag == .extended);
@@ -3515,7 +3560,10 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
                                 }
                                 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
                                 try wip_nav.refType(field_type);
-                                if (!is_comptime) {
+                                if (is_comptime) try wip_nav.blockValue(
+                                    ty_src_loc,
+                                    Value.fromInterned(loaded_struct.fieldInit(ip, field_index)),
+                                ) else {
                                     try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
                                     try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
                                         field_type.abiAlignment(zcu).toByteUnits().?);
@@ -3616,7 +3664,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
         }
         try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
         try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items);
-        try wip_nav.flush();
+        try wip_nav.flush(ty_src_loc);
     }
 }
 
@@ -4085,6 +4133,7 @@ const AbbrevCode = enum {
     decl_packed_struct,
     decl_union,
     decl_var,
+    decl_const,
     decl_func,
     decl_empty_func,
     decl_func_generic,
@@ -4220,6 +4269,16 @@ const AbbrevCode = enum {
                 .{ .external, .flag },
             },
         },
+        .decl_const = .{
+            .tag = .constant,
+            .attrs = decl_abbrev_common_attrs ++ .{
+                .{ .linkage_name, .strp },
+                .{ .type, .ref_addr },
+                .{ .const_value, .block },
+                .{ .alignment, .udata },
+                .{ .external, .flag },
+            },
+        },
         .decl_func = .{
             .tag = .subprogram,
             .children = true,
@@ -4339,9 +4398,10 @@ const AbbrevCode = enum {
         .struct_field_comptime = .{
             .tag = .member,
             .attrs = &.{
+                .{ .const_expr, .flag_present },
                 .{ .name, .strp },
                 .{ .type, .ref_addr },
-                .{ .const_expr, .flag_present },
+                .{ .default_value, .block },
             },
         },
         .packed_struct_field = .{
src/link/Plan9.zig
@@ -422,10 +422,7 @@ pub fn updateFunc(self: *Plan9, pt: Zcu.PerThread, func_index: InternPool.Index,
     );
     const code = switch (res) {
         .ok => try code_buffer.toOwnedSlice(),
-        .fail => |em| {
-            try zcu.failed_codegen.put(gpa, func.owner_nav, em);
-            return;
-        },
+        .fail => |em| return zcu.failed_codegen.put(gpa, func.owner_nav, em),
     };
     self.getAtomPtr(atom_idx).code = .{
         .code_ptr = null,
@@ -463,15 +460,17 @@ pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
         var code_buffer = std.ArrayList(u8).init(gpa);
         defer code_buffer.deinit();
         // TODO we need the symbol index for symbol in the table of locals for the containing atom
-        const res = try codegen.generateSymbol(&self.base, pt, zcu.navSrcLoc(nav_index), nav_init, &code_buffer, .none, .{
-            .parent_atom_index = @intCast(atom_idx),
-        });
+        const res = try codegen.generateSymbol(
+            &self.base,
+            pt,
+            zcu.navSrcLoc(nav_index),
+            nav_init,
+            &code_buffer,
+            .{ .atom_index = @intCast(atom_idx) },
+        );
         const code = switch (res) {
             .ok => code_buffer.items,
-            .fail => |em| {
-                try zcu.failed_codegen.put(gpa, nav_index, em);
-                return;
-            },
+            .fail => |em| return zcu.failed_codegen.put(gpa, nav_index, em),
         };
         try self.data_nav_table.ensureUnusedCapacity(gpa, 1);
         const duped_code = try gpa.dupe(u8, code);
@@ -1116,7 +1115,7 @@ fn updateLazySymbolAtom(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol, a
         &required_alignment,
         &code_buffer,
         .none,
-        .{ .parent_atom_index = @as(Atom.Index, @intCast(atom_index)) },
+        .{ .atom_index = @intCast(atom_index) },
     );
     const code = switch (res) {
         .ok => code_buffer.items,
@@ -1373,21 +1372,21 @@ pub fn getNavVAddr(
     log.debug("getDeclVAddr for {}", .{nav.name.fmt(ip)});
     if (ip.indexToKey(nav.status.resolved.val) == .@"extern") {
         if (nav.name.eqlSlice("etext", ip)) {
-            try self.addReloc(reloc_info.parent_atom_index, .{
+            try self.addReloc(reloc_info.parent.atom_index, .{
                 .target = undefined,
                 .offset = reloc_info.offset,
                 .addend = reloc_info.addend,
                 .type = .special_etext,
             });
         } else if (nav.name.eqlSlice("edata", ip)) {
-            try self.addReloc(reloc_info.parent_atom_index, .{
+            try self.addReloc(reloc_info.parent.atom_index, .{
                 .target = undefined,
                 .offset = reloc_info.offset,
                 .addend = reloc_info.addend,
                 .type = .special_edata,
             });
         } else if (nav.name.eqlSlice("end", ip)) {
-            try self.addReloc(reloc_info.parent_atom_index, .{
+            try self.addReloc(reloc_info.parent.atom_index, .{
                 .target = undefined,
                 .offset = reloc_info.offset,
                 .addend = reloc_info.addend,
@@ -1400,7 +1399,7 @@ pub fn getNavVAddr(
     // otherwise, we just add a relocation
     const atom_index = try self.seeNav(pt, nav_index);
     // the parent_atom_index in this case is just the decl_index of the parent
-    try self.addReloc(reloc_info.parent_atom_index, .{
+    try self.addReloc(reloc_info.parent.atom_index, .{
         .target = atom_index,
         .offset = reloc_info.offset,
         .addend = reloc_info.addend,
@@ -1435,7 +1434,7 @@ pub fn lowerUav(
     gop.value_ptr.* = index;
     // we need to free name latex
     var code_buffer = std.ArrayList(u8).init(gpa);
-    const res = try codegen.generateSymbol(&self.base, pt, src_loc, val, &code_buffer, .{ .none = {} }, .{ .parent_atom_index = index });
+    const res = try codegen.generateSymbol(&self.base, pt, src_loc, val, &code_buffer, .{ .atom_index = index });
     const code = switch (res) {
         .ok => code_buffer.items,
         .fail => |em| return .{ .fail = em },
@@ -1459,7 +1458,7 @@ pub fn lowerUav(
 
 pub fn getUavVAddr(self: *Plan9, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
     const atom_index = self.uavs.get(uav).?;
-    try self.addReloc(reloc_info.parent_atom_index, .{
+    try self.addReloc(reloc_info.parent.atom_index, .{
         .target = atom_index,
         .offset = reloc_info.offset,
         .addend = reloc_info.addend,
src/codegen.zig
@@ -38,12 +38,6 @@ pub const CodeGenError = error{
     CodegenFail,
 } || link.File.UpdateDebugInfoError;
 
-pub const DebugInfoOutput = union(enum) {
-    dwarf: *link.File.Dwarf.WipNav,
-    plan9: *link.File.Plan9.DebugInfoOutput,
-    none,
-};
-
 fn devFeatureForBackend(comptime backend: std.builtin.CompilerBackend) dev.Feature {
     comptime assert(mem.startsWith(u8, @tagName(backend), "stage2_"));
     return @field(dev.Feature, @tagName(backend)["stage2_".len..] ++ "_backend");
@@ -69,7 +63,7 @@ pub fn generateFunction(
     air: Air,
     liveness: Liveness,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
+    debug_output: link.File.DebugInfoOutput,
 ) CodeGenError!Result {
     const zcu = pt.zcu;
     const func = zcu.funcInfo(func_index);
@@ -95,7 +89,7 @@ pub fn generateLazyFunction(
     src_loc: Zcu.LazySrcLoc,
     lazy_sym: link.File.LazySymbol,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
+    debug_output: link.File.DebugInfoOutput,
 ) CodeGenError!Result {
     const zcu = pt.zcu;
     const file = Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(&zcu.intern_pool);
@@ -127,10 +121,10 @@ pub fn generateLazySymbol(
     // TODO don't use an "out" parameter like this; put it in the result instead
     alignment: *Alignment,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
-    reloc_info: RelocInfo,
+    debug_output: link.File.DebugInfoOutput,
+    reloc_parent: link.File.RelocInfo.Parent,
 ) CodeGenError!Result {
-    _ = reloc_info;
+    _ = reloc_parent;
 
     const tracy = trace(@src());
     defer tracy.end();
@@ -192,8 +186,7 @@ pub fn generateSymbol(
     src_loc: Zcu.LazySrcLoc,
     val: Value,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
-    reloc_info: RelocInfo,
+    reloc_parent: link.File.RelocInfo.Parent,
 ) CodeGenError!Result {
     const tracy = trace(@src());
     defer tracy.end();
@@ -290,7 +283,7 @@ pub fn generateSymbol(
                 switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(switch (error_union.val) {
                     .err_name => try pt.intern(.{ .undef = payload_ty.toIntern() }),
                     .payload => |payload| payload,
-                }), code, debug_output, reloc_info)) {
+                }), code, reloc_parent)) {
                     .ok => {},
                     .fail => |em| return .{ .fail = em },
                 }
@@ -318,7 +311,7 @@ pub fn generateSymbol(
         },
         .enum_tag => |enum_tag| {
             const int_tag_ty = ty.intTagType(zcu);
-            switch (try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, debug_output, reloc_info)) {
+            switch (try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, reloc_parent)) {
                 .ok => {},
                 .fail => |em| return .{ .fail = em },
             }
@@ -334,16 +327,16 @@ pub fn generateSymbol(
             },
             .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(16)),
         },
-        .ptr => switch (try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, debug_output, reloc_info, 0)) {
+        .ptr => switch (try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, reloc_parent, 0)) {
             .ok => {},
             .fail => |em| return .{ .fail = em },
         },
         .slice => |slice| {
-            switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.ptr), code, debug_output, reloc_info)) {
+            switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.ptr), code, reloc_parent)) {
                 .ok => {},
                 .fail => |em| return .{ .fail = em },
             }
-            switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.len), code, debug_output, reloc_info)) {
+            switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.len), code, reloc_parent)) {
                 .ok => {},
                 .fail => |em| return .{ .fail = em },
             }
@@ -355,7 +348,7 @@ pub fn generateSymbol(
 
             if (ty.optionalReprIsPayload(zcu)) {
                 if (payload_val) |value| {
-                    switch (try generateSymbol(bin_file, pt, src_loc, value, code, debug_output, reloc_info)) {
+                    switch (try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent)) {
                         .ok => {},
                         .fail => |em| return Result{ .fail = em },
                     }
@@ -368,7 +361,7 @@ pub fn generateSymbol(
                     const value = payload_val orelse Value.fromInterned(try pt.intern(.{
                         .undef = payload_type.toIntern(),
                     }));
-                    switch (try generateSymbol(bin_file, pt, src_loc, value, code, debug_output, reloc_info)) {
+                    switch (try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent)) {
                         .ok => {},
                         .fail => |em| return Result{ .fail = em },
                     }
@@ -390,7 +383,7 @@ pub fn generateSymbol(
                                 elem
                             else
                                 array_type.sentinel,
-                        }), code, debug_output, reloc_info)) {
+                        }), code, reloc_parent)) {
                             .ok => {},
                             .fail => |em| return .{ .fail = em },
                         }
@@ -449,7 +442,7 @@ pub fn generateSymbol(
                                         math.cast(usize, index) orelse return error.Overflow
                                     ],
                                     .repeated_elem => |elem| elem,
-                                }), code, debug_output, reloc_info)) {
+                                }), code, reloc_parent)) {
                                     .ok => {},
                                     .fail => |em| return .{ .fail = em },
                                 }
@@ -482,7 +475,7 @@ pub fn generateSymbol(
                         .repeated_elem => |elem| elem,
                     };
 
-                    switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, debug_output, reloc_info)) {
+                    switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent)) {
                         .ok => {},
                         .fail => |em| return Result{ .fail = em },
                     }
@@ -524,7 +517,7 @@ pub fn generateSymbol(
                                     return error.Overflow;
                                 var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size);
                                 defer tmp_list.deinit();
-                                switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), &tmp_list, debug_output, reloc_info)) {
+                                switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), &tmp_list, reloc_parent)) {
                                     .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items),
                                     .fail => |em| return Result{ .fail = em },
                                 }
@@ -559,7 +552,7 @@ pub fn generateSymbol(
                             ) orelse return error.Overflow;
                             if (padding > 0) try code.appendNTimes(0, padding);
 
-                            switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, debug_output, reloc_info)) {
+                            switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent)) {
                                 .ok => {},
                                 .fail => |em| return Result{ .fail = em },
                             }
@@ -583,12 +576,12 @@ pub fn generateSymbol(
             const layout = ty.unionGetLayout(zcu);
 
             if (layout.payload_size == 0) {
-                return generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, debug_output, reloc_info);
+                return generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent);
             }
 
             // Check if we should store the tag first.
             if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) {
-                switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, debug_output, reloc_info)) {
+                switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent)) {
                     .ok => {},
                     .fail => |em| return Result{ .fail = em },
                 }
@@ -601,7 +594,7 @@ pub fn generateSymbol(
                 if (!field_ty.hasRuntimeBits(zcu)) {
                     try code.appendNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow);
                 } else {
-                    switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, debug_output, reloc_info)) {
+                    switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, reloc_parent)) {
                         .ok => {},
                         .fail => |em| return Result{ .fail = em },
                     }
@@ -612,14 +605,14 @@ pub fn generateSymbol(
                     }
                 }
             } else {
-                switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, debug_output, reloc_info)) {
+                switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, reloc_parent)) {
                     .ok => {},
                     .fail => |em| return Result{ .fail = em },
                 }
             }
 
             if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) {
-                switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, debug_output, reloc_info)) {
+                switch (try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent)) {
                     .ok => {},
                     .fail => |em| return Result{ .fail = em },
                 }
@@ -640,40 +633,29 @@ fn lowerPtr(
     src_loc: Zcu.LazySrcLoc,
     ptr_val: InternPool.Index,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
-    reloc_info: RelocInfo,
+    reloc_parent: link.File.RelocInfo.Parent,
     prev_offset: u64,
 ) CodeGenError!Result {
     const zcu = pt.zcu;
     const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
     const offset: u64 = prev_offset + ptr.byte_offset;
     return switch (ptr.base_addr) {
-        .nav => |nav| try lowerNavRef(bin_file, pt, src_loc, nav, code, debug_output, reloc_info, offset),
-        .uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, code, debug_output, reloc_info, offset),
-        .int => try generateSymbol(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), code, debug_output, reloc_info),
+        .nav => |nav| try lowerNavRef(bin_file, pt, src_loc, nav, code, reloc_parent, offset),
+        .uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, code, reloc_parent, offset),
+        .int => try generateSymbol(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), code, reloc_parent),
         .eu_payload => |eu_ptr| try lowerPtr(
             bin_file,
             pt,
             src_loc,
             eu_ptr,
             code,
-            debug_output,
-            reloc_info,
+            reloc_parent,
             offset + errUnionPayloadOffset(
                 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu).errorUnionPayload(zcu),
                 zcu,
             ),
         ),
-        .opt_payload => |opt_ptr| try lowerPtr(
-            bin_file,
-            pt,
-            src_loc,
-            opt_ptr,
-            code,
-            debug_output,
-            reloc_info,
-            offset,
-        ),
+        .opt_payload => |opt_ptr| try lowerPtr(bin_file, pt, src_loc, opt_ptr, code, reloc_parent, offset),
         .field => |field| {
             const base_ptr = Value.fromInterned(field.base);
             const base_ty = base_ptr.typeOf(zcu).childType(zcu);
@@ -692,27 +674,21 @@ fn lowerPtr(
                 },
                 else => unreachable,
             };
-            return lowerPtr(bin_file, pt, src_loc, field.base, code, debug_output, reloc_info, offset + field_off);
+            return lowerPtr(bin_file, pt, src_loc, field.base, code, reloc_parent, offset + field_off);
         },
         .arr_elem, .comptime_field, .comptime_alloc => unreachable,
     };
 }
 
-const RelocInfo = struct {
-    parent_atom_index: u32,
-};
-
 fn lowerUavRef(
     lf: *link.File,
     pt: Zcu.PerThread,
     src_loc: Zcu.LazySrcLoc,
     uav: InternPool.Key.Ptr.BaseAddr.Uav,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
-    reloc_info: RelocInfo,
+    reloc_parent: link.File.RelocInfo.Parent,
     offset: u64,
 ) CodeGenError!Result {
-    _ = debug_output;
     const zcu = pt.zcu;
     const ip = &zcu.intern_pool;
     const target = lf.comp.root_mod.resolved_target.result;
@@ -735,7 +711,7 @@ fn lowerUavRef(
     }
 
     const vaddr = try lf.getUavVAddr(uav_val, .{
-        .parent_atom_index = reloc_info.parent_atom_index,
+        .parent = reloc_parent,
         .offset = code.items.len,
         .addend = @intCast(offset),
     });
@@ -756,12 +732,10 @@ fn lowerNavRef(
     src_loc: Zcu.LazySrcLoc,
     nav_index: InternPool.Nav.Index,
     code: *std.ArrayList(u8),
-    debug_output: DebugInfoOutput,
-    reloc_info: RelocInfo,
+    reloc_parent: link.File.RelocInfo.Parent,
     offset: u64,
 ) CodeGenError!Result {
     _ = src_loc;
-    _ = debug_output;
     const zcu = pt.zcu;
     const ip = &zcu.intern_pool;
     const target = zcu.navFileScope(nav_index).mod.resolved_target.result;
@@ -775,7 +749,7 @@ fn lowerNavRef(
     }
 
     const vaddr = try lf.getNavVAddr(pt, nav_index, .{
-        .parent_atom_index = reloc_info.parent_atom_index,
+        .parent = reloc_parent,
         .offset = code.items.len,
         .addend = @intCast(offset),
     });
src/link.zig
@@ -330,6 +330,11 @@ pub const File = struct {
         }
     }
 
+    pub const DebugInfoOutput = union(enum) {
+        dwarf: *Dwarf.WipNav,
+        plan9: *Plan9.DebugInfoOutput,
+        none,
+    };
     pub const UpdateDebugInfoError = Dwarf.UpdateError;
     pub const FlushDebugInfoError = Dwarf.FlushError;
 
@@ -673,9 +678,14 @@ pub const File = struct {
     }
 
     pub const RelocInfo = struct {
-        parent_atom_index: u32,
+        parent: Parent,
         offset: u64,
         addend: u32,
+
+        pub const Parent = union(enum) {
+            atom_index: u32,
+            debug_output: DebugInfoOutput,
+        };
     };
 
     /// Get allocated `Nav`'s address in virtual memory.