From fd9f45c358837b0091b795fad1c75f4efc8f4fc4 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Wed, 12 Aug 2026 18:12:19 -0400 Subject: [PATCH] Elf2: rework lost handling --- lib/std/dwarf/TAG.zig | 1 + src/Zcu/PerThread.zig | 5 +- src/link.zig | 14 +- src/link/C.zig | 3 +- src/link/Dwarf.zig | 110 ++++++------ src/link/Dwarf2.zig | 312 ++++++++++++++++++++--------------- src/link/Elf.zig | 4 +- src/link/Elf/ZigObject.zig | 4 +- src/link/Elf2.zig | 301 ++++++++++++++++++++------------- src/link/MachO.zig | 4 +- src/link/MachO/ZigObject.zig | 4 +- src/link/Spork8.zig | 5 +- src/link/Wasm.zig | 4 +- 13 files changed, 452 insertions(+), 319 deletions(-) diff --git a/lib/std/dwarf/TAG.zig b/lib/std/dwarf/TAG.zig index 6838c1dd02dc9b00881850e9a9f47aab309cea37..63f4ee34c62eeb2181f229d0e6bda2999ec59d54 100644 --- a/lib/std/dwarf/TAG.zig +++ b/lib/std/dwarf/TAG.zig @@ -120,3 +120,4 @@ pub const PGI_interface_block = 0xA020; // ZIG extensions. pub const ZIG_padding = 0xfdb1; pub const ZIG_comptime_value = 0xfdb2; +pub const ZIG_lost_declaration = 0xfdb3; diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 943a092b38dab0197e55d830e9e45ed79215f826..845451870513b8953dc77e72b28f49ea270cfa8f 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -877,7 +877,10 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void { const new_line = new_zir.getDeclaration(new_inst).src_line; if (old_line != new_line) { comp.link_prog_node.increaseEstimatedTotalItems(1); - try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .debug_update_line_number = tracked_inst_index }); + try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .debug_update_line_number = .{ + .inst = tracked_inst_index, + .line = new_line, + } }); } }, else => {}, diff --git a/src/link.zig b/src/link.zig index 6c2899ab94c3efc7d9ce394c073fab890a463cdb..d1878de3a1e6fc3a89d432e01d96b1f191ae98ff 100644 --- a/src/link.zig +++ b/src/link.zig @@ -870,10 +870,11 @@ pub const File = struct { /// On an incremental update, fixup the line number of all `Nav`s at the given `TrackedInst`, because /// its line number has changed. The ZIR instruction `ti_id` has tag `.declaration`. /// Never called when LLVM is codegenning the ZCU. - fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) Error!void { + fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index, line: u32) Error!void { assert(pt.zcu.llvm_object == null); { const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?; + assert(ti.inst != .main_struct_inst); const file = pt.zcu.fileByIndex(ti.file); const inst = file.zir.?.instructions.get(@backingInt(ti.inst)); assert(inst.tag == .declaration); @@ -885,7 +886,7 @@ pub const File = struct { .coff2 => {}, inline else => |tag| { dev.check(tag.devFeature()); - return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id); + return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id, line); }, } } @@ -1452,7 +1453,10 @@ pub const ZcuTask = union(enum) { ty: InternPool.Index, success: bool, }, - debug_update_line_number: InternPool.TrackedInst.Index, + debug_update_line_number: struct { + inst: InternPool.TrackedInst.Index, + line: u32, + }, lost_tracking: InternPool.TrackedInst.Index, }; @@ -1713,12 +1717,12 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void }; break :nav null; }, - .debug_update_line_number => |ti| nav: { + .debug_update_line_number => |line_update| nav: { const nav_prog_node = comp.link_prog_node.start("Update line number", 0); defer nav_prog_node.end(); if (pt.zcu.llvm_object == null) { if (comp.bin_file) |lf| { - lf.updateLineNumber(pt, ti) catch |err| switch (err) { + lf.updateLineNumber(pt, line_update.inst, line_update.line) catch |err| switch (err) { error.OutOfMemory => diags.setAllocFailure(), else => |e| log.err("update line number failed: {s}", .{@errorName(e)}), }; diff --git a/src/link/C.zig b/src/link/C.zig index a080687e40e369dc5d941b2484c8fa915e9e394c..d6d9b1f67d993082e8a592aaa0ef9e18531dc696 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -721,12 +721,13 @@ fn updateUav( rendered_decl.ctype_deps = try c.addCTypeDependencies(pt, &dg.ctype_deps); } -pub fn updateLineNumber(c: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) error{}!void { +pub fn updateLineNumber(c: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index, line: u32) error{}!void { // The C backend does not currently emit "#line" directives. Even if it did, it would not be // capable of updating those line numbers without re-generating the entire declaration. _ = c; _ = pt; _ = ti_id; + _ = line; } pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.Error!void { diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 61882b07b38e2dca4622a1a6b05b57700f2dfb2f..7ca2d9d728b38e5b26d68e389800ce367cbde240 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -2202,7 +2202,7 @@ pub const WipNav = struct { wip_nav: *WipNav, abbrev_code: struct { decl: AbbrevCode, - generic_decl: AbbrevCode, + decl_abstract: AbbrevCode, decl_instance: AbbrevCode, }, nav: *const InternPool.Nav, @@ -2216,11 +2216,11 @@ pub const WipNav = struct { const orig_entry = wip_nav.entry; defer wip_nav.entry = orig_entry; - const parent_type, const is_generic_decl = if (nav.analysis) |analysis| parent_info: { + const parent_type, const is_abstract = if (nav.analysis) |analysis| parent_info: { const parent_type: Type = .fromInterned(zcu.namespacePtr(analysis.namespace).owner_type); const decl_gop = try dwarf.decls.getOrPut(dwarf.gpa, analysis.zir_index); errdefer _ = if (!decl_gop.found_existing) dwarf.decls.pop(); - const was_generic_decl = decl_gop.found_existing and + const was_abstract = decl_gop.found_existing and switch (try dwarf.debug_info.declAbbrevCode(wip_nav.unit, decl_gop.value_ptr.*)) { .null, .decl_alias, @@ -2242,9 +2242,9 @@ pub const WipNav = struct { .decl_extern_nullary_func, .decl_extern_func, => false, - .generic_decl_var, - .generic_decl_const, - .generic_decl_func, + .decl_abstract_var, + .decl_abstract_const, + .decl_abstract_func, => true, // This comes from a decl which was previously generated as an incomplete value @@ -2255,11 +2255,11 @@ pub const WipNav = struct { else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}), }; if (parent_type.getCaptures(zcu).len == 0) { - if (was_generic_decl) try dwarf.freeCommonEntry(wip_nav.unit, decl_gop.value_ptr.*); + if (was_abstract) try dwarf.freeCommonEntry(wip_nav.unit, decl_gop.value_ptr.*); decl_gop.value_ptr.* = orig_entry; break :parent_info .{ parent_type, false }; } else { - if (was_generic_decl) + if (was_abstract) dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(decl_gop.value_ptr.*).clear() else decl_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit); @@ -2268,8 +2268,8 @@ pub const WipNav = struct { } } else .{ null, false }; - try wip_nav.abbrevCode(if (is_generic_decl) abbrev_code.generic_decl else abbrev_code.decl); - try wip_nav.refType((if (is_generic_decl) null else parent_type) orelse + try wip_nav.abbrevCode(if (is_abstract) abbrev_code.decl_abstract else abbrev_code.decl); + try wip_nav.refType((if (is_abstract) null else parent_type) orelse .fromInterned(zcu.fileRootType(file))); assert(diw.end == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, decl.src_line + 1, dwarf.endian); @@ -2277,14 +2277,14 @@ pub const WipNav = struct { try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private); try wip_nav.strp(nav.name.toSlice(ip)); - if (!is_generic_decl) return; - const generic_decl_entry = wip_nav.entry; - try dwarf.debug_info.section.replaceEntry(wip_nav.unit, generic_decl_entry, dwarf, wip_nav.debug_info.written()); + if (!is_abstract) return; + const abstract_entry = wip_nav.entry; + try dwarf.debug_info.section.replaceEntry(wip_nav.unit, abstract_entry, dwarf, wip_nav.debug_info.written()); wip_nav.debug_info.clearRetainingCapacity(); wip_nav.entry = orig_entry; try wip_nav.abbrevCode(abbrev_code.decl_instance); try wip_nav.refType(parent_type.?); - try wip_nav.infoSectionOffset(.debug_info, wip_nav.unit, generic_decl_entry, 0); + try wip_nav.infoSectionOffset(.debug_info, wip_nav.unit, abstract_entry, 0); } }; @@ -2680,11 +2680,11 @@ fn initWipNavInner( const diw = &wip_nav.debug_info.writer; try wip_nav.declCommon(if (func_type.param_types.len > 0 or func_type.is_var_args) .{ .decl = .decl_extern_func, - .generic_decl = .generic_decl_func, + .decl_abstract = .decl_abstract_func, .decl_instance = .decl_instance_extern_func, } else .{ .decl = .decl_extern_nullary_func, - .generic_decl = .generic_decl_func, + .decl_abstract = .decl_abstract_func, .decl_instance = .decl_instance_extern_nullary_func, }, &nav, inst_info.file, &decl); try wip_nav.strp(@"extern".name.toSlice(ip)); @@ -2705,7 +2705,7 @@ fn initWipNavInner( .func => |func| if (func.owner_nav != nav_index) { try wip_nav.declCommon(.{ .decl = .decl_alias, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_alias, }, &nav, inst_info.file, &decl); try wip_nav.refNav(func.owner_nav); @@ -2758,7 +2758,7 @@ fn initWipNavInner( const diw = &wip_nav.debug_info.writer; try wip_nav.declCommon(.{ .decl = .decl_func, - .generic_decl = .generic_decl_func, + .decl_abstract = .decl_abstract_func, .decl_instance = .decl_instance_func, }, &nav, inst_info.file, &decl); try wip_nav.strp(switch (decl.linkage) { @@ -2817,10 +2817,10 @@ fn initWipNavInner( const diw = &wip_nav.debug_info.writer; try wip_nav.declCommon(.{ .decl = .decl_var, - .generic_decl = switch (decl.kind) { + .decl_abstract = switch (decl.kind) { .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable, - .@"const" => .generic_decl_const, - .@"var" => .generic_decl_var, + .@"const" => .decl_abstract_const, + .@"var" => .decl_abstract_var, }, .decl_instance = .decl_instance_var, }, &nav, inst_info.file, &decl); @@ -3181,7 +3181,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo .alias => { try wip_nav.declCommon(.{ .decl = .decl_alias, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_alias, }, &nav, inst_info.file, &decl); try wip_nav.refType(nav_val.toType()); @@ -3189,7 +3189,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo .@"var" => { try wip_nav.declCommon(.{ .decl = .decl_var, - .generic_decl = .generic_decl_var, + .decl_abstract = .decl_abstract_var, .decl_instance = .decl_instance_var, }, &nav, inst_info.file, &decl); try wip_nav.strp(switch (decl.linkage) { @@ -3209,19 +3209,19 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo const has_comptime_state = nav_ty.comptimeOnly(zcu); try wip_nav.declCommon(if (has_runtime_bits and has_comptime_state) .{ .decl = .decl_const_runtime_bits_comptime_state, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_const_runtime_bits_comptime_state, } else if (has_comptime_state) .{ .decl = .decl_const_comptime_state, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_const_comptime_state, } else if (has_runtime_bits) .{ .decl = .decl_const_runtime_bits, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_const_runtime_bits, } else .{ .decl = .decl_const, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_const, }, &nav, inst_info.file, &decl); try wip_nav.strp(switch (decl.linkage) { @@ -3245,11 +3245,11 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo } else true; try wip_nav.declCommon(if (is_nullary) .{ .decl = .decl_nullary_func_generic, - .generic_decl = .generic_decl_func, + .decl_abstract = .decl_abstract_func, .decl_instance = .decl_instance_nullary_func_generic, } else .{ .decl = .decl_func_generic, - .generic_decl = .generic_decl_func, + .decl_abstract = .decl_abstract_func, .decl_instance = .decl_instance_func_generic, }, &nav, inst_info.file, &decl); try wip_nav.refType(.fromInterned(func_type.return_type)); @@ -3267,7 +3267,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo .func_alias => |owner_nav| { try wip_nav.declCommon(.{ .decl = .decl_alias, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_alias, }, &nav, inst_info.file, &decl); try wip_nav.refNav(owner_nav); @@ -3463,7 +3463,7 @@ fn emitIncompleteContainerType( const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); try wip_nav.declCommon(.{ .decl = .decl_namespace_struct, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_namespace_struct, }, &nav, file, &decl); try wip_nav.debug_info.writer.writeByte(@intFromBool(true)); @@ -3881,11 +3881,11 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); try wip_nav.declCommon(if (loaded_struct.field_types.len == 0) .{ .decl = .decl_namespace_struct, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_namespace_struct, } else .{ .decl = .decl_struct, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_struct, }, &nav, file, &decl); } else { @@ -3960,7 +3960,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); try wip_nav.declCommon(.{ .decl = .decl_packed_struct, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_packed_struct, }, &nav, file, &decl); break :t true; @@ -3997,7 +3997,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); try wip_nav.declCommon(.{ .decl = .decl_union, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_union, }, &nav, file, &decl); break :t true; @@ -4059,7 +4059,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); try wip_nav.declCommon(.{ .decl = .decl_packed_union, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_packed_union, }, &nav, file, &decl); break :t true; @@ -4092,11 +4092,11 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); try wip_nav.declCommon(if (loaded_enum.field_names.len > 0) .{ .decl = .decl_enum, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_enum, } else .{ .decl = .decl_empty_enum, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_empty_enum, }, &nav, file, &decl); } else { @@ -4134,7 +4134,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); try wip_nav.declCommon(.{ .decl = .decl_namespace_struct, - .generic_decl = .generic_decl_const, + .decl_abstract = .decl_abstract_const, .decl_instance = .decl_instance_namespace_struct, }, &nav, file, &decl); } else { @@ -4645,7 +4645,7 @@ fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { unpacked, opv_null, err }; } -pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedInst.Index) UpdateError!void { +pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedInst.Index, line: u32) UpdateError!void { const comp = dwarf.bin_file.comp; const io = comp.io; const ip = &zcu.intern_pool; @@ -4653,17 +4653,9 @@ pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedI const inst_info = zir_index.resolveFull(ip).?; assert(inst_info.inst != .main_struct_inst); const file = zcu.fileByIndex(inst_info.file); - const decl = file.zir.?.getDeclaration(inst_info.inst); - log.debug("updateLineNumber({s}:{d}:{d} %{d} = {s})", .{ - file.sub_file_path, - decl.src_line + 1, - decl.src_column + 1, - @backingInt(inst_info.inst), - file.zir.?.nullTerminatedString(decl.name), - }); var line_buf: [4]u8 = undefined; - std.mem.writeInt(u32, &line_buf, decl.src_line + 1, dwarf.endian); + std.mem.writeInt(u32, &line_buf, line + 1, dwarf.endian); const unit = dwarf.debug_info.section.getUnit(dwarf.getUnitIfExists(file.mod.?) orelse return); const entry = unit.getEntry(dwarf.decls.get(zir_index) orelse return); @@ -5144,9 +5136,9 @@ const AbbrevCode = enum { decl_func_generic, decl_extern_nullary_func, decl_extern_func, - generic_decl_var, - generic_decl_const, - generic_decl_func, + decl_abstract_var, + decl_abstract_const, + decl_abstract_func, decl_instance_alias, decl_instance_empty_enum, decl_instance_enum, @@ -5270,7 +5262,7 @@ const AbbrevCode = enum { .{ .accessibility, .data1 }, .{ .name, .strp }, }; - const generic_decl_abbrev_common_attrs = decl_abbrev_common_attrs ++ &[_]Attr{ + const decl_abstract_abbrev_common_attrs = decl_abbrev_common_attrs ++ &[_]Attr{ .{ .declaration, .flag_present }, }; const decl_instance_abbrev_common_attrs = &[_]Attr{ @@ -5455,17 +5447,17 @@ const AbbrevCode = enum { .{ .noreturn, .flag }, }, }, - .generic_decl_var = .{ + .decl_abstract_var = .{ .tag = .variable, - .attrs = generic_decl_abbrev_common_attrs, + .attrs = decl_abstract_abbrev_common_attrs, }, - .generic_decl_const = .{ + .decl_abstract_const = .{ .tag = .constant, - .attrs = generic_decl_abbrev_common_attrs, + .attrs = decl_abstract_abbrev_common_attrs, }, - .generic_decl_func = .{ + .decl_abstract_func = .{ .tag = .subprogram, - .attrs = generic_decl_abbrev_common_attrs, + .attrs = decl_abstract_abbrev_common_attrs, }, .decl_instance_alias = .{ .tag = .imported_declaration, diff --git a/src/link/Dwarf2.zig b/src/link/Dwarf2.zig index e51525bc3de9ae3913d2aca2e747edad6f088813..63936350d2647cd802605a8b4106213877d22537 100644 --- a/src/link/Dwarf2.zig +++ b/src/link/Dwarf2.zig @@ -8,7 +8,8 @@ units: std.array_hash_map.Auto(*Module, Unit), /// Indices are `link.ConstPool.Index`. values: std.ArrayList(Value), globals: std.array_hash_map.Auto(InternPool.Nav.Index, Global), -funcs: std.array_hash_map.Auto(InternPool.TrackedInst.Index, Func), +funcs: std.array_hash_map.Auto(InternPool.Nav.Index, Func), +decls: std.array_hash_map.Auto(InternPool.TrackedInst.Index, MappedFile.Node.Index), debug_abbrev: Abbrev, frame: Frame, @@ -32,7 +33,8 @@ pub const Unit = struct { debug_line_header_ni: MappedFile.Node.Index.Optional, debug_line_header_changed: bool, debug_rnglists_ni: MappedFile.Node.Index.Optional, - debug_rnglists_offset: usize, + debug_rnglists_offsets_table_offset: usize, + debug_rnglists_end: usize, pub const Index = enum(u32) { _, @@ -123,7 +125,6 @@ pub const Global = struct { }; pub const Func = struct { - owner_nav: InternPool.Nav.Index, fde_ni: MappedFile.Node.Index.Optional, debug_info_ni: MappedFile.Node.Index.Optional, debug_line_ni: MappedFile.Node.Index.Optional, @@ -131,7 +132,7 @@ pub const Func = struct { pub const Index = enum(u32) { _, - pub fn srcInst(fi: Func.Index, dwarf: *Dwarf) InternPool.TrackedInst.Index { + pub fn nav(fi: Func.Index, dwarf: *Dwarf) InternPool.Nav.Index { return dwarf.funcs.keys()[@backingInt(fi)]; } @@ -156,7 +157,7 @@ pub const Frame = struct { pub const Abbrev = struct { ni: MappedFile.Node.Index.Optional, - offset: usize, + end: usize, set: std.enums.EnumSet(AbbrevCode), }; @@ -628,7 +629,7 @@ pub const WipNav = struct { pub fn startDebugInfo(debug: *Debug) link.Error!void { assert(debug.wip_nav.func != .none); debug.startDebugInfoInner() catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.info_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer), else => |e| return e, }; } @@ -637,7 +638,8 @@ pub const WipNav = struct { const zcu = debug.pt.zcu; const ip = &zcu.intern_pool; const func = zcu.funcInfo(debug.wip_nav.func); - const inst_info = ip.getNav(func.owner_nav).srcInst(ip).resolveFull(ip).?; + const src_inst = ip.getNav(func.owner_nav).srcInst(ip); + const inst_info = src_inst.resolveFull(ip).?; const decl = zcu.fileByIndex(inst_info.file).zir.?.getDeclaration(inst_info.inst); const nav = ip.getNav(func.owner_nav); const diw = &debug.info_writer.interface; @@ -655,7 +657,7 @@ pub const WipNav = struct { pub fn startDebugLine(debug: *Debug) link.Error!void { assert(debug.wip_nav.func != .none); debug.startDebugLineInner() catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.line_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer), else => |e| return e, }; } @@ -698,24 +700,25 @@ pub const WipNav = struct { pub fn finishFunc(debug: *Debug, func_length: u64) link.Error!void { assert(debug.wip_nav.func != .none); debug.finishDebugInfo(func_length) catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.info_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer), else => |e| return e, }; debug.finishDebugLine() catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.line_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer), else => |e| return e, }; } fn finishDebugInfo(debug: *Debug, func_length: u64) link.EmitError!void { + const dwarf = debug.wip_nav.dwarf; const diw = &debug.info_writer.interface; std.mem.writeInt( u32, diw.buffered()[debug.info_func_length_offset..][0..4], @intCast(func_length), - debug.wip_nav.dwarf.endian, + dwarf.endian, ); try diw.writeUleb128(@backingInt(AbbrevCode.null)); - try debug.wip_nav.dwarf.genDebugInfoPadding(diw, diw.unusedCapacityLen()); + try dwarf.genDebugInfoPadding(diw, diw.unusedCapacityLen()); } fn finishDebugLine(debug: *Debug) link.EmitError!void { const dlw = &debug.line_writer.interface; @@ -731,7 +734,7 @@ pub const WipNav = struct { loc: Loc, ) link.Error!void { return debug.genLocalVarDebugInfoInner(tag, opt_name, ty, loc) catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.info_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer), else => |e| e, }; } @@ -761,7 +764,7 @@ pub const WipNav = struct { val: ZigValue, ) link.Error!void { return debug.genLocalConstDebugInfoInner(tag, opt_name, val) catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.info_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer), else => |e| e, }; } @@ -798,7 +801,7 @@ pub const WipNav = struct { pub fn genVarArgsDebugInfo(debug: *Debug) link.Error!void { return debug.genVarArgsDebugInfoInner() catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.info_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer), else => |e| e, }; } @@ -815,7 +818,7 @@ pub const WipNav = struct { end: bool, ) link.Error!void { return debug.advanceLineAndPcInner(delta_line, delta_pc, end) catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.line_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer), }; } fn advanceLineAndPcInner( @@ -870,7 +873,7 @@ pub const WipNav = struct { pub fn setColumn(debug: *Debug, column: u32) link.Error!void { return debug.setColumnInner(column) catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.line_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer), }; } fn setColumnInner(debug: *Debug, column: u32) Writer.Error!void { @@ -881,7 +884,7 @@ pub const WipNav = struct { pub fn negateStmt(debug: *Debug) link.Error!void { return debug.negateStmtInner() catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.line_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer), }; } fn negateStmtInner(debug: *Debug) Writer.Error!void { @@ -890,7 +893,7 @@ pub const WipNav = struct { pub fn setPrologueEnd(debug: *Debug) link.Error!void { return debug.setPrologueEndInner() catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.line_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer), }; } fn setPrologueEndInner(debug: *Debug) Writer.Error!void { @@ -899,7 +902,7 @@ pub const WipNav = struct { pub fn setEpilogueBegin(debug: *Debug) link.Error!void { return debug.setEpilogueBeginInner() catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.line_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer), }; } fn setEpilogueBeginInner(debug: *Debug) Writer.Error!void { @@ -908,7 +911,7 @@ pub const WipNav = struct { pub fn enterBlock(debug: *Debug, code_off: usize) link.Error!void { return debug.enterBlockInner(code_off) catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.info_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer), else => |e| e, }; } @@ -928,7 +931,7 @@ pub const WipNav = struct { pub fn leaveBlock(debug: *Debug, code_off: usize) link.Error!void { return debug.leaveBlockInner(code_off) catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.info_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer), else => |e| e, }; } @@ -961,7 +964,7 @@ pub const WipNav = struct { column: u32, ) link.Error!void { return debug.enterInlineFuncInner(func, code_off, line, column) catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.info_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer), else => |e| e, }; } @@ -996,7 +999,7 @@ pub const WipNav = struct { pub fn leaveInlineFunc(debug: *Debug, func: InternPool.Index, code_off: usize) link.Error!void { return debug.leaveInlineFuncInner(func, code_off) catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.info_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer), else => |e| e, }; } @@ -1029,7 +1032,7 @@ pub const WipNav = struct { pub fn setInlineFunc(debug: *Debug, func: InternPool.Index) link.Error!void { return debug.setInlineFuncInner(func) catch |err| switch (err) { - error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.line_writer), + error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer), else => |e| e, }; } @@ -1187,7 +1190,7 @@ pub const WipNav = struct { pub fn genDebugFrameHeader(wip_nav: *WipNav) link.Error!void { wip_nav.genDebugFrameHeaderInner() catch |err| switch (err) { - error.WriteFailed => return wip_nav.reportWriteError(&wip_nav.fde_writer), + error.WriteFailed => return wip_nav.dwarf.reportWriteError(&wip_nav.fde_writer), else => |e| return e, }; } @@ -1230,7 +1233,7 @@ pub const WipNav = struct { pub fn genDebugFrame(wip_nav: *WipNav, loc: u32, cfa: Cfa) link.Error!void { return wip_nav.genDebugFrameInner(loc, cfa) catch |err| switch (err) { - error.WriteFailed => return wip_nav.reportWriteError(&wip_nav.fde_writer), + error.WriteFailed => return wip_nav.dwarf.reportWriteError(&wip_nav.fde_writer), else => |e| return e, }; } @@ -1336,16 +1339,6 @@ pub const WipNav = struct { }, ); } - - fn reportWriteError(wip_nav: *WipNav, mfnw: *const MappedFile.Node.Writer) link.Error { - switch (mfnw.err.?) { - else => |e| return e, - error.MappedFileIo => return wip_nav.dwarf.lf.comp.link_diags.fail( - "failed to write output file: {t}", - .{mfnw.mf.io_err.?}, - ), - } - } }; pub fn init(lf: *link.File, format: DW.Format) Dwarf { @@ -1365,10 +1358,11 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf { .values = .empty, .globals = .empty, .funcs = .empty, + .decls = .empty, .debug_abbrev = .{ .ni = .none, - .offset = 0, + .end = 0, .set = .empty, }, .frame = .{ @@ -1443,7 +1437,7 @@ pub fn deinit(dwarf: *Dwarf) void { dwarf.* = undefined; } -pub fn initUnits(dwarf: *Dwarf, zcu: *Zcu) std.mem.Allocator.Error!void { +pub fn updateUnits(dwarf: *Dwarf, zcu: *Zcu) std.mem.Allocator.Error!void { try dwarf.units.ensureTotalCapacity(zcu.gpa, zcu.module_roots.count() - dwarf.units.count()); for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, root| if (root.unwrap()) |root_zfi| { if (!zcu.alive_files.contains(root_zfi)) continue; @@ -1461,7 +1455,8 @@ pub fn initUnits(dwarf: *Dwarf, zcu: *Zcu) std.mem.Allocator.Error!void { .debug_line_header_ni = .none, .debug_line_header_changed = true, .debug_rnglists_ni = .none, - .debug_rnglists_offset = undefined, + .debug_rnglists_offsets_table_offset = undefined, + .debug_rnglists_end = undefined, }; const root_di, const root_fi = try unit_gop.value_ptr.getFile( zcu.gpa, @@ -1476,15 +1471,48 @@ pub fn getUnit(dwarf: *Dwarf, mod: *Module) Unit.Index { return @fromBackingInt(@intCast(dwarf.units.getIndex(mod).?)); } -pub fn getFunc(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) link.Error!Func.Index { +pub fn getGlobal(dwarf: *Dwarf, nav: InternPool.Nav.Index) link.Error!Global.Index { const comp = dwarf.lf.comp; const gpa = comp.gpa; - const zcu = comp.zcu.?; - const ip = &zcu.intern_pool; - const src_inst = ip.getNav(owner_nav).srcInst(ip); - const func_gop = try dwarf.funcs.getOrPut(gpa, src_inst); + const global_gop = try dwarf.globals.getOrPut(gpa, nav); + if (!global_gop.found_existing) global_gop.value_ptr.* = .{ + .debug_info_ni = .none, + }; + const gi: Global.Index = @fromBackingInt(@intCast(global_gop.index)); + if (global_gop.value_ptr.debug_info_ni == .none) { + const elf = dwarf.lf.cast(.elf2).?; + try elf.nodes.ensureUnusedCapacity(gpa, 1); + try elf.dwarf_globals.ensureUnusedCapacity(gpa, 1); + const unit = dwarf.getUnit(comp.zcu.?.zcu.navFileScope(nav).mod.?).get(dwarf); + assert(unit.debug_info_ni != .none); + global_gop.value_ptr.debug_info_ni = elf.addNodeAssumeCapacity( + elf.mf.addLastChildNode(gpa, unit.debug_info_ni, .{ + .enable_next_moved = true, + }) catch |err| switch (err) { + else => |e| return e, + error.MappedFileIo => return comp.link_diags.fail("failed to write output file: {t}", .{ + elf.mf.io_err.?, + }), + }, + .{ .global_debug_info = gi }, + ); + elf.dwarf_globals.addOneAssumeCapacity().* = .{ + .debug_info_first_target_reloc = .none, + .debug_info_first_node_reloc = .none, + .debug_info_first_symbol_reloc = .none, + }; + } + return gi; +} +pub fn getGlobalIfExists(dwarf: *Dwarf, nav: InternPool.Nav.Index) ?Global.Index { + return @fromBackingInt(@intCast(dwarf.globals.getIndex(nav) orelse return null)); +} + +pub fn getFunc(dwarf: *Dwarf, nav: InternPool.Nav.Index) link.Error!Func.Index { + const comp = dwarf.lf.comp; + const gpa = comp.gpa; + const func_gop = try dwarf.funcs.getOrPut(gpa, nav); if (!func_gop.found_existing) func_gop.value_ptr.* = .{ - .owner_nav = owner_nav, .fde_ni = .none, .debug_info_ni = .none, .debug_line_ni = .none, @@ -1494,7 +1522,7 @@ pub fn getFunc(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) link.Error!Func.I const elf = dwarf.lf.cast(.elf2).?; try elf.nodes.ensureUnusedCapacity(gpa, 1); try elf.dwarf_funcs.ensureUnusedCapacity(gpa, 1); - const unit = dwarf.getUnit(zcu.fileByIndex(src_inst.resolveFile(ip)).mod.?).get(dwarf); + const unit = dwarf.getUnit(comp.zcu.?.navFileScope(nav).mod.?).get(dwarf); func_gop.value_ptr.debug_info_ni = .wrap(elf.addNodeAssumeCapacity( unit.debug_info_ni.unwrap().?.addFloatingChild(gpa, &elf.mf, .{ .enable_next_moved = true, @@ -1518,10 +1546,8 @@ pub fn getFunc(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) link.Error!Func.I } return fi; } -pub fn getFuncIfExists(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) ?Func.Index { - const ip = &dwarf.lf.comp.zcu.?.intern_pool; - return @fromBackingInt(@intCast(dwarf.funcs.getIndex(ip.getNav(owner_nav).srcInst(ip)) orelse - return null)); +pub fn getFuncIfExists(dwarf: *Dwarf, nav: InternPool.Nav.Index) ?Func.Index { + return @fromBackingInt(@intCast(dwarf.funcs.getIndex(nav) orelse return null)); } pub fn unitLengthSize(dwarf: *Dwarf) usize { @@ -1654,11 +1680,11 @@ pub fn updateEhFrameFde(dwarf: *Dwarf, fde: []u8, fde_offset: u64) void { pub fn genDebugInfoHeader( dwarf: *Dwarf, + zcu: *Zcu, mod: *Module, unit: *Unit, dih_nw: *MappedFile.Node.Writer, debug_rnglists_offsets_table_offset: usize, - zcu: *Zcu, ) link.EmitError!void { const comp = zcu.comp; const dihw = &dih_nw.interface; @@ -1695,20 +1721,22 @@ pub fn genDebugInfoHeader( zcu.builtin_modules.get(mod.getBuiltinOptions(comp.config).hash()).?, zcu.root_mod, zcu.std_mod, - }) |name, dep| try dwarf.genModuleDependency(dih_nw, name, dep, module_offset); + }) |name, dep| try dwarf.genModuleDependency(zcu, dih_nw, name, dep, module_offset); for (mod.deps.keys(), mod.deps.values()) |name, dep| - try dwarf.genModuleDependency(dih_nw, name, dep, module_offset); + try dwarf.genModuleDependency(zcu, dih_nw, name, dep, module_offset); for ([2]AbbrevCode{ .pad_1, .pad_n }) |pad| _ = try dwarf.refAbbrevCode(pad); try dwarf.genDebugInfoPadding(dihw, dihw.unusedCapacityLen()); } fn genModuleDependency( dwarf: *Dwarf, + zcu: *Zcu, nw: *MappedFile.Node.Writer, name: []const u8, dep: *Module, module_offset: usize, ) link.EmitError!void { + if (!zcu.alive_files.contains(zcu.module_roots.get(dep).?.unwrap() orelse return)) return; const diw = &nw.interface; try diw.writeUleb128(try dwarf.refAbbrevCode(.module_dependency)); try diw.writeAll(name); @@ -1889,7 +1917,7 @@ pub fn genDebugRnglistsHeader( .@"32" => try drhw.writeInt(u32, 4, dwarf.endian), .@"64" => try drhw.writeInt(u64, 8, dwarf.endian), } - unit.debug_rnglists_offset = drhw.end; + unit.debug_rnglists_end = drhw.end; try drhw.writeByte(DW.RLE.end_of_list); return offsets_table_offset; } @@ -1902,24 +1930,22 @@ pub fn genDebugRnglists( func_length: u64, ) link.EmitError!void { const drw = &dr_nw.interface; - drw.end = unit.debug_rnglists_offset; + drw.end = unit.debug_rnglists_end; try drw.writeByte(DW.RLE.start_length); try dwarf.symbolAddress(dr_nw, func_si, 0); try drw.writeUleb128(func_length); - unit.debug_rnglists_offset = drw.end; + unit.debug_rnglists_end = drw.end; try drw.writeByte(DW.RLE.end_of_list); } pub fn updateLineNumber( dwarf: *Dwarf, - zcu: *Zcu, - src_inst: InternPool.TrackedInst.Index, - debug_info: []u8, + mf: *MappedFile, + inst: InternPool.TrackedInst.Index, + line: u32, ) void { - const inst_info = src_inst.resolveFull(&zcu.intern_pool).?; - assert(inst_info.inst != .main_struct_inst); - const src_line = zcu.fileByIndex(inst_info.file).zir.?.getDeclaration(inst_info.inst).src_line; - std.mem.writeInt(u32, debug_info[AbbrevCode.decl_bytes..][0..4], src_line + 1, dwarf.endian); + const decl_ni = dwarf.decls.get(inst) orelse return; + std.mem.writeInt(u32, decl_ni.slice(mf)[AbbrevCode.decl_bytes..][0..4], line + 1, dwarf.endian); } fn refAbbrevCodeIfExists( @@ -1930,36 +1956,45 @@ fn refAbbrevCodeIfExists( return if (dwarf.debug_abbrev.set.contains(abbrev_code)) @backingInt(abbrev_code) else null; } -fn refAbbrevCode( +pub fn refAbbrevCode( dwarf: *Dwarf, abbrev_code: AbbrevCode, -) link.EmitError!@typeInfo(AbbrevCode).@"enum".tag_type { +) link.Error!@typeInfo(AbbrevCode).@"enum".tag_type { if (dwarf.refAbbrevCodeIfExists(abbrev_code)) |backing_int| { @branchHint(.likely); return backing_int; } - const elf = dwarf.lf.cast(.elf2).?; - const comp = elf.base.comp; - var nw: MappedFile.Node.Writer = undefined; - dwarf.debug_abbrev.ni.unwrap().?.writer(comp.gpa, &elf.mf, &nw); - defer nw.deinit(); + var da_nw: MappedFile.Node.Writer = undefined; + dwarf.debug_abbrev.ni.unwrap().?.writer(dwarf.lf.comp.gpa, &dwarf.lf.cast(.elf2).?.mf, &da_nw); + defer da_nw.deinit(); + dwarf.genDebugAbbrev(&da_nw, abbrev_code) catch |err| switch (err) { + else => |e| return e, + error.WriteFailed => return dwarf.reportWriteError(&da_nw), + }; + dwarf.debug_abbrev.set.insert(abbrev_code); + return dwarf.refAbbrevCodeIfExists(abbrev_code).?; +} + +fn genDebugAbbrev( + dwarf: *Dwarf, + da_nw: *MappedFile.Node.Writer, + abbrev_code: AbbrevCode, +) link.EmitError!void { const abbrev = AbbrevCode.abbrevs.get(abbrev_code); - const daw = &nw.interface; - daw.end = dwarf.debug_abbrev.offset; + const daw = &da_nw.interface; + daw.end = dwarf.debug_abbrev.end; try daw.writeUleb128(@backingInt(abbrev_code)); try daw.writeUleb128(@backingInt(abbrev.tag)); try daw.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no); for (abbrev.attrs) |*attr| { try daw.writeUleb128(@backingInt(switch (attr[0]) { else => |at| at, - .ZIG_call_line_relative => |at| if (comp.config.incremental) at else .call_line, + .ZIG_call_line_relative => |at| if (dwarf.lf.comp.config.incremental) at else .call_line, })); try daw.writeUleb128(@backingInt(attr[1])); } for (0..2) |_| try daw.writeUleb128(0); - dwarf.debug_abbrev.offset = daw.end; - dwarf.debug_abbrev.set.insert(abbrev_code); - return dwarf.refAbbrevCodeIfExists(abbrev_code).?; + dwarf.debug_abbrev.end = daw.end; } fn sectionOffset( @@ -2007,6 +2042,16 @@ fn strp(dwarf: *Dwarf, s: *Str, nw: *MappedFile.Node.Writer, str: []const u8) li }); } +fn reportWriteError(dwarf: *Dwarf, nw: *const MappedFile.Node.Writer) link.Error { + switch (nw.err.?) { + else => |e| return e, + error.MappedFileIo => return dwarf.lf.comp.link_diags.fail( + "failed to write output file: {t}", + .{nw.mf.io_err.?}, + ), + } +} + fn DeclValEnum(comptime T: type) type { const decl_names = @typeInfo(T).@"struct".decl_names; @setEvalBranchQuota(10 * decl_names.len); @@ -2034,7 +2079,8 @@ pub const AbbrevCode = enum { // padding codes must be one byte uleb128 values to function pad_1, pad_n, - // decl, generic decl, and instance codes are assumed to all have the same uleb128 length + // decl, specification, and instance codes are assumed to all have the same uleb128 size + decl_lost, decl_alias, decl_empty_enum, decl_enum, @@ -2054,9 +2100,9 @@ pub const AbbrevCode = enum { decl_func_generic, decl_extern_nullary_func, decl_extern_func, - generic_decl_var, - generic_decl_const, - generic_decl_func, + decl_specification_struct, + decl_specification_union, + decl_specification_func, decl_instance_alias, decl_instance_empty_enum, decl_instance_enum, @@ -2174,20 +2220,23 @@ pub const AbbrevCode = enum { DeclValEnum(DW.AT), DeclValEnum(DW.FORM), }; - const decl_abbrev_common_attrs = &[_]Attr{ + const decl_attrs = &[_]Attr{ //.{ .ZIG_parent, .ref_addr }, .{ .decl_line, .data4 }, .{ .decl_column, .udata }, .{ .accessibility, .data1 }, .{ .name, .strp }, }; - const generic_decl_abbrev_common_attrs = decl_abbrev_common_attrs ++ &[_]Attr{ + + const decl_specification_attrs = decl_attrs ++ &[_]Attr{ .{ .declaration, .flag_present }, }; - const decl_instance_abbrev_common_attrs = &[_]Attr{ - .{ .ZIG_parent, .ref_addr }, - .{ .abstract_origin, .ref_addr }, + + const decl_instance_attrs = &[_]Attr{ + //.{ .ZIG_parent, .ref_addr }, + .{ .specification, .ref_addr }, }; + const abbrevs = std.EnumArray(AbbrevCode, struct { tag: DeclValEnum(DW.TAG), children: bool = false, @@ -2202,35 +2251,38 @@ pub const AbbrevCode = enum { .{ .ZIG_padding, .block }, }, }, + .decl_lost = .{ + .tag = .ZIG_lost_declaration, + }, .decl_alias = .{ .tag = .imported_declaration, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .import, .ref_addr }, }, }, .decl_empty_enum = .{ .tag = .enumeration_type, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .type, .ref_addr }, }, }, .decl_enum = .{ .tag = .enumeration_type, .children = true, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .type, .ref_addr }, }, }, .decl_namespace_struct = .{ .tag = .structure_type, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .declaration, .flag }, }, }, .decl_struct = .{ .tag = .structure_type, .children = true, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .byte_size, .udata }, .{ .alignment, .udata }, }, @@ -2238,14 +2290,14 @@ pub const AbbrevCode = enum { .decl_packed_struct = .{ .tag = .structure_type, .children = true, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .type, .ref_addr }, }, }, .decl_union = .{ .tag = .union_type, .children = true, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .byte_size, .udata }, .{ .alignment, .udata }, }, @@ -2253,13 +2305,13 @@ pub const AbbrevCode = enum { .decl_packed_union = .{ .tag = .union_type, .children = true, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .type, .ref_addr }, }, }, .decl_var = .{ .tag = .variable, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .location, .exprloc }, @@ -2269,7 +2321,7 @@ pub const AbbrevCode = enum { }, .decl_const = .{ .tag = .constant, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .alignment, .udata }, @@ -2278,7 +2330,7 @@ pub const AbbrevCode = enum { }, .decl_const_runtime_bits = .{ .tag = .constant, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .alignment, .udata }, @@ -2288,7 +2340,7 @@ pub const AbbrevCode = enum { }, .decl_const_comptime_state = .{ .tag = .constant, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .alignment, .udata }, @@ -2298,7 +2350,7 @@ pub const AbbrevCode = enum { }, .decl_const_runtime_bits_comptime_state = .{ .tag = .constant, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .alignment, .udata }, @@ -2309,7 +2361,7 @@ pub const AbbrevCode = enum { }, .decl_nullary_func = .{ .tag = .subprogram, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .low_pc, .addr }, @@ -2322,7 +2374,7 @@ pub const AbbrevCode = enum { .decl_func = .{ .tag = .subprogram, .children = true, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .linkage_name, .strp }, //.{ .type, .ref_addr }, .{ .low_pc, .addr }, @@ -2334,20 +2386,20 @@ pub const AbbrevCode = enum { }, .decl_nullary_func_generic = .{ .tag = .subprogram, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .type, .ref_addr }, }, }, .decl_func_generic = .{ .tag = .subprogram, .children = true, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .type, .ref_addr }, }, }, .decl_extern_nullary_func = .{ .tag = .subprogram, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .low_pc, .addr }, @@ -2358,7 +2410,7 @@ pub const AbbrevCode = enum { .decl_extern_func = .{ .tag = .subprogram, .children = true, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .low_pc, .addr }, @@ -2366,47 +2418,47 @@ pub const AbbrevCode = enum { .{ .noreturn, .flag }, }, }, - .generic_decl_var = .{ + .decl_specification_struct = .{ .tag = .variable, - .attrs = generic_decl_abbrev_common_attrs, + .attrs = decl_specification_attrs, }, - .generic_decl_const = .{ + .decl_specification_union = .{ .tag = .constant, - .attrs = generic_decl_abbrev_common_attrs, + .attrs = decl_specification_attrs, }, - .generic_decl_func = .{ + .decl_specification_func = .{ .tag = .subprogram, - .attrs = generic_decl_abbrev_common_attrs, + .attrs = decl_specification_attrs, }, .decl_instance_alias = .{ .tag = .imported_declaration, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .import, .ref_addr }, }, }, .decl_instance_empty_enum = .{ .tag = .enumeration_type, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .type, .ref_addr }, }, }, .decl_instance_enum = .{ .tag = .enumeration_type, .children = true, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .type, .ref_addr }, }, }, .decl_instance_namespace_struct = .{ .tag = .structure_type, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .declaration, .flag }, }, }, .decl_instance_struct = .{ .tag = .structure_type, .children = true, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .byte_size, .udata }, .{ .alignment, .udata }, }, @@ -2414,14 +2466,14 @@ pub const AbbrevCode = enum { .decl_instance_packed_struct = .{ .tag = .structure_type, .children = true, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .type, .ref_addr }, }, }, .decl_instance_union = .{ .tag = .union_type, .children = true, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .byte_size, .udata }, .{ .alignment, .udata }, }, @@ -2429,13 +2481,13 @@ pub const AbbrevCode = enum { .decl_instance_packed_union = .{ .tag = .union_type, .children = true, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .type, .ref_addr }, }, }, .decl_instance_var = .{ .tag = .variable, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .location, .exprloc }, @@ -2445,7 +2497,7 @@ pub const AbbrevCode = enum { }, .decl_instance_const = .{ .tag = .constant, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .alignment, .udata }, @@ -2454,7 +2506,7 @@ pub const AbbrevCode = enum { }, .decl_instance_const_runtime_bits = .{ .tag = .constant, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .alignment, .udata }, @@ -2464,7 +2516,7 @@ pub const AbbrevCode = enum { }, .decl_instance_const_comptime_state = .{ .tag = .constant, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .alignment, .udata }, @@ -2474,7 +2526,7 @@ pub const AbbrevCode = enum { }, .decl_instance_const_runtime_bits_comptime_state = .{ .tag = .constant, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .alignment, .udata }, @@ -2485,7 +2537,7 @@ pub const AbbrevCode = enum { }, .decl_instance_nullary_func = .{ .tag = .subprogram, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .low_pc, .addr }, @@ -2498,7 +2550,7 @@ pub const AbbrevCode = enum { .decl_instance_func = .{ .tag = .subprogram, .children = true, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .low_pc, .addr }, @@ -2510,20 +2562,20 @@ pub const AbbrevCode = enum { }, .decl_instance_nullary_func_generic = .{ .tag = .subprogram, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .type, .ref_addr }, }, }, .decl_instance_func_generic = .{ .tag = .subprogram, .children = true, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .type, .ref_addr }, }, }, .decl_instance_extern_nullary_func = .{ .tag = .subprogram, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .low_pc, .addr }, @@ -2534,7 +2586,7 @@ pub const AbbrevCode = enum { .decl_instance_extern_func = .{ .tag = .subprogram, .children = true, - .attrs = decl_instance_abbrev_common_attrs ++ .{ + .attrs = decl_instance_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, .{ .low_pc, .addr }, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index e20eaebb39e394e7e28517ce7520b7f10fb79a5f..681a86d7f4207a5a8389dfb8233c541bf543b4b8 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1688,8 +1688,8 @@ pub fn updateExports( return self.zigObjectPtr().?.updateExports(self, pt, export_indices); } -pub fn updateLineNumber(self: *Elf, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) link.Error!void { - return self.zigObjectPtr().?.updateLineNumber(pt, ti_id); +pub fn updateLineNumber(self: *Elf, pt: Zcu.PerThread, inst: InternPool.TrackedInst.Index, line: u32) link.Error!void { + return self.zigObjectPtr().?.updateLineNumber(pt, inst, line); } fn checkDuplicates(self: *Elf) !void { diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 27268c24d136157379a9a76f5bf059df9f81c2c6..3fb1450b305d4411ba62ce09147ecb52e41df06e 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -1946,11 +1946,11 @@ pub fn updateExports( } } -pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) link.Error!void { +pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index, line: u32) link.Error!void { if (self.dwarf) |*dwarf| { const comp = dwarf.bin_file.comp; const diags = &comp.link_diags; - dwarf.updateLineNumber(pt.zcu, ti_id) catch |err| switch (err) { + dwarf.updateLineNumber(pt.zcu, ti_id, line) catch |err| switch (err) { error.OutOfMemory, error.Canceled, error.AlreadyReported => |e| return e, else => |e| return diags.fail("failed to update dwarf line numbers: {s}", .{@errorName(e)}), }; diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index 4d17c1c6af9d51e8cb8ae51c4cc2dba19f8d96c6..93e6caa3562d9bf46c0110eff63fa72f4486a456 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -501,7 +501,7 @@ const Section = struct { ni: MappedFile.Node.Index, /// A symbol which is exactly at the start of this section. /// - /// If the section does not have flag `std.elf.SHF.ALLOC`, this is `.null`. + /// When not emitting a relocatable, or for special section types, this is `.null`. lsi: Symbol.LocalIndex, rela: union { /// This field is active if and only if this section is *not* a `SHT_RELA` section. @@ -848,10 +848,10 @@ const Section = struct { } } - /// Asserts that `rela_shndx` is a `SHT_RELA` section, and asserts that `index` refers to an - /// `R_*_RELATIVE` relocation inside of it; then, updates that relocation's addend (which is - /// an address in this DSO without the runtime load offset applied) to the given value. - fn relaSetRelativeOffset(rela_shndx: Index, elf: *Elf, index: RelaIndex, new_addend: u64) void { + /// Asserts that `rela_shndx` is a `SHT_RELA` section and updates the `addend` field of the + /// `ElfN.Rela` entry at the given index. Asserts that `index` is not in the free-list (i.e. + /// it is not deleted). + fn relaSetAddend(rela_shndx: Index, elf: *Elf, index: RelaIndex, new_addend: u64) void { switch (elf.shdrPtr(rela_shndx)) { inline else => |shdr, class| { assert(elf.targetLoad(&shdr.type) == .RELA); @@ -1603,6 +1603,20 @@ const SymbolReloc = struct { } }; + fn flushMovedNode(reloc: *SymbolReloc, elf: *Elf, node_vaddr: u64) void { + if (reloc.rela_index.unwrap()) |rela_index| { + // The node has moved, so the offset of the relocation within the section might have + // changed, so update the `offset` field of the `ElfN.Rela` entry. + reloc.relaSection(elf).relaSetOffset(elf, rela_index, node_vaddr + reloc.offset); + } + // This is not just the inverse of the above condition, because if `reloc` is relative + // to the base of this DSO, then `rela_index` is an `R_*_RELATIVE` relocation, but we + // still need to call `SymbolReloc.apply` to update that relocation's addend. + if (elf.ehdrType() != .REL) { + reloc.apply(elf); + } + } + fn apply(reloc: *SymbolReloc, elf: *Elf) void { assert(elf.ehdrType() != .REL); if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) { @@ -1688,7 +1702,7 @@ const SymbolReloc = struct { } assert(reloc.type.action.simple.cast == .unsigned); assert(reloc.type.action.simple.shift == .@"0"); - elf.shndx.rela_dyn.relaSetRelativeOffset(elf, rela_index, target_val); + elf.shndx.rela_dyn.relaSetAddend(elf, rela_index, target_val); return; }, }; @@ -1767,30 +1781,58 @@ const NodeReloc = struct { } }; + fn flushMovedNode(reloc: *NodeReloc, elf: *Elf, node_vaddr: u64) void { + if (reloc.rela_index.unwrap()) |rela_index| { + assert(elf.ehdrType() == .REL); + // The node has moved, so the offset of the relocation within the section might have + // changed, so update the `offset` field of the `ElfN.Rela` entry. + elf.getNodeShndx(reloc.node).get(elf).rela.shndx.relaSetOffset(elf, rela_index, node_vaddr + reloc.offset); + } else { + assert(elf.ehdrType() != .REL); + reloc.apply(elf); + } + } + + fn flushMovedTarget(reloc: *NodeReloc, elf: *Elf, target_section_offset: u64) void { + if (reloc.rela_index.unwrap()) |rela_index| { + assert(elf.ehdrType() == .REL); + // The target has moved, so the `addend` field of the `ElfN.Rela` entry needs to be updated. + elf.getNodeShndx(reloc.node).get(elf).rela.shndx.relaSetAddend(elf, rela_index, target_section_offset +% @as(u64, @bitCast(reloc.addend))); + } else { + assert(elf.ehdrType() != .REL); + reloc.apply(elf); + } + } + fn apply(reloc: *NodeReloc, elf: *Elf) void { - assert(elf.ehdrType() != .REL); - if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(&elf.mf)) { - // There's no point applying the relocation now, because it will be re-applied by - // `flushMoved` at some point anyway. - return; - } - switch (reloc.result) { - .ok => {}, - .overflowed => elf.overflowed_reloc_count -= 1, - .misaligned => elf.misaligned_reloc_count -= 1, - } - if (reloc.applyInner(elf)) { - @branchHint(.likely); - reloc.result = .ok; - } else |err| switch (err) { - error.RelocationOverflow => { - reloc.result = .overflowed; - elf.overflowed_reloc_count += 1; - }, - error.RelocationMisaligned => { - reloc.result = .misaligned; - elf.misaligned_reloc_count += 1; - }, + if (reloc.rela_index.unwrap()) |rela_index| { + assert(elf.ehdrType() == .REL); + _ = rela_index; + } else { + assert(elf.ehdrType() != .REL); + if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(&elf.mf)) { + // There's no point applying the relocation now, because it will be re-applied by + // `flushMoved` at some point anyway. + return; + } + switch (reloc.result) { + .ok => {}, + .overflowed => elf.overflowed_reloc_count -= 1, + .misaligned => elf.misaligned_reloc_count -= 1, + } + if (reloc.applyInner(elf)) { + @branchHint(.likely); + reloc.result = .ok; + } else |err| switch (err) { + error.RelocationOverflow => { + reloc.result = .overflowed; + elf.overflowed_reloc_count += 1; + }, + error.RelocationMisaligned => { + reloc.result = .misaligned; + elf.misaligned_reloc_count += 1; + }, + } } } fn applyInner(reloc: *const NodeReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void { @@ -5220,7 +5262,42 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); return parent_vaddr + offset; } -fn getNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 { +fn computeNodeSectionOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 { + const parent_ni = ni.parent(&elf.mf).unwrap().?; + const parent_section_offset = parent_section_offset: switch (elf.getNode(parent_ni)) { + .deleted, + .archive, + .archive_header, + .archive_input_member, + .archive_elf_member_header, + .elf, + .ehdr, + .shdr, + .segment, + => unreachable, + .section, .section_manual_size => 0, + .input_section, .copied_global => unreachable, + .nav, .uav, .lazy_code, .lazy_const_data => unreachable, + .debug_shared, .unit_padding => unreachable, + .unit_frame, .unit_debug_info, .unit_debug_line => { + const parent_section_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); + break :parent_section_offset parent_section_offset; + }, + .unit_frame_cie, + .unit_debug_info_header, + .unit_debug_line_header, + .unit_debug_rnglists, + .value_debug_info, + .global_debug_info, + .func_frame_fde, + .func_debug_info, + .func_debug_line, + => unreachable, + }; + const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); + return parent_section_offset + offset; +} +fn computeNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 { return ni.fileLocation(&elf.mf, false).offset - elf.ni.elf.fileLocation(&elf.mf, false).offset; } @@ -5293,8 +5370,8 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { }, .func_debug_info => |fi| .{ .first_symbol_reloc = &elf.dwarf_funcs.items[@backingInt(fi)].debug_info_first_symbol_reloc, - .skip_symbol_relocs = if (elf.navs.getPtr(fi.get(&elf.dwarf).owner_nav)) |owner_nav| - owner_nav.lsi.index().ptr(elf).node + .skip_symbol_relocs = if (elf.navs.getPtr(fi.nav(&elf.dwarf))) |nav| + nav.lsi.index().ptr(elf).node else .none, .first_node_reloc = &elf.dwarf_funcs.items[@backingInt(fi)].debug_info_first_node_reloc, @@ -5358,17 +5435,7 @@ fn flushMovedNodeRelocs( for (elf.symbol_relocs.items[@backingInt(opts.first_symbol_reloc)..]) |*reloc| { if (reloc.node.toOptional() == opts.skip_symbol_relocs) continue; if (reloc.node != node) break; - if (reloc.rela_index.unwrap()) |rela_index| { - // The node has moved, so the offset of the relocation within the section might have - // changed, so update the `offset` field of the `ElfN.Rela` entry. - reloc.relaSection(elf).relaSetOffset(elf, rela_index, node_vaddr + reloc.offset); - } - // This is not just the inverse of the above condition, because if `reloc` is relative - // to the base of this DSO, then `rela_index` is an `R_*_RELATIVE` relocation, but we - // still need to call `SymbolReloc.apply` to update that relocation's addend. - if (elf.ehdrType() != .REL) { - reloc.apply(elf); - } + reloc.flushMovedNode(elf, node_vaddr); } } @@ -5376,15 +5443,7 @@ fn flushMovedNodeRelocs( for (elf.node_relocs.items[@backingInt(opts.first_node_reloc)..]) |*reloc| { if (reloc.node.toOptional() == opts.skip_node_relocs) continue; if (reloc.node != node) break; - if (reloc.rela_index.unwrap()) |rela_index| { - assert(elf.ehdrType() == .REL); - // The node has moved, so the offset of the relocation within the section might have - // changed, so update the `offset` field of the `ElfN.Rela` entry. - elf.getNodeShndx(reloc.node).get(elf).rela.shndx.relaSetOffset(elf, rela_index, node_vaddr + reloc.offset); - } else { - assert(elf.ehdrType() != .REL); - reloc.apply(elf); - } + reloc.flushMovedNode(elf, node_vaddr); } } @@ -7113,7 +7172,7 @@ pub fn zcuFilesReady(elf: *Elf, zcu: *Zcu) link.Error!void { fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void { const gpa = zcu.gpa; - try elf.dwarf.initUnits(zcu); + try elf.dwarf.updateUnits(zcu); const old_units_len = elf.dwarf_units.items.len; const new_units_len = elf.dwarf.units.count(); try elf.dwarf_units.appendNTimes(gpa, .{ @@ -7204,11 +7263,11 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void { defer dih_nw.deinit(); elf.resetNodeRelocs(debug_info_header_ni); elf.dwarf.genDebugInfoHeader( + zcu, mod, unit, &dih_nw, debug_rnglists_offsets_table_offset, - zcu, ) catch |err| switch (err) { else => |e| return e, error.WriteFailed => return dih_nw.err.?, @@ -7397,7 +7456,11 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { const gpa = elf.base.comp.gpa; try elf.nodes.ensureUnusedCapacity(gpa, 1); try elf.shdrs.ensureUnusedCapacity(gpa, 1); - if (opts.flags.ALLOC) try elf.ensureUnusedSymbolCapacity(1, .all_local); + const want_symbol = opts.flags.ALLOC or switch (opts.type) { + .NULL, .PROGBITS, .NOBITS, .X86_64_UNWIND => elf.ehdrType() == .REL, + else => false, + }; + if (want_symbol) try elf.ensureUnusedSymbolCapacity(1, .all_local); const shstrtab_entry = try elf.string(.shstrtab, opts.name); const shndx: Section.Index, const new_shdr_size = shndx: switch (elf.ehdrPtr()) { @@ -7443,19 +7506,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { true => .{ .section_manual_size = shndx }, }); const addr = elf.computeNodeVAddr(ni); - const lsi: Symbol.LocalIndex = if (opts.flags.ALLOC) elf.addLocalSymbolAssumeCapacity(.{ - .node = .wrap(ni), - .name = .empty, - .value = addr, - .size = 0, - .type = .SECTION, - .shndx = shndx, - }) else .null; - elf.shdrs.appendAssumeCapacity(.{ .lsi = lsi, .ni = ni, .rela = switch (opts.type) { - .REL => unreachable, - .RELA => .{ .free_head = .none }, - else => .{ .shndx = .UNDEF }, - } }); + elf.shdrs.appendAssumeCapacity(.{ + .lsi = if (want_symbol) elf.addLocalSymbolAssumeCapacity(.{ + .node = ni.toOptional(), + .name = .empty, + .value = addr, + .size = 0, + .type = .SECTION, + .shndx = shndx, + }) else .null, + .ni = ni, + .rela = switch (opts.type) { + .REL => unreachable, + .RELA => .{ .free_head = .none }, + else => .{ .shndx = .UNDEF }, + }, + }); switch (elf.shdrPtr(shndx)) { inline else => |shdr, class| { shdr.* = .{ @@ -7463,7 +7529,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { .type = opts.type, .flags = .{ .shf = opts.flags }, .addr = @intCast(addr), - .offset = @intCast(elf.getNodeElfOffset(ni)), + .offset = @intCast(elf.computeNodeElfOffset(ni)), .size = @intCast(opts.size), .link = opts.link, .info = opts.info, @@ -8068,7 +8134,7 @@ fn addNodeRelocAssumeCapacity( .abs32 => .UA32, .abs64 => .UA64, } }, - .X86_64 => .{ .SPARC = switch (@"type") { + .X86_64 => .{ .X86_64 = switch (@"type") { .abs32 => .@"32", .abs64 => .@"64", } }, @@ -8078,8 +8144,11 @@ fn addNodeRelocAssumeCapacity( // the section offset now, but there's no point, because `flushMovedNodeRelocs` will // eventually do it for us anyway, so just init to 0. .offset = 0, - .raw_sym_index = @backingInt(shndx.get(elf).lsi.index()), - .addend = addend, + .raw_sym_index = @backingInt(switch (shndx.get(elf).lsi) { + .null => unreachable, + else => |lsi| lsi.index(), + }), + .addend = 0, }); elf.node_relocs.appendAssumeCapacity(.{ .node = node, @@ -8576,7 +8645,8 @@ fn updateFuncInner( const debug_output: link.File.DebugInfoOutput, const dwarf_func = debug_output: { if (elf.ehdrMachine() != .X86_64) break :debug_output .{ .none, undefined }; const dwarf = &elf.dwarf; - const mod = zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?; + const src_inst = nav.srcInst(ip); + const mod = zcu.fileByIndex(src_inst.resolveFile(ip)).mod.?; if (mod.strip and mod.unwind_tables == .none) break :debug_output .{ .none, undefined }; try elf.nodes.ensureUnusedCapacity(gpa, 4); @@ -8662,6 +8732,7 @@ fn updateFuncInner( debug.blocks = .empty; const debug_info_ni = dwarf_func.debug_info_ni.unwrap().?; + try dwarf.decls.put(zcu.comp.gpa, src_inst, debug_info_ni); try debug_info_ni.moved(gpa, &elf.mf); try debug_info_ni.nextMoved(gpa, &elf.mf); debug_info_ni.writer(gpa, &elf.mf, &debug.info_writer); @@ -8787,23 +8858,31 @@ fn updateFuncInner( try elf.genPending(pt); } -pub fn updateLineNumber(elf: *Elf, pt: Zcu.PerThread, src_inst: InternPool.TrackedInst.Index) void { - const func = elf.dwarf.funcs.getPtr(src_inst) orelse return; - elf.dwarf.updateLineNumber(pt.zcu, src_inst, func.debug_info_ni.unwrap().?.slice(&elf.mf)); +pub fn updateLineNumber( + elf: *Elf, + _: Zcu.PerThread, + inst: InternPool.TrackedInst.Index, + line: u32, +) void { + elf.dwarf.updateLineNumber(&elf.mf, inst, line); } pub fn lostTracking( elf: *Elf, _: Zcu.PerThread, - src_inst: InternPool.TrackedInst.Index, -) std.mem.Allocator.Error!void { - const func = elf.dwarf.funcs.getPtr(src_inst) orelse return; - elf.resetNodeRelocs(func.fde_ni.unwrap().?); - elf.resetNodeRelocs(func.debug_info_ni.unwrap().?); - elf.resetNodeRelocs(func.debug_line_ni.unwrap().?); - try elf.deleteNode(&func.fde_ni); - try elf.deleteNode(&func.debug_info_ni); - try elf.deleteNode(&func.debug_line_ni); + inst: InternPool.TrackedInst.Index, +) link.Error!void { + const decl_ni = elf.dwarf.decls.get(inst) orelse return; + const comp = elf.base.comp; + var diw: std.Io.Writer = .fixed(decl_ni.slice(&elf.mf)); + elf.resetNodeRelocs(decl_ni); + diw.writeUleb128(try elf.dwarf.refAbbrevCode(.decl_lost)) catch unreachable; + decl_ni.resizeLeaf(comp.gpa, &elf.mf, diw.end) catch |err| switch (err) { + error.MappedFileIo => return comp.link_diags.fail("failed to write output file: {t}", .{ + elf.mf.io_err.?, + }), + else => |e| return e, + }; } pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void { @@ -9127,7 +9206,7 @@ fn idleProgNode( .func_debug_info => "debug", .func_debug_line => "line", }, - ip.getNav(fi.get(&elf.dwarf).owner_nav).fqn.fmt(ip), + ip.getNav(fi.nav(&elf.dwarf)).fqn.fmt(ip), }) catch &name; }, }, 0); @@ -9304,7 +9383,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void { } fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void { - const elf_offset = elf.getNodeElfOffset(ni); + const elf_offset = elf.computeNodeElfOffset(ni); switch (elf.getNode(ni)) { else => unreachable, .ehdr => assert(elf_offset == 0), @@ -9508,32 +9587,34 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void }); }, .debug_shared => |ss| { + const target_section_offset = elf.computeNodeSectionOffset(ni); var target_ri = elf.dwarf_shared.getPtr(ss).first_target_reloc; while (target_ri != .none) { const target_reloc = target_ri.get(elf); assert(target_reloc.target == ni); - target_reloc.apply(elf); + target_reloc.flushMovedTarget(elf, target_section_offset); target_ri = target_reloc.next; } }, .unit_padding, .unit_frame, .unit_debug_info, .unit_debug_line => {}, .unit_frame_cie => |ui| { - const dwarf_unit = &elf.dwarf_units.items[@backingInt(ui)]; - var target_ri = dwarf_unit.frame_cie_first_target_reloc; + const target_section_offset = elf.computeNodeSectionOffset(ni); + var target_ri = elf.dwarf_units.items[@backingInt(ui)].frame_cie_first_target_reloc; while (target_ri != .none) { const target_reloc = target_ri.get(elf); assert(target_reloc.target == ni); - target_reloc.apply(elf); + target_reloc.flushMovedTarget(elf, target_section_offset); target_ri = target_reloc.next; } }, .unit_debug_info_header => |ui| { const dwarf_unit = &elf.dwarf_units.items[@backingInt(ui)]; + const target_section_offset = elf.computeNodeSectionOffset(ni); var target_ri = dwarf_unit.debug_info_header_first_target_reloc; while (target_ri != .none) { const target_reloc = target_ri.get(elf); assert(target_reloc.target == ni); - target_reloc.apply(elf); + target_reloc.flushMovedTarget(elf, target_section_offset); target_ri = target_reloc.next; } elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{ @@ -9542,11 +9623,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void }, .unit_debug_line_header => |ui| { const dwarf_unit = &elf.dwarf_units.items[@backingInt(ui)]; + const target_section_offset = elf.computeNodeSectionOffset(ni); var target_ri = dwarf_unit.debug_line_header_first_target_reloc; while (target_ri != .none) { const target_reloc = target_ri.get(elf); assert(target_reloc.target == ni); - target_reloc.apply(elf); + target_reloc.flushMovedTarget(elf, target_section_offset); target_ri = target_reloc.next; } elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{ @@ -9555,34 +9637,29 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void }, .unit_debug_rnglists => |ui| { const dwarf_unit = &elf.dwarf_units.items[@backingInt(ui)]; + const target_section_offset = elf.computeNodeSectionOffset(ni); var target_ri = dwarf_unit.debug_rnglists_first_target_reloc; while (target_ri != .none) { const target_reloc = target_ri.get(elf); assert(target_reloc.target == ni); - target_reloc.apply(elf); + target_reloc.flushMovedTarget(elf, target_section_offset); target_ri = target_reloc.next; } const node_vaddr = elf.computeNodeVAddr(ni); for (dwarf_unit.debug_rnglists_symbol_relocs.keys()) |symbol_ri| { const symbol_reloc = symbol_ri.get(elf); assert(symbol_reloc.node == ni); - if (symbol_reloc.rela_index.unwrap()) |rela_index| { - // The node has moved, so the offset of the relocation within the section might have - // changed, so update the `offset` field of the `ElfN.Rela` entry. - symbol_reloc.relaSection(elf).relaSetOffset(elf, rela_index, node_vaddr + symbol_reloc.offset); - } - if (elf.ehdrType() != .REL) { - symbol_reloc.apply(elf); - } + symbol_reloc.flushMovedNode(elf, node_vaddr); } }, .value_debug_info => |vi| { const dwarf_value = &elf.dwarf_values.items[@backingInt(vi)]; + const target_section_offset = elf.computeNodeSectionOffset(ni); var target_ri = dwarf_value.debug_info_first_target_reloc; while (target_ri != .none) { const target_reloc = target_ri.get(elf); assert(target_reloc.target == ni); - target_reloc.apply(elf); + target_reloc.flushMovedTarget(elf, target_section_offset); target_ri = target_reloc.next; } elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{ @@ -9592,11 +9669,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void }, .global_debug_info => |vi| { const dwarf_global = &elf.dwarf_globals.items[@backingInt(vi)]; + const target_section_offset = elf.computeNodeSectionOffset(ni); var target_ri = dwarf_global.debug_info_first_target_reloc; while (target_ri != .none) { const target_reloc = target_ri.get(elf); assert(target_reloc.target == ni); - target_reloc.apply(elf); + target_reloc.flushMovedTarget(elf, target_section_offset); target_ri = target_reloc.next; } elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{ @@ -9607,7 +9685,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void .func_frame_fde => |fi| { const dwarf_func = &elf.dwarf_funcs.items[@backingInt(fi)]; const zcu = elf.base.comp.zcu.?; - const mod = zcu.fileByIndex(fi.srcInst(&elf.dwarf).resolveFile(&zcu.intern_pool)).mod.?; + const mod = zcu.navFileScope(fi.nav(&elf.dwarf)).mod.?; switch (mod.unwind_tables) { .none => {}, .sync, .async => { @@ -9622,17 +9700,18 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void }, .func_debug_info => |fi| { const dwarf_func = &elf.dwarf_funcs.items[@backingInt(fi)]; + const target_section_offset = elf.computeNodeSectionOffset(ni); var target_ri = dwarf_func.debug_info_first_target_reloc; while (target_ri != .none) { const target_reloc = target_ri.get(elf); assert(target_reloc.target == ni); - target_reloc.apply(elf); + target_reloc.flushMovedTarget(elf, target_section_offset); target_ri = target_reloc.next; } elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{ .first_symbol_reloc = dwarf_func.debug_info_first_symbol_reloc, - .skip_symbol_relocs = if (elf.navs.getPtr(fi.get(&elf.dwarf).owner_nav)) |owner_nav| - owner_nav.lsi.index().ptr(elf).node + .skip_symbol_relocs = if (elf.navs.getPtr(fi.nav(&elf.dwarf))) |nav| + nav.lsi.index().ptr(elf).node else .none, .first_node_reloc = dwarf_func.debug_info_first_node_reloc, @@ -10630,10 +10709,10 @@ pub fn printNode( .func_frame_fde, .func_debug_info, .func_debug_line => |fi| { const zcu = elf.base.comp.zcu.?; const ip = &zcu.intern_pool; - const owner_nav = ip.getNav(fi.get(&elf.dwarf).owner_nav); + const nav = ip.getNav(fi.nav(&elf.dwarf)); try w.print("({f}, {f})", .{ - Type.fromInterned(owner_nav.resolved.?.type).fmt(.{ .zcu = zcu, .tid = tid }), - owner_nav.fqn.fmt(ip), + Type.fromInterned(nav.resolved.?.type).fmt(.{ .zcu = zcu, .tid = tid }), + nav.fqn.fmt(ip), }); }, } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 0a2c0c9c50c14065f77e166fac72b68ef6820bb0..9e17264efa630896211fc511fa56e803987b9219 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -3095,8 +3095,8 @@ pub fn updateNav(self: *MachO, pt: Zcu.PerThread, nav: InternPool.Nav.Index) lin return self.getZigObject().?.updateNav(self, pt, nav); } -pub fn updateLineNumber(self: *MachO, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) link.Error!void { - return self.getZigObject().?.updateLineNumber(pt, ti_id); +pub fn updateLineNumber(self: *MachO, pt: Zcu.PerThread, inst: InternPool.TrackedInst.Index, line: u32) link.Error!void { + return self.getZigObject().?.updateLineNumber(pt, inst, line); } pub fn updateExports( diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 3ae2cda02926c7dcf650d050d59785ee8b276acf..7f27237432b084917e457a34c495e20912290762 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -1412,11 +1412,11 @@ fn updateLazySymbol( try macho_file.pwriteAll(code, file_offset); } -pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) link.Error!void { +pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index, line: u32) link.Error!void { if (self.dwarf) |*dwarf| { const comp = dwarf.bin_file.comp; const diags = &comp.link_diags; - dwarf.updateLineNumber(pt.zcu, ti_id) catch |err| switch (err) { + dwarf.updateLineNumber(pt.zcu, ti_id, line) catch |err| switch (err) { error.OutOfMemory, error.Canceled, error.AlreadyReported => |e| return e, else => |e| return diags.fail("failed to update dwarf line numbers: {s}", .{@errorName(e)}), }; diff --git a/src/link/Spork8.zig b/src/link/Spork8.zig index 3487387c55b2d52580494793ce34c5e11a36a764..32c983ce1c7a407f75101bf2d5ff982373dd3820 100644 --- a/src/link/Spork8.zig +++ b/src/link/Spork8.zig @@ -168,10 +168,11 @@ pub fn updateNav(spork8: *Spork8, pt: Zcu.PerThread, nav_index: InternPool.Nav.I log.debug("updateNav {f}", .{nav.fqn.fmt(ip)}); } -pub fn updateLineNumber(spork8: *Spork8, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { +pub fn updateLineNumber(spork8: *Spork8, pt: Zcu.PerThread, inst: InternPool.TrackedInst.Index, line: u32) !void { _ = spork8; _ = pt; - _ = ti_id; + _ = inst; + _ = line; } pub fn deleteExport( diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 56b82fef3b02e2917ec78e5e22c0bd93c3688eae..6f393c7b836d8674e70d220c5eabac58ef3d1391 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -3728,11 +3728,11 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index } } -pub fn updateLineNumber(wasm: *Wasm, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) link.Error!void { +pub fn updateLineNumber(wasm: *Wasm, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index, line: u32) link.Error!void { const comp = wasm.base.comp; const diags = &comp.link_diags; if (wasm.dwarf) |*dw| { - dw.updateLineNumber(pt.zcu, ti_id) catch |err| switch (err) { + dw.updateLineNumber(pt.zcu, ti_id, line) catch |err| switch (err) { error.OutOfMemory, error.Canceled, error.AlreadyReported => |e| return e, else => |e| return diags.fail("failed to update dwarf line numbers: {s}", .{@errorName(e)}), }; -- 2.54.0