authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-08-17 19:00:21-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-03 12:59:38-04:00
log84c2fd3d781b8843dfd3565139282fddf60e4e97
treef27ecfebd78e4b0d66341502a1e8dc61e1f0bfe2
parentea682d27a14176ef5bc07c2538a4388f31bf8161

Dwarf2: implement more type debug info


3 files changed, 413 insertions(+), 130 deletions(-)

src/link/Coff.zig+22-14
......@@ -7756,22 +7756,30 @@ pub fn printNode(
77567756 }
77577757 return;
77587758 }
7759 const file_loc = ni.fileLocation(&coff.mf, false);
7760 if (file_loc.size == 0) return;
7761 var address = file_loc.offset;
7759 const start_address: usize, const end_address: usize = file_loc: {
7760 const file_loc = ni.fileLocation(&coff.mf, false);
7761 break :file_loc .{ @intCast(file_loc.offset), @intCast(file_loc.offset + file_loc.size) };
7762 };
7763 var address = start_address;
77627764 const line_len = 0x10;
7763 var line_it = std.mem.window(
7764 u8,
7765 coff.mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
7766 line_len,
7767 line_len,
7768 );
7769 while (line_it.next()) |line_bytes| : (address += line_len) {
7765 while (true) : (address = @min(std.mem.alignForward(usize, address + 1, line_len), end_address)) {
77707766 try w.splatByteAll(' ', indent + 1);
7771 try w.print("{x:0>8} ", .{address});
7772 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});
7773 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);
7774 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');
7767 try w.print("{x:0>8}", .{address});
7768 if (address == end_address) break try w.writeByte('\n');
7769 try w.splatByteAll(' ', 2);
7770 const start_byte_address = std.mem.alignBackward(usize, address, line_len);
7771 const end_byte_address = start_byte_address + line_len;
7772 for (start_byte_address..end_byte_address) |byte_address|
7773 if (byte_address < start_address or byte_address >= end_address)
7774 try w.splatByteAll(' ', 3)
7775 else
7776 try w.print("{x:0>2} ", .{coff.mf.memory_map.memory[byte_address]});
7777 try w.writeByte(' ');
7778 for (start_byte_address..@min(end_address, end_byte_address)) |byte_address|
7779 try w.writeByte(if (byte_address < start_address or byte_address >= end_address) ' ' else char: {
7780 const byte = coff.mf.memory_map.memory[byte_address];
7781 break :char if (std.ascii.isPrint(byte)) byte else '.';
7782 });
77757783 try w.writeByte('\n');
77767784 }
77777785}
src/link/Dwarf2.zig+295-74
......@@ -635,8 +635,12 @@ pub const WipNav = struct {
635635 const zcu = debug.pt.zcu;
636636 const ip = &zcu.intern_pool;
637637 const func = zcu.funcInfo(debug.wip_nav.func);
638 const func_type = ip.indexToKey(func.ty).func_type;
638639 const inst_info = ip.getNav(func.owner_nav).srcInst(ip).resolveFull(ip).?;
639 const decl = zcu.fileByIndex(inst_info.file).zir.?.getDeclaration(inst_info.inst);
640 const zf = zcu.fileByIndex(inst_info.file);
641 const mod = zf.mod.?;
642 const target = &mod.resolved_target.result;
643 const decl = zf.zir.?.getDeclaration(inst_info.inst);
640644 const nav = ip.getNav(func.owner_nav);
641645 const diw = &debug.info_writer.interface;
642646 try diw.writeUleb128(try dwarf.refAbbrevCode(.decl_func));
......@@ -645,10 +649,19 @@ pub const WipNav = struct {
645649 try diw.writeUleb128(decl.src_column + 1);
646650 try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
647651 try debug.strp(nav.name.toSlice(ip));
648 try debug.strp(nav.fqn.toSlice(ip));
652 try debug.strp(switch (decl.linkage) {
653 .normal => nav.fqn,
654 .@"extern", .@"export" => nav.name,
655 }.toSlice(ip));
656 try debug.refType(.fromInterned(func_type.return_type));
649657 try dwarf.symbolAddress(&debug.info_writer, debug.wip_nav.func_si, 0);
650658 debug.info_func_length_offset = diw.end;
651659 try diw.writeInt(u32, undefined, dwarf.endian);
660 try diw.writeUleb128(
661 target_info.minFunctionAlignment(target).max(nav.resolved.?.@"align").toByteUnits().?,
662 );
663 try diw.writeByte(@intFromBool(decl.linkage != .normal));
664 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
652665 }
653666
654667 pub fn startDebugLine(debug: *Debug) link.Error!void {
......@@ -1712,7 +1725,7 @@ pub fn genDebugInfoHeader(
17121725 try dwarf.strp(&dwarf.debug_line_str, dih_nw, mod.root_src_path);
17131726 try dwarf.sectionOffset(
17141727 dih_nw,
1715 dwarf.getUnit(comp.root_mod).get(dwarf).debug_info_header_ni.unwrap().?,
1728 dwarf.getUnit(zcu.root_mod).get(dwarf).debug_info_header_ni.unwrap().?,
17161729 compile_unit_offset,
17171730 );
17181731 try dwarf.sectionOffset(dih_nw, unit.debug_line_header_ni.unwrap().?, 0);
......@@ -1726,11 +1739,14 @@ pub fn genDebugInfoHeader(
17261739 try dihw.writeUleb128(try dwarf.refAbbrevCode(.module));
17271740 try dwarf.strp(&dwarf.debug_str, dih_nw, mod.fully_qualified_name);
17281741 try dihw.writeUleb128(0);
1729 for ([_][]const u8{ "builtin", "root", "std" }, [_]*Module{
1742 try dwarf.genModuleDependency(
1743 dih_nw,
1744 "builtin",
17301745 zcu.builtin_modules.get(mod.getBuiltinOptions(comp.config).hash()).?,
1731 zcu.root_mod,
1732 zcu.std_mod,
1733 }) |name, dep| try dwarf.genModuleDependency(dih_nw, name, dep, module_offset);
1746 module_offset,
1747 );
1748 try dwarf.genModuleDependency(dih_nw, "root", zcu.root_mod, module_offset);
1749 try dwarf.genModuleDependency(dih_nw, "std", zcu.std_mod, module_offset);
17341750 for (mod.deps.keys(), mod.deps.values()) |name, dep|
17351751 try dwarf.genModuleDependency(dih_nw, name, dep, module_offset);
17361752 for ([2]AbbrevCode{ .pad_1, .pad_n }) |pad| _ = try dwarf.refAbbrevCode(pad);
......@@ -1739,18 +1755,17 @@ pub fn genDebugInfoHeader(
17391755
17401756fn genModuleDependency(
17411757 dwarf: *Dwarf,
1742 nw: *MappedFile.Node.Writer,
1758 di_nw: *MappedFile.Node.Writer,
17431759 name: []const u8,
17441760 dep: *Module,
17451761 module_offset: usize,
17461762) link.EmitError!void {
17471763 const dep_unit = dwarf.getUnit(dep).get(dwarf);
17481764 if (!dep_unit.alive) return;
1749 const diw = &nw.interface;
1765 const diw = &di_nw.interface;
17501766 try diw.writeUleb128(try dwarf.refAbbrevCode(.module_dependency));
1751 try diw.writeAll(name);
1752 try diw.writeByte(0);
1753 try dwarf.sectionOffset(nw, dep_unit.debug_info_header_ni.unwrap().?, module_offset);
1767 try dwarf.strp(&dwarf.debug_str, di_nw, name);
1768 try dwarf.sectionOffset(di_nw, dep_unit.debug_info_header_ni.unwrap().?, module_offset);
17541769}
17551770
17561771pub fn genDebugInfoPadding(dwarf: *Dwarf, diw: *Writer, size: u64) Writer.Error!void {
......@@ -1948,9 +1963,10 @@ pub fn updateComptimeNav(
19481963 pt: Zcu.PerThread,
19491964 nav_index: InternPool.Nav.Index,
19501965) link.Error!void {
1951 const zcu = dwarf.lf.comp.zcu.?;
1966 const zcu = pt.zcu;
19521967 const ip = &zcu.intern_pool;
19531968 const nav = ip.getNav(nav_index);
1969 log.debug("updateComptimeNav({f})", .{nav.fqn.fmt(ip)});
19541970 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
19551971 const nav_val: Value = .fromInterned(nav.resolved.?.value);
19561972 const file = zcu.fileByIndex(inst_info.file);
......@@ -1998,6 +2014,7 @@ pub fn updateComptimeNav(
19982014 defer di_nw.deinit();
19992015 const parent_cpi = try dwarf.getConst(pt, .fromInterned(zcu.fileRootType(inst_info.file)));
20002016 dwarf.genDeclFuncGeneric(
2017 pt,
20012018 &di_nw,
20022019 zir,
20032020 parent_cpi,
......@@ -2020,6 +2037,7 @@ pub fn updateComptimeNav(
20202037}
20212038fn genDeclFuncGeneric(
20222039 dwarf: *Dwarf,
2040 pt: Zcu.PerThread,
20232041 di_nw: *MappedFile.Node.Writer,
20242042 zir: *const std.zig.Zir,
20252043 parent_cpi: link.ConstPool.Index,
......@@ -2035,75 +2053,268 @@ fn genDeclFuncGeneric(
20352053 try diw.writeUleb128(decl.src_column + 1);
20362054 try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
20372055 try dwarf.strp(&dwarf.debug_str, di_nw, name);
2038 for (param_body) |param_inst| switch (zir.getParamName(param_inst) orelse continue) {
2039 .empty => {
2040 try diw.writeUleb128(try dwarf.refAbbrevCode(.unnamed_arg));
2041 try diw.writeUleb128(0);
2042 },
2043 else => |param_name| {
2044 try diw.writeUleb128(try dwarf.refAbbrevCode(.arg));
2045 try dwarf.strp(&dwarf.debug_str, di_nw, zir.nullTerminatedString(param_name));
2046 try diw.writeUleb128(0);
2047 },
2048 };
2056 var param_index: u32 = 0;
2057 for (param_body) |param_inst| {
2058 switch (zir.getParamName(param_inst) orelse break) {
2059 .empty => try diw.writeUleb128(try dwarf.refAbbrevCode(.unnamed_param)),
2060 else => |param_name| {
2061 try diw.writeUleb128(try dwarf.refAbbrevCode(.param));
2062 try dwarf.strp(&dwarf.debug_str, di_nw, zir.nullTerminatedString(param_name));
2063 },
2064 }
2065 try dwarf.sectionOffset(di_nw, Const.get(try dwarf.getConst(
2066 pt,
2067 .fromInterned(fn_ty.param_types.get(&pt.zcu.intern_pool)[param_index]),
2068 ), dwarf).debug_info_ni.unwrap().?, 0);
2069 param_index += 1;
2070 }
20492071 if (fn_ty.is_var_args) try diw.writeUleb128(try dwarf.refAbbrevCode(.is_var_args));
20502072 try diw.writeUleb128(@backingInt(AbbrevCode.null));
20512073 try dwarf.genDebugInfoPadding(diw, diw.unusedCapacityLen());
20522074}
20532075
2054pub fn addConst(dwarf: *Dwarf, cpi: link.ConstPool.Index, val: InternPool.Index) link.Error!void {
2076pub fn addConst(
2077 dwarf: *Dwarf,
2078 cpi: link.ConstPool.Index,
2079 val: InternPool.Index,
2080 addConstNode: *const fn (
2081 lf: *link.File,
2082 ui: Dwarf.Unit.Index,
2083 cpi: link.ConstPool.Index,
2084 ) link.Error!MappedFile.Node.Index,
2085) link.Error!void {
20552086 const comp = dwarf.lf.comp;
20562087 const zcu = comp.zcu.?;
20572088 const ip = &zcu.intern_pool;
2058 try dwarf.consts.ensureUnusedCapacity(comp.gpa, 1);
20592089
20602090 assert(@backingInt(cpi) == dwarf.consts.items.len);
2061 dwarf.consts.appendAssumeCapacity(.{
2062 .debug_info_ni = switch (ip.indexToKey(val)) {
2063 else => .none,
2064 .struct_type, .union_type, .enum_type, .opaque_type => |_, tag| debug_info_ni: {
2091 try dwarf.consts.append(comp.gpa, .{
2092 .debug_info_ni = debug_info_ni: switch (ip.indexToKey(val)) {
2093 else => try addConstNode(dwarf.lf, dwarf.getUnit(zcu.root_mod), cpi),
2094 .func => |func| {
2095 const fi = try dwarf.getFunc(func.owner_nav);
2096 break :debug_info_ni fi.get(dwarf).debug_info_ni.unwrap().?;
2097 },
2098 .@"extern" => |@"extern"| {
2099 const gi = try dwarf.getGlobal(@"extern".owner_nav);
2100 break :debug_info_ni gi.get(dwarf).debug_info_ni.unwrap().?;
2101 },
2102 .struct_type, .union_type, .enum_type, .opaque_type => |_, tag| {
20652103 if (switch (tag) {
2104 else => unreachable,
20662105 .struct_type => ip.loadStructType(val).name_nav,
20672106 .union_type => ip.loadUnionType(val).name_nav,
20682107 .enum_type => ip.loadEnumType(val).name_nav,
20692108 .opaque_type => ip.loadOpaqueType(val).name_nav,
2070 else => unreachable,
20712109 }.unwrap()) |name_nav| {
20722110 const name_gi = try dwarf.getGlobal(name_nav);
20732111 break :debug_info_ni name_gi.get(dwarf).debug_info_ni.unwrap().?;
20742112 }
2075 const elf = dwarf.lf.cast(.elf2).?;
2076 try elf.nodes.ensureUnusedCapacity(comp.gpa, 1);
2077 try elf.dwarf_consts.ensureUnusedCapacity(comp.gpa, 1);
2078 const src_inst = Type.fromInterned(val).typeDeclInstAllowGeneratedTag(zcu).?;
2079 const unit = dwarf.getUnit(zcu.fileByIndex(src_inst.resolveFile(ip)).mod.?).get(dwarf);
2080 const debug_info_ni = elf.addNodeAssumeCapacity(
2081 unit.debug_info_ni.unwrap().?.addFloatingChild(comp.gpa, &elf.mf, .{
2082 .enable_next_moved = true,
2083 }) catch |err| switch (err) {
2084 else => |e| return e,
2085 error.MappedFileIo => return comp.link_diags.fail("failed to write output file: {t}", .{
2086 elf.mf.io_err.?,
2087 }),
2088 },
2089 .{ .const_debug_info = cpi },
2090 );
2091 elf.dwarf_consts.putAssumeCapacity(cpi, .{
2092 .debug_info_first_target_reloc = .none,
2093 .debug_info_first_symbol_reloc = .none,
2094 .debug_info_first_node_reloc = .none,
2095 });
2096
2097 break :debug_info_ni debug_info_ni;
2098 }.toOptional(),
2099 },
2113 break :debug_info_ni try addConstNode(dwarf.lf, dwarf.getUnit(zcu.fileByIndex(
2114 Type.fromInterned(val).typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip),
2115 ).mod.?), cpi);
2116 },
2117 }.toOptional(),
21002118 });
21012119}
21022120
2103pub fn updateConst(dwarf: *Dwarf, cpi: link.ConstPool.Index, val: InternPool.Index) void {
2104 _ = dwarf;
2105 _ = cpi;
2106 _ = val;
2121pub fn updateConst(
2122 dwarf: *Dwarf,
2123 pt: Zcu.PerThread,
2124 di_nw: *MappedFile.Node.Writer,
2125 val: InternPool.Index,
2126) link.Error!void {
2127 switch (val) {
2128 .generic_poison_type => log.debug("updateConst(anytype)", .{}),
2129 else => log.debug("updateConst({f})", .{Value.fromInterned(val).fmtValue(pt)}),
2130 }
2131 dwarf.updateConstInner(pt, di_nw, val) catch |err| switch (err) {
2132 else => |e| return e,
2133 error.WriteFailed => return dwarf.reportWriteError(di_nw),
2134 };
2135}
2136fn updateConstInner(
2137 dwarf: *Dwarf,
2138 pt: Zcu.PerThread,
2139 di_nw: *MappedFile.Node.Writer,
2140 val: InternPool.Index,
2141) link.EmitError!void {
2142 const zcu = pt.zcu;
2143 const ip = &zcu.intern_pool;
2144 const diw = &di_nw.interface;
2145 switch (ip.indexToKey(val)) {
2146 else => return,
2147 .struct_type => {
2148 const loaded_struct = ip.loadStructType(val);
2149 const ty: Type = .fromInterned(val);
2150 const file = loaded_struct.zir_index.resolveFile(ip);
2151 switch (loaded_struct.layout) {
2152 .auto, .@"extern" => {
2153 const struct_is_file: bool = if (loaded_struct.zir_index.resolve(ip)) |inst|
2154 inst == .main_struct_inst
2155 else
2156 false;
2157 if (loaded_struct.name_nav.unwrap()) |nav_index| {
2158 assert(!struct_is_file);
2159 const nav = ip.getNav(nav_index);
2160 const decl_inst = nav.srcInst(ip).resolve(ip).?;
2161 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
2162 try diw.writeUleb128(try dwarf.refAbbrevCode(
2163 if (loaded_struct.field_types.len == 0) .decl_namespace_struct else .decl_struct,
2164 ));
2165 try dwarf.sectionOffset(di_nw, Const.get(
2166 try dwarf.getConst(pt, .fromInterned(zcu.fileRootType(file))),
2167 dwarf,
2168 ).debug_info_ni.unwrap().?, 0);
2169 try diw.writeInt(u32, decl.src_line + 1, dwarf.endian);
2170 try diw.writeUleb128(decl.src_column + 1);
2171 try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
2172 try dwarf.strp(&dwarf.debug_str, di_nw, nav.name.toSlice(ip));
2173 } else {
2174 const zfi = loaded_struct.zir_index.resolveFile(ip);
2175 const ui = dwarf.getUnit(zcu.fileByIndex(zfi).mod.?);
2176 _, const fi = try ui.get(dwarf).getFile(zcu.gpa, ui, zfi);
2177 try diw.writeUleb128(try dwarf.refAbbrevCode(switch (loaded_struct.field_types.len) {
2178 0 => if (struct_is_file) .empty_file else .empty_struct_type,
2179 else => if (struct_is_file) .file else .struct_type,
2180 }));
2181 try diw.writeUleb128(@backingInt(fi));
2182 try dwarf.strp(&dwarf.debug_str, di_nw, loaded_struct.name.toSlice(ip));
2183 }
2184 if (loaded_struct.field_types.len == 0) {
2185 if (!struct_is_file) try diw.writeByte(@intFromBool(false));
2186 } else {
2187 try diw.writeUleb128(ty.abiSize(zcu));
2188 try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
2189 for (0..loaded_struct.field_types.len) |field_index| {
2190 const is_comptime = loaded_struct.field_is_comptime_bits.get(ip, field_index);
2191 // TODO: we currently don't emit information about default values for
2192 // non-`comptime` fields, because these default values are resolved at a
2193 // separate time in the compiler frontend. To emit this information, the
2194 // frontend needs to tell us when the default values are available: like
2195 // how `Zcu.PerThread.ensureTypeLayoutUpToDate` enqueues a link task to
2196 // indicate completion of the type's layout, a task should be enqueued
2197 // by `Zcu.PerThread.ensureStructDefaultsUpToDate`, and upon receiving
2198 // it we should patch the correct default field values in.
2199 const field_init: InternPool.Index = if (is_comptime) loaded_struct.field_defaults.getOrNone(ip, field_index) else .none;
2200 assert(!(is_comptime and field_init == .none));
2201 const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
2202 const has_runtime_bits, const has_comptime_state = switch (field_init) {
2203 .none => .{ false, false },
2204 else => .{
2205 field_type.hasRuntimeBits(zcu),
2206 field_type.comptimeOnly(zcu),
2207 },
2208 };
2209 try diw.writeUleb128(try dwarf.refAbbrevCode(if (is_comptime)
2210 if (has_comptime_state)
2211 .field_comptime_comptime_state
2212 else if (has_runtime_bits)
2213 .field_comptime_runtime_bits
2214 else
2215 .field_comptime
2216 else if (field_init != .none)
2217 if (has_comptime_state)
2218 .field_default_comptime_state
2219 else if (has_runtime_bits)
2220 .field_default_runtime_bits
2221 else
2222 .field
2223 else
2224 .field));
2225 try dwarf.strp(
2226 &dwarf.debug_str,
2227 di_nw,
2228 loaded_struct.field_names.get(ip)[field_index].toSlice(ip),
2229 );
2230 try dwarf.sectionOffset(di_nw, Const.get(
2231 try dwarf.getConst(pt, field_type.toValue()),
2232 dwarf,
2233 ).debug_info_ni.unwrap().?, 0);
2234 if (!is_comptime) {
2235 try diw.writeUleb128(loaded_struct.field_offsets.get(ip)[field_index]);
2236 try diw.writeUleb128(loaded_struct.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
2237 field_type.abiAlignment(zcu).toByteUnits().?);
2238 }
2239 if (has_comptime_state)
2240 try dwarf.sectionOffset(di_nw, Const.get(
2241 try dwarf.getConst(pt, .fromInterned(field_init)),
2242 dwarf,
2243 ).debug_info_ni.unwrap().?, 0)
2244 else if (has_runtime_bits)
2245 //try wip_nav.blockValue(.fromInterned(field_init));
2246 try diw.writeUleb128(0);
2247 }
2248 try diw.writeUleb128(@backingInt(AbbrevCode.null));
2249 }
2250 },
2251 .@"packed" => return,
2252 }
2253 },
2254 .simple_type => |simple_type| switch (simple_type) {
2255 .f16,
2256 .f32,
2257 .f64,
2258 .f80,
2259 .f128,
2260 .usize,
2261 .isize,
2262 .c_char,
2263 .c_short,
2264 .c_ushort,
2265 .c_int,
2266 .c_uint,
2267 .c_long,
2268 .c_ulong,
2269 .c_longlong,
2270 .c_ulonglong,
2271 .c_longdouble,
2272 .bool,
2273 => {
2274 const ty: Type = .fromInterned(val);
2275 try diw.writeUleb128(try dwarf.refAbbrevCode(.numeric_type));
2276 try dwarf.strp(&dwarf.debug_str, di_nw, @tagName(simple_type));
2277 try diw.writeByte(if (val == .bool_type)
2278 DW.ATE.boolean
2279 else if (ty.isRuntimeFloat())
2280 DW.ATE.float
2281 else if (ty.isSignedInt(zcu))
2282 DW.ATE.signed
2283 else if (ty.isUnsignedInt(zcu))
2284 DW.ATE.unsigned
2285 else
2286 unreachable);
2287 try diw.writeUleb128(ty.bitSize(zcu));
2288 try diw.writeUleb128(ty.abiSize(zcu));
2289 try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
2290 },
2291 .generic_poison => {
2292 try diw.writeUleb128(try dwarf.refAbbrevCode(.void_type));
2293 try dwarf.strp(&dwarf.debug_str, di_nw, "anytype");
2294 },
2295 .anyopaque,
2296 .void,
2297 .type,
2298 .comptime_int,
2299 .comptime_float,
2300 .noreturn,
2301 => {
2302 try diw.writeUleb128(try dwarf.refAbbrevCode(.void_type));
2303 try dwarf.strp(&dwarf.debug_str, di_nw, @tagName(simple_type));
2304 },
2305 inline .null, .undefined => |tag| {
2306 try diw.writeUleb128(try dwarf.refAbbrevCode(.void_type));
2307 try dwarf.strp(&dwarf.debug_str, di_nw, "@TypeOf(" ++ @tagName(tag) ++ ")");
2308 },
2309 .enum_literal => {
2310 try diw.writeUleb128(try dwarf.refAbbrevCode(.void_type));
2311 try dwarf.strp(&dwarf.debug_str, di_nw, "@EnumLiteral()");
2312 },
2313 .anyerror => return,
2314 .adhoc_inferred_error_set => unreachable,
2315 },
2316 }
2317 try dwarf.genDebugInfoPadding(diw, diw.unusedCapacityLen());
21072318}
21082319
21092320pub fn updateConstIncomplete(
......@@ -2112,6 +2323,7 @@ pub fn updateConstIncomplete(
21122323 di_nw: *MappedFile.Node.Writer,
21132324 val: InternPool.Index,
21142325) link.Error!void {
2326 log.debug("updateConstIncomplete({f})", .{Value.fromInterned(val).fmtValue(pt)});
21152327 dwarf.updateConstIncompleteInner(pt, di_nw, val) catch |err| switch (err) {
21162328 else => |e| return e,
21172329 error.WriteFailed => return dwarf.reportWriteError(di_nw),
......@@ -2123,8 +2335,7 @@ fn updateConstIncompleteInner(
21232335 di_nw: *MappedFile.Node.Writer,
21242336 val: InternPool.Index,
21252337) link.EmitError!void {
2126 const comp = dwarf.lf.comp;
2127 const zcu = comp.zcu.?;
2338 const zcu = pt.zcu;
21282339 const ip = &zcu.intern_pool;
21292340 const diw = &di_nw.interface;
21302341 done: {
......@@ -2133,8 +2344,8 @@ fn updateConstIncompleteInner(
21332344 const loaded_struct = ip.loadStructType(val);
21342345 if (loaded_struct.zir_index.resolveFull(ip)) |src_inst| switch (src_inst.inst) {
21352346 .main_struct_inst => {
2136 const ui = dwarf.getUnit(comp.zcu.?.fileByIndex(src_inst.file).mod.?);
2137 _, const fi = try ui.get(dwarf).getFile(comp.gpa, ui, src_inst.file);
2347 const ui = dwarf.getUnit(zcu.fileByIndex(src_inst.file).mod.?);
2348 _, const fi = try ui.get(dwarf).getFile(zcu.gpa, ui, src_inst.file);
21382349 try diw.writeUleb128(try dwarf.refAbbrevCode(.empty_file));
21392350 try diw.writeUleb128(@backingInt(fi));
21402351 try dwarf.strp(&dwarf.debug_str, di_nw, loaded_struct.name.toSlice(ip));
......@@ -2171,8 +2382,8 @@ fn updateConstIncompleteInner(
21712382 },
21722383 else => |val_key| break :done switch (val_key.typeOf()) {
21732384 .type_type => {
2174 const name = try comp.gpa.print("{f}", .{Type.fromInterned(val).fmt(pt)});
2175 defer comp.gpa.free(name);
2385 const name = try zcu.gpa.print("{f}", .{Type.fromInterned(val).fmt(pt)});
2386 defer zcu.gpa.free(name);
21762387 try diw.writeUleb128(try dwarf.refAbbrevCode(.generated_empty_struct_type));
21772388 try dwarf.strp(&dwarf.debug_str, di_nw, name);
21782389 try diw.writeByte(@intFromBool(true));
......@@ -2203,7 +2414,7 @@ fn updateConstIncompleteInner(
22032414 try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
22042415 } else {
22052416 const ui = dwarf.getUnit(zcu.fileByIndex(src_inst.file).mod.?);
2206 _, const fi = try ui.get(dwarf).getFile(comp.gpa, ui, src_inst.file);
2417 _, const fi = try ui.get(dwarf).getFile(zcu.gpa, ui, src_inst.file);
22072418 try diw.writeUleb128(try dwarf.refAbbrevCode(.empty_struct_type));
22082419 try diw.writeUleb128(@backingInt(fi));
22092420 }
......@@ -2433,7 +2644,8 @@ pub const AbbrevCode = enum {
24332644 array_len,
24342645 nullary_func_type,
24352646 func_type,
2436 func_type_param,
2647 param,
2648 unnamed_param,
24372649 is_var_args,
24382650 generated_empty_enum_type,
24392651 generated_enum_type,
......@@ -2651,12 +2863,12 @@ pub const AbbrevCode = enum {
26512863 .children = true,
26522864 .attrs = decl_attrs ++ .{
26532865 .{ .linkage_name, .strp },
2654 //.{ .type, .ref_addr },
2866 .{ .type, .ref_addr },
26552867 .{ .low_pc, .addr },
26562868 .{ .high_pc, .data4 },
2657 //.{ .alignment, .udata },
2658 //.{ .external, .flag },
2659 //.{ .noreturn, .flag },
2869 .{ .alignment, .udata },
2870 .{ .external, .flag },
2871 .{ .noreturn, .flag },
26602872 },
26612873 },
26622874 .decl_nullary_func_generic = .{
......@@ -2897,7 +3109,7 @@ pub const AbbrevCode = enum {
28973109 .module_dependency = .{
28983110 .tag = .imported_module,
28993111 .attrs = &.{
2900 .{ .name, .string },
3112 .{ .name, .strp },
29013113 .{ .import, .ref_addr },
29023114 },
29033115 },
......@@ -3148,7 +3360,14 @@ pub const AbbrevCode = enum {
31483360 .{ .type, .ref_addr },
31493361 },
31503362 },
3151 .func_type_param = .{
3363 .param = .{
3364 .tag = .formal_parameter,
3365 .attrs = &.{
3366 .{ .name, .strp },
3367 .{ .type, .ref_addr },
3368 },
3369 },
3370 .unnamed_param = .{
31523371 .tag = .formal_parameter,
31533372 .attrs = &.{
31543373 .{ .type, .ref_addr },
......@@ -3578,9 +3797,11 @@ const DW = std.dwarf;
35783797const Dwarf = @This();
35793798const InternPool = @import("../InternPool.zig");
35803799const link = @import("../link.zig");
3800const log = std.log.scoped(.dwarf);
35813801const MappedFile = @import("MappedFile.zig");
35823802const Module = @import("../Module.zig");
35833803const std = @import("std");
3804const target_info = @import("../target.zig");
35843805const Type = @import("../Type.zig");
35853806const Value = @import("../Value.zig");
35863807const Writer = std.Io.Writer;
src/link/Elf2.zig+96-42
......@@ -5954,15 +5954,11 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
59545954 .@"fn" => a: {
59555955 const mod = zcu.navFileScope(nav_index).mod.?;
59565956 const target = &mod.resolved_target.result;
5957 const min = target_util.minFunctionAlignment(target);
59585957 break :a .fromIp(switch (nav.resolved.?.@"align") {
5959 else => |a| a.maxStrict(min),
5958 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
59605959 .none => switch (mod.optimize_mode) {
5961 .debug,
5962 .safe,
5963 .fast,
5964 => target_util.defaultFunctionAlignment(target),
5965 .small => min,
5960 .debug, .safe, .fast => target_util.defaultFunctionAlignment(target),
5961 .small => target_util.minFunctionAlignment(target),
59665962 }.maxStrict(Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu)),
59675963 });
59685964 },
......@@ -8626,25 +8622,71 @@ pub fn updateContainerTypeInner(
86268622pub fn addConst(
86278623 elf: *Elf,
86288624 _: Zcu.PerThread,
8629 index: link.ConstPool.Index,
8625 cpi: link.ConstPool.Index,
86308626 val: InternPool.Index,
86318627) link.Error!void {
86328628 switch (elf.base.comp.config.debug_format) {
86338629 .strip => {},
8634 .dwarf => try elf.dwarf.addConst(index, val),
8630 .dwarf => {
8631 const gpa = elf.base.comp.gpa;
8632 try elf.nodes.ensureUnusedCapacity(gpa, 1);
8633 try elf.dwarf_consts.ensureUnusedCapacity(gpa, 1);
8634 try elf.dwarf.addConst(cpi, val, &addConstNode);
8635 elf.dwarf_consts.putAssumeCapacity(cpi, .{
8636 .debug_info_first_target_reloc = .none,
8637 .debug_info_first_symbol_reloc = .none,
8638 .debug_info_first_node_reloc = .none,
8639 });
8640 },
86358641 .code_view => unreachable,
86368642 }
86378643}
8644fn addConstNode(lf: *link.File, ui: Dwarf.Unit.Index, cpi: link.ConstPool.Index) link.Error!MappedFile.Node.Index {
8645 const elf = lf.cast(.elf2).?;
8646 const unit = ui.get(&elf.dwarf);
8647 return elf.addNodeAssumeCapacity(
8648 unit.debug_info_ni.unwrap().?.addFloatingChild(lf.comp.gpa, &elf.mf, .{
8649 .enable_next_moved = true,
8650 }) catch |err| switch (err) {
8651 else => |e| return e,
8652 error.MappedFileIo => return lf.comp.link_diags.fail("failed to write output file: {t}", .{
8653 elf.mf.io_err.?,
8654 }),
8655 },
8656 .{ .const_debug_info = cpi },
8657 );
8658}
86388659
86398660pub fn updateConst(
86408661 elf: *Elf,
8641 _: Zcu.PerThread,
8662 pt: Zcu.PerThread,
8663 cpi: link.ConstPool.Index,
8664 val: InternPool.Index,
8665) link.Error!void {
8666 switch (val) {
8667 .anyerror_type => {}, // handled in `updateErrorData` instead
8668 else => try elf.updateConstInner(pt, cpi, val),
8669 }
8670}
8671fn updateConstInner(
8672 elf: *Elf,
8673 pt: Zcu.PerThread,
86428674 cpi: link.ConstPool.Index,
86438675 val: InternPool.Index,
86448676) link.Error!void {
8677 if (val == .anyerror_type) return; // handled in `updateErrorData` instead
86458678 switch (elf.base.comp.config.debug_format) {
86468679 .strip => {},
8647 .dwarf => elf.dwarf.updateConst(cpi, val),
8680 .dwarf => {
8681 const gpa = elf.base.comp.gpa;
8682 const debug_info_ni = Dwarf.Const.get(cpi, &elf.dwarf).debug_info_ni.unwrap().?;
8683 try debug_info_ni.moved(gpa, &elf.mf);
8684 var di_nw: MappedFile.Node.Writer = undefined;
8685 debug_info_ni.writer(gpa, &elf.mf, &di_nw);
8686 defer di_nw.deinit();
8687 elf.resetNodeRelocs(debug_info_ni);
8688 try elf.dwarf.updateConst(pt, &di_nw, val);
8689 },
86488690 .code_view => unreachable,
86498691 }
86508692}
......@@ -8658,10 +8700,13 @@ pub fn updateConstIncomplete(
86588700 switch (elf.base.comp.config.debug_format) {
86598701 .strip => {},
86608702 .dwarf => {
8703 const gpa = elf.base.comp.gpa;
86618704 const debug_info_ni = Dwarf.Const.get(cpi, &elf.dwarf).debug_info_ni.unwrap().?;
8705 try debug_info_ni.moved(gpa, &elf.mf);
86628706 var di_nw: MappedFile.Node.Writer = undefined;
8663 debug_info_ni.writer(elf.base.comp.gpa, &elf.mf, &di_nw);
8707 debug_info_ni.writer(gpa, &elf.mf, &di_nw);
86648708 defer di_nw.deinit();
8709 elf.resetNodeRelocs(debug_info_ni);
86658710 try elf.dwarf.updateConstIncomplete(pt, &di_nw, val);
86668711 },
86678712 .code_view => unreachable,
......@@ -8952,16 +8997,19 @@ pub fn lostTracking(
89528997}
89538998
89548999pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void {
8955 elf.genLazyInner(pt, .{
9000 const comp = elf.base.comp;
9001 if (elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type)) |lmi| elf.genLazyInner(pt, .{
89569002 .kind = .const_data,
8957 .index = @intCast(elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return),
9003 .index = @intCast(lmi),
89589004 }) catch |err| switch (err) {
89599005 else => |e| return e,
8960 error.MappedFileIo => return elf.base.comp.link_diags.fail(
9006 error.MappedFileIo => return comp.link_diags.fail(
89619007 "failed to write output file: {t}",
89629008 .{elf.mf.io_err.?},
89639009 ),
89649010 };
9011 if (elf.dwarf.const_pool.getIfExists(.anyerror_type)) |cpi|
9012 try elf.updateConstInner(pt, cpi, .anyerror_type);
89659013}
89669014
89679015pub fn flush(
......@@ -9258,10 +9306,12 @@ fn idleProgNode(
92589306 },
92599307 ui.mod(&elf.dwarf).fully_qualified_name,
92609308 }) catch &name,
9261 .const_debug_info => |cpi| std.mem.print(&name, "debug info for {f}", .{
9262 Value.fromInterned(cpi.val(&elf.dwarf.const_pool))
9263 .fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
9264 }) catch &name,
9309 .const_debug_info => |cpi| switch (cpi.val(&elf.dwarf.const_pool)) {
9310 .generic_poison_type => "anytype",
9311 else => |val| std.mem.print(&name, "debug info for {f}", .{
9312 Value.fromInterned(val).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
9313 }) catch &name,
9314 },
92659315 .global_debug_info => |gi| {
92669316 const ip = &elf.base.comp.zcu.?.intern_pool;
92679317 break :name std.mem.print(&name, "debug info for {f}", .{
......@@ -10790,12 +10840,12 @@ pub fn printNode(
1079010840 .unit_debug_line_header,
1079110841 .unit_debug_rnglists,
1079210842 => |ui| try w.print("({s})", .{ui.mod(&elf.dwarf).fully_qualified_name}),
10793 .const_debug_info => |cpi| try w.print("({f})", .{
10794 Value.fromInterned(cpi.val(&elf.dwarf.const_pool)).fmtValue(.{
10795 .zcu = elf.base.comp.zcu.?,
10796 .tid = tid,
10843 .const_debug_info => |cpi| switch (cpi.val(&elf.dwarf.const_pool)) {
10844 .generic_poison_type => try w.writeAll("(anytype)"),
10845 else => |val| try w.print("({f})", .{
10846 Value.fromInterned(val).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
1079710847 }),
10798 }),
10848 },
1079910849 .global_debug_info => |gi| {
1080010850 const zcu = elf.base.comp.zcu.?;
1080110851 const ip = &zcu.intern_pool;
......@@ -10839,26 +10889,30 @@ pub fn printNode(
1083910889 }
1084010890 return;
1084110891 }
10842 const file_loc = ni.fileLocation(&elf.mf, false);
10843 var address = file_loc.offset;
10844 if (file_loc.size == 0) {
10845 try w.splatByteAll(' ', indent + 1);
10846 try w.print("{x:0>8}\n", .{address});
10847 return;
10848 }
10892 const start_address: usize, const end_address: usize = file_loc: {
10893 const file_loc = ni.fileLocation(&elf.mf, false);
10894 break :file_loc .{ @intCast(file_loc.offset), @intCast(file_loc.offset + file_loc.size) };
10895 };
10896 var address = start_address;
1084910897 const line_len = 0x10;
10850 var line_it = std.mem.window(
10851 u8,
10852 elf.mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
10853 line_len,
10854 line_len,
10855 );
10856 while (line_it.next()) |line_bytes| : (address += line_len) {
10898 while (true) : (address = @min(std.mem.alignForward(usize, address + 1, line_len), end_address)) {
1085710899 try w.splatByteAll(' ', indent + 1);
10858 try w.print("{x:0>8} ", .{address});
10859 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});
10860 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);
10861 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');
10900 try w.print("{x:0>8}", .{address});
10901 if (address == end_address) break try w.writeByte('\n');
10902 try w.splatByteAll(' ', 2);
10903 const start_byte_address = std.mem.alignBackward(usize, address, line_len);
10904 const end_byte_address = start_byte_address + line_len;
10905 for (start_byte_address..end_byte_address) |byte_address|
10906 if (byte_address < start_address or byte_address >= end_address)
10907 try w.splatByteAll(' ', 3)
10908 else
10909 try w.print("{x:0>2} ", .{elf.mf.memory_map.memory[byte_address]});
10910 try w.writeByte(' ');
10911 for (start_byte_address..@min(end_address, end_byte_address)) |byte_address|
10912 try w.writeByte(if (byte_address < start_address or byte_address >= end_address) ' ' else char: {
10913 const byte = elf.mf.memory_map.memory[byte_address];
10914 break :char if (std.ascii.isPrint(byte)) byte else '.';
10915 });
1086210916 try w.writeByte('\n');
1086310917 }
1086410918}