authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-09-04 10:40:22+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-04 20:57:35+02:00
log1436d488b9d64af6d7087c0070d18df3d23604c5
treed973a598231e79b0d4a8bcb2dc721ca0f896138a
parent5b46e1f7f4db2ce06b4f150d653d98cf8363f348

std.debug.Dwarf: basic support for DW_LNE_ZIG_set_decl

This makes stack traces with `-fincremental`, um, sort of work: ``` thread 29999 panic: this is the RIGHT panic /home/mlugg/panic.zig:15:25: 0x7a1907 in bar (panic.zig) 1, 2, 3, 123 => @panic("this is the RIGHT panic"), ^ /home/mlugg/panic.zig:7:12: 0x7a138c in foo (panic.zig) bar(123); ^ /home/mlugg/panic.zig:2:8: 0x7a12fe in main (panic.zig) foo(true); ^ /home/mlugg/zig/master/lib/std/start.zig:779:64: 0x7a0e3b in callMain (std.zig) ^ /home/mlugg/zig/master/lib/std/Target.zig:1651:5: 0x7a0861 in _start (std.zig) pub inline fn isSparc(arch: Arch) bool { ^ Aborted ./panic ``` The last two frames are clearly incorrect. However, we actually agree with lldb-zig about those source locations, so it seems like that's a bug in the compiler's `link.Dwarf2` implementation.

1 files changed, 77 insertions(+), 10 deletions(-)

lib/std/debug/Dwarf.zig+77-10
...@@ -114,12 +114,14 @@ pub const Abbrev = struct {...@@ -114,12 +114,14 @@ pub const Abbrev = struct {
114};114};
115115
116pub const CompileUnit = struct {116pub const CompileUnit = struct {
117 offset: u64,
118 size: u64,
117 version: u16,119 version: u16,
118 format: Format,120 format: Format,
119 addr_size_bytes: u8,121 addr_size_bytes: u8,
122 abbrev_offset: u64,
120 die: Die,123 die: Die,
121 pc_range: ?PcRange,124 pc_range: ?PcRange,
122
123 str_offsets_base: usize,125 str_offsets_base: usize,
124 addr_base: usize,126 addr_base: usize,
125 rnglists_base: usize,127 rnglists_base: usize,
...@@ -246,14 +248,6 @@ pub const Die = struct {...@@ -246,14 +248,6 @@ pub const Die = struct {
246 return form_value.getUInt(u64);248 return form_value.getUInt(u64);
247 }249 }
248250
249 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
250 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
251 return switch (form_value.*) {
252 .Const => |value| value.asUnsignedLe(),
253 else => bad(),
254 };
255 }
256
257 fn getAttrRef(self: *const Die, id: u64, unit_offset: u64, unit_len: u64) !u64 {251 fn getAttrRef(self: *const Die, id: u64, unit_offset: u64, unit_len: u64) !u64 {
258 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;252 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
259 return switch (form_value.*) {253 return switch (form_value.*) {
...@@ -425,12 +419,14 @@ fn scanAllFunctions(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!void {...@@ -425,12 +419,14 @@ fn scanAllFunctions(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!void {
425 const next_unit_pos = this_unit_offset + next_offset;419 const next_unit_pos = this_unit_offset + next_offset;
426420
427 var compile_unit: CompileUnit = .{421 var compile_unit: CompileUnit = .{
422 .offset = this_unit_offset,
423 .size = next_offset,
428 .version = version,424 .version = version,
429 .format = unit_header.format,425 .format = unit_header.format,
430 .addr_size_bytes = address_size,426 .addr_size_bytes = address_size,
427 .abbrev_offset = debug_abbrev_offset,
431 .die = undefined,428 .die = undefined,
432 .pc_range = null,429 .pc_range = null,
433
434 .str_offsets_base = 0,430 .str_offsets_base = 0,
435 .addr_base = 0,431 .addr_base = 0,
436 .rnglists_base = 0,432 .rnglists_base = 0,
...@@ -624,9 +620,12 @@ fn scanAllCompileUnits(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!voi...@@ -624,9 +620,12 @@ fn scanAllCompileUnits(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!voi
624 compile_unit_die.attrs = try gpa.dupe(Die.Attr, compile_unit_die.attrs);620 compile_unit_die.attrs = try gpa.dupe(Die.Attr, compile_unit_die.attrs);
625621
626 var compile_unit: CompileUnit = .{622 var compile_unit: CompileUnit = .{
623 .offset = this_unit_offset,
624 .size = next_offset,
627 .version = version,625 .version = version,
628 .format = unit_header.format,626 .format = unit_header.format,
629 .addr_size_bytes = address_size,627 .addr_size_bytes = address_size,
628 .abbrev_offset = debug_abbrev_offset,
630 .pc_range = null,629 .pc_range = null,
631 .die = compile_unit_die,630 .die = compile_unit_die,
632 .str_offsets_base = if (compile_unit_die.getAttr(AT.str_offsets_base)) |fv| try fv.getUInt(usize) else 0,631 .str_offsets_base = if (compile_unit_die.getAttr(AT.str_offsets_base)) |fv| try fv.getUInt(usize) else 0,
...@@ -1097,6 +1096,16 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, endian: Endian, compile_unit:...@@ -1097,6 +1096,16 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, endian: Endian, compile_unit:
1097 }1096 }
1098 }1097 }
10991098
1099 const abbrev_table = try d.getAbbrevTable(gpa, compile_unit.abbrev_offset);
1100 const attrs_buf = try gpa.alloc(Die.Attr, max_attrs: {
1101 var max_attrs: usize = 0;
1102 for (abbrev_table.abbrevs) |abbrev| {
1103 max_attrs = @max(max_attrs, abbrev.attrs.len);
1104 }
1105 break :max_attrs max_attrs;
1106 });
1107 defer gpa.free(attrs_buf);
1108
1100 var prog = LineNumberProgram.init(default_is_stmt, version);1109 var prog = LineNumberProgram.init(default_is_stmt, version);
1101 var line_table: CompileUnit.SrcLocCache.LineTable = .{};1110 var line_table: CompileUnit.SrcLocCache.LineTable = .{};
1102 errdefer line_table.deinit(gpa);1111 errdefer line_table.deinit(gpa);
...@@ -1144,6 +1153,64 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, endian: Endian, compile_unit:...@@ -1144,6 +1153,64 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, endian: Endian, compile_unit:
1144 .size = size,1153 .size = size,
1145 });1154 });
1146 },1155 },
1156 DW.LNE.ZIG_set_decl => {
1157 const decl_die_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
1158 var di_fr: Reader = .fixed(d.section(.debug_info) orelse continue);
1159 di_fr.seek = @intCast(decl_die_offset);
1160 var die = (try parseDie(
1161 &di_fr,
1162 attrs_buf,
1163 abbrev_table,
1164 unit_header.format,
1165 endian,
1166 addr_size_bytes,
1167 compile_unit.version,
1168 )) orelse continue;
1169 if (die.getAttr(AT.low_pc)) |_| {
1170 prog.address = try die.getAttrAddr(d, endian, AT.low_pc, compile_unit);
1171 }
1172 if (die.getAttr(AT.decl_line)) |decl_line| {
1173 prog.line = try decl_line.getUInt(i64);
1174 }
1175 if (die.getAttr(AT.decl_column)) |decl_column| {
1176 prog.column = try decl_column.getUInt(u64);
1177 }
1178 while (die.getAttr(AT.decl_file) == null) {
1179 if (die.getAttr(AT.abstract_origin)) |_| {
1180 di_fr.seek = @intCast(try die.getAttrRef(
1181 AT.abstract_origin,
1182 compile_unit.offset,
1183 compile_unit.size,
1184 ));
1185 } else if (die.getAttr(AT.specification)) |_| {
1186 di_fr.seek = @intCast(try die.getAttrRef(
1187 AT.specification,
1188 compile_unit.offset,
1189 compile_unit.size,
1190 ));
1191 } else if (die.getAttr(AT.ZIG_parent)) |_| {
1192 di_fr.seek = @intCast(try die.getAttrRef(
1193 AT.ZIG_parent,
1194 compile_unit.offset,
1195 compile_unit.size,
1196 ));
1197 } else {
1198 // no parent, so we can't find DW_AT_decl_file
1199 break;
1200 }
1201 die = (try parseDie(
1202 &di_fr,
1203 attrs_buf,
1204 abbrev_table,
1205 unit_header.format,
1206 endian,
1207 addr_size_bytes,
1208 compile_unit.version,
1209 )) orelse break;
1210 } else {
1211 prog.file = try die.getAttr(AT.decl_file).?.getUInt(usize);
1212 }
1213 },
1147 else => try fr.discardAll64(op_size - 1),1214 else => try fr.discardAll64(op_size - 1),
1148 }1215 }
1149 } else if (opcode >= opcode_base) {1216 } else if (opcode >= opcode_base) {