authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-03 15:28:19-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-03 15:29:46-04:00
logd44db8ea0c35122aefbb1d86bed820b382eec988
tree0fea7dd49e2c56cb3410b6d6b9f675eb504f9aa8
parent980bf80036a896ff01e7395c3887858ebae3e7f7

debug: fix and test Elf2 stack trace printing

- fix corrupt debug info - fix dwarf unit version handling - run stack and error trace tests with Elf2

5 files changed, 84 insertions(+), 42 deletions(-)

lib/std/debug/Dwarf.zig+10-8
...@@ -387,18 +387,19 @@ fn scanAllFunctions(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!void {...@@ -387,18 +387,19 @@ fn scanAllFunctions(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!void {
387 const next_offset = unit_header.header_length + unit_header.unit_length;387 const next_offset = unit_header.header_length + unit_header.unit_length;
388388
389 const version = try fr.takeInt(u16, endian);389 const version = try fr.takeInt(u16, endian);
390 if (version < 2 or version > 5) return bad();
391
392 var address_size: u8 = undefined;390 var address_size: u8 = undefined;
393 var debug_abbrev_offset: u64 = undefined;391 var debug_abbrev_offset: u64 = undefined;
394 if (version >= 5) {392 if (version == 5) {
395 const unit_type = try fr.takeByte();393 const unit_type = try fr.takeByte();
396 if (unit_type != DW.UT.compile) return bad();394 if (unit_type != DW.UT.compile) return bad();
397 address_size = try fr.takeByte();395 address_size = try fr.takeByte();
398 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);396 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
399 } else {397 } else if (version >= 2 and version < 5) {
400 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);398 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
401 address_size = try fr.takeByte();399 address_size = try fr.takeByte();
400 } else {
401 this_unit_offset += next_offset;
402 continue;
402 }403 }
403404
404 const abbrev_table = try di.getAbbrevTable(gpa, debug_abbrev_offset);405 const abbrev_table = try di.getAbbrevTable(gpa, debug_abbrev_offset);
...@@ -585,18 +586,19 @@ fn scanAllCompileUnits(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!voi...@@ -585,18 +586,19 @@ fn scanAllCompileUnits(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!voi
585 const next_offset = unit_header.header_length + unit_header.unit_length;586 const next_offset = unit_header.header_length + unit_header.unit_length;
586587
587 const version = try fr.takeInt(u16, endian);588 const version = try fr.takeInt(u16, endian);
588 if (version < 2 or version > 5) return bad();
589
590 var address_size: u8 = undefined;589 var address_size: u8 = undefined;
591 var debug_abbrev_offset: u64 = undefined;590 var debug_abbrev_offset: u64 = undefined;
592 if (version >= 5) {591 if (version == 5) {
593 const unit_type = try fr.takeByte();592 const unit_type = try fr.takeByte();
594 if (unit_type != UT.compile) return bad();593 if (unit_type != UT.compile) return bad();
595 address_size = try fr.takeByte();594 address_size = try fr.takeByte();
596 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);595 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
597 } else {596 } else if (version >= 2 and version < 5) {
598 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);597 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
599 address_size = try fr.takeByte();598 address_size = try fr.takeByte();
599 } else {
600 this_unit_offset += next_offset;
601 continue;
600 }602 }
601603
602 const abbrev_table = try di.getAbbrevTable(gpa, debug_abbrev_offset);604 const abbrev_table = try di.getAbbrevTable(gpa, debug_abbrev_offset);
src/link/Dwarf2.zig-6
...@@ -1058,7 +1058,6 @@ pub const WipNav = struct {...@@ -1058,7 +1058,6 @@ pub const WipNav = struct {
1058 01058 0
1059 else1059 else
1060 zcu.navSrcLine(zcu.funcInfo(debug.wip_nav.func).owner_nav) + 1) + line);1060 zcu.navSrcLine(zcu.funcInfo(debug.wip_nav.func).owner_nav) + 1) + line);
1061 try di_w.writeUleb128(line);
1062 try di_w.writeUleb128(column + 1);1061 try di_w.writeUleb128(column + 1);
1063 block.low_pc_off = code_off;1062 block.low_pc_off = code_off;
1064 try dwarf.addrSym(di_nw, debug.wip_nav.func_si, code_off);1063 try dwarf.addrSym(di_nw, debug.wip_nav.func_si, code_off);
...@@ -2898,11 +2897,6 @@ fn updateConstInner(...@@ -2898,11 +2897,6 @@ fn updateConstInner(
28982897
2899 else => return,2898 else => return,
2900 .func => |func| {2899 .func => |func| {
2901 const fi = try dwarf.getFunc(func.owner_nav);
2902 switch (fi.get(dwarf).state) {
2903 .unresolved => {},
2904 .resolved => return,
2905 }
2906 const fn_ty = ip.indexToKey(func.ty).func_type;2900 const fn_ty = ip.indexToKey(func.ty).func_type;
2907 const nav = ip.getNav(func.owner_nav);2901 const nav = ip.getNav(func.owner_nav);
2908 const inst_info = nav.srcInst(ip).resolveFull(ip).?;2902 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
src/link/Elf2.zig+19-21
...@@ -8753,7 +8753,7 @@ pub fn updateConst(...@@ -8753,7 +8753,7 @@ pub fn updateConst(
8753) link.Error!void {8753) link.Error!void {
8754 switch (val) {8754 switch (val) {
8755 .anyerror_type => {}, // handled in `updateErrorData` instead8755 .anyerror_type => {}, // handled in `updateErrorData` instead
8756 else => try elf.updateConstInner(pt, cpi, val),8756 else => try elf.updateConstInner(pt, cpi, val, .complete),
8757 }8757 }
8758}8758}
8759fn updateConstInner(8759fn updateConstInner(
...@@ -8761,11 +8761,22 @@ fn updateConstInner(...@@ -8761,11 +8761,22 @@ fn updateConstInner(
8761 pt: Zcu.PerThread,8761 pt: Zcu.PerThread,
8762 cpi: link.ConstPool.Index,8762 cpi: link.ConstPool.Index,
8763 val: InternPool.Index,8763 val: InternPool.Index,
8764 complete: enum { incomplete, complete },
8764) link.Error!void {8765) link.Error!void {
8765 switch (elf.base.comp.config.debug_format) {8766 switch (elf.base.comp.config.debug_format) {
8766 .strip => {},8767 .strip => {},
8767 .dwarf => {8768 .dwarf => {
8768 {8769 {
8770 switch (pt.zcu.intern_pool.indexToKey(val)) {
8771 else => {},
8772 .func => |func| {
8773 const fi = try elf.dwarf.getFunc(func.owner_nav);
8774 switch (fi.get(&elf.dwarf).state) {
8775 .unresolved => {},
8776 .resolved => return,
8777 }
8778 },
8779 }
8769 const gpa = elf.base.comp.gpa;8780 const gpa = elf.base.comp.gpa;
8770 const debug_info_ni = Dwarf.Const.get(cpi, &elf.dwarf).debug_info_ni.unwrap().?;8781 const debug_info_ni = Dwarf.Const.get(cpi, &elf.dwarf).debug_info_ni.unwrap().?;
8771 try debug_info_ni.moved(gpa, &elf.mf);8782 try debug_info_ni.moved(gpa, &elf.mf);
...@@ -8773,7 +8784,10 @@ fn updateConstInner(...@@ -8773,7 +8784,10 @@ fn updateConstInner(
8773 debug_info_ni.writer(gpa, &elf.mf, &di_nw);8784 debug_info_ni.writer(gpa, &elf.mf, &di_nw);
8774 defer di_nw.deinit();8785 defer di_nw.deinit();
8775 elf.resetNodeRelocs(debug_info_ni);8786 elf.resetNodeRelocs(debug_info_ni);
8776 try elf.dwarf.updateConst(pt, &di_nw, val);8787 switch (complete) {
8788 .incomplete => try elf.dwarf.updateConstIncomplete(pt, &di_nw, val),
8789 .complete => try elf.dwarf.updateConst(pt, &di_nw, val),
8790 }
8777 }8791 }
8778 try elf.genPending(pt);8792 try elf.genPending(pt);
8779 },8793 },
...@@ -8787,23 +8801,7 @@ pub fn updateConstIncomplete(...@@ -8787,23 +8801,7 @@ pub fn updateConstIncomplete(
8787 cpi: link.ConstPool.Index,8801 cpi: link.ConstPool.Index,
8788 val: InternPool.Index,8802 val: InternPool.Index,
8789) link.Error!void {8803) link.Error!void {
8790 switch (elf.base.comp.config.debug_format) {8804 return elf.updateConstInner(pt, cpi, val, .incomplete);
8791 .strip => {},
8792 .dwarf => {
8793 {
8794 const gpa = elf.base.comp.gpa;
8795 const debug_info_ni = Dwarf.Const.get(cpi, &elf.dwarf).debug_info_ni.unwrap().?;
8796 try debug_info_ni.moved(gpa, &elf.mf);
8797 var di_nw: MappedFile.Node.Writer = undefined;
8798 debug_info_ni.writer(gpa, &elf.mf, &di_nw);
8799 defer di_nw.deinit();
8800 elf.resetNodeRelocs(debug_info_ni);
8801 try elf.dwarf.updateConstIncomplete(pt, &di_nw, val);
8802 }
8803 try elf.genPending(pt);
8804 },
8805 .code_view => unreachable,
8806 }
8807}8805}
88088806
8809pub fn updateFunc(8807pub fn updateFunc(
...@@ -9032,7 +9030,7 @@ fn updateFuncInner(...@@ -9032,7 +9030,7 @@ fn updateFuncInner(
9032 if (func.analysisUnordered(ip).inferred_error_set) {9030 if (func.analysisUnordered(ip).inferred_error_set) {
9033 const ies = ip.getIfExists(.{ .inferred_error_set_type = func_index }).?;9031 const ies = ip.getIfExists(.{ .inferred_error_set_type = func_index }).?;
9034 if (elf.dwarf.const_pool.getIfExists(ies)) |cpi|9032 if (elf.dwarf.const_pool.getIfExists(ies)) |cpi|
9035 try elf.updateConstInner(pt, cpi, ies);9033 try elf.updateConstInner(pt, cpi, ies, .complete);
9036 }9034 }
9037 },9035 },
9038 .none => {},9036 .none => {},
...@@ -9083,7 +9081,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void {...@@ -9083,7 +9081,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void {
9083 .index = @intCast(lmi),9081 .index = @intCast(lmi),
9084 });9082 });
9085 if (elf.dwarf.const_pool.getIfExists(.anyerror_type)) |cpi|9083 if (elf.dwarf.const_pool.getIfExists(.anyerror_type)) |cpi|
9086 try elf.updateConstInner(pt, cpi, .anyerror_type);9084 try elf.updateConstInner(pt, cpi, .anyerror_type, .complete);
9087}9085}
90889086
9089pub fn flush(9087pub fn flush(
test/src/ErrorTrace.zig+29-5
...@@ -36,6 +36,7 @@ pub const CaseParameters = struct {...@@ -36,6 +36,7 @@ pub const CaseParameters = struct {
36 optimize: OptimizeMode = .debug,36 optimize: OptimizeMode = .debug,
37 use_llvm: ?bool = null,37 use_llvm: ?bool = null,
38 use_lld: ?bool = null,38 use_lld: ?bool = null,
39 use_new_linker: ?bool = null,
3940
40 // This is intended for targets that, for any reason, shouldn't be run as part of a normal test41 // This is intended for targets that, for any reason, shouldn't be run as part of a normal test
41 // invocation. This could be because of a slow backend, requiring a newer LLVM version, being42 // invocation. This could be because of a slow backend, requiring a newer LLVM version, being
...@@ -256,6 +257,14 @@ pub const param_sets = [_]CaseParameters{...@@ -256,6 +257,14 @@ pub const param_sets = [_]CaseParameters{
256 .abi = .none,257 .abi = .none,
257 },258 },
258 },259 },
260 .{
261 .target = .{
262 .cpu_arch = .x86_64,
263 .os_tag = .linux,
264 .abi = .none,
265 },
266 .use_new_linker = true,
267 },
259 .{268 .{
260 .target = .{269 .target = .{
261 .cpu_arch = .x86_64,270 .cpu_arch = .x86_64,
...@@ -265,6 +274,15 @@ pub const param_sets = [_]CaseParameters{...@@ -265,6 +274,15 @@ pub const param_sets = [_]CaseParameters{
265 .use_llvm = true,274 .use_llvm = true,
266 .use_lld = true,275 .use_lld = true,
267 },276 },
277 .{
278 .target = .{
279 .cpu_arch = .x86_64,
280 .os_tag = .linux,
281 .abi = .none,
282 },
283 .use_llvm = true,
284 .use_new_linker = true,
285 },
268 .{286 .{
269 .target = .{287 .target = .{
270 .cpu_arch = .x86_64,288 .cpu_arch = .x86_64,
...@@ -439,18 +457,23 @@ pub fn addCase(self: *ErrorTrace, case: Case) void {...@@ -439,18 +457,23 @@ pub fn addCase(self: *ErrorTrace, case: Case) void {
439 };457 };
440458
441 const backend_string = if (params.use_llvm == true)459 const backend_string = if (params.use_llvm == true)
442 "-llvm"460 " llvm"
443 else if (params.use_llvm == false)461 else if (params.use_llvm == false)
444 "-selfhosted"462 " selfhosted"
445 else463 else
446 "";464 "";
447465
448 const annotated_case_name = b.fmt("check {s} ({s}{s}{t}{s})", .{466 const annotated_case_name = b.fmt("check {s} ({s} {t}{s}{s})", .{
449 case.name,467 case.name,
450 triple orelse "",468 triple orelse "native",
451 if (triple != null) " " else "",
452 params.optimize,469 params.optimize,
453 backend_string,470 backend_string,
471 if (params.use_new_linker == true)
472 " new_linker"
473 else if (params.use_lld == true)
474 " lld"
475 else
476 "",
454 });477 });
455 if (self.options.test_filters.len > 0) {478 if (self.options.test_filters.len > 0) {
456 for (self.options.test_filters) |test_filter| {479 for (self.options.test_filters) |test_filter| {
...@@ -472,6 +495,7 @@ pub fn addCase(self: *ErrorTrace, case: Case) void {...@@ -472,6 +495,7 @@ pub fn addCase(self: *ErrorTrace, case: Case) void {
472 .use_llvm = params.use_llvm,495 .use_llvm = params.use_llvm,
473 .use_lld = params.use_lld,496 .use_lld = params.use_lld,
474 });497 });
498 exe.use_new_linker = params.use_new_linker;
475 exe.bundle_ubsan_rt = false;499 exe.bundle_ubsan_rt = false;
476500
477 const run = b.addRunArtifact(exe);501 const run = b.addRunArtifact(exe);
test/src/StackTrace.zig+26-2
...@@ -38,6 +38,7 @@ pub const CaseParameters = struct {...@@ -38,6 +38,7 @@ pub const CaseParameters = struct {
38 link_libc: ?bool = null,38 link_libc: ?bool = null,
39 use_llvm: ?bool = null,39 use_llvm: ?bool = null,
40 use_lld: ?bool = null,40 use_lld: ?bool = null,
41 use_new_linker: ?bool = null,
41 pie: ?bool = null,42 pie: ?bool = null,
42 /// To enable this coverage, one of two things needs to happen:43 /// To enable this coverage, one of two things needs to happen:
43 /// * The compiler needs to gain the ability to strip only debug info (not symbols)44 /// * The compiler needs to gain the ability to strip only debug info (not symbols)
...@@ -752,6 +753,14 @@ pub const param_sets = [_]CaseParameters{...@@ -752,6 +753,14 @@ pub const param_sets = [_]CaseParameters{
752 .abi = .none,753 .abi = .none,
753 },754 },
754 },755 },
756 .{
757 .target = .{
758 .cpu_arch = .x86_64,
759 .os_tag = .linux,
760 .abi = .none,
761 },
762 .use_new_linker = true,
763 },
755 .{764 .{
756 .target = .{765 .target = .{
757 .cpu_arch = .x86_64,766 .cpu_arch = .x86_64,
...@@ -761,6 +770,15 @@ pub const param_sets = [_]CaseParameters{...@@ -761,6 +770,15 @@ pub const param_sets = [_]CaseParameters{
761 .use_llvm = true,770 .use_llvm = true,
762 .use_lld = true,771 .use_lld = true,
763 },772 },
773 .{
774 .target = .{
775 .cpu_arch = .x86_64,
776 .os_tag = .linux,
777 .abi = .none,
778 },
779 .use_llvm = true,
780 .use_new_linker = true,
781 },
764 .{782 .{
765 .target = .{783 .target = .{
766 .cpu_arch = .x86_64,784 .cpu_arch = .x86_64,
...@@ -1175,9 +1193,14 @@ fn addCaseInstance(...@@ -1175,9 +1193,14 @@ fn addCaseInstance(
11751193
1176 const annotated_case_name = b.fmt("check {s} ({s}{s}{s}{s}{s}{s}{s}{s}{s})", .{1194 const annotated_case_name = b.fmt("check {s} ({s}{s}{s}{s}{s}{s}{s}{s}{s})", .{
1177 name,1195 name,
1178 triple orelse "",1196 triple orelse "native",
1179 if (triple != null) " " else "",
1180 backend_string,1197 backend_string,
1198 if (params.use_new_linker == true)
1199 " new_linker"
1200 else if (params.use_lld == true)
1201 " lld"
1202 else
1203 "",
1181 if (params.pie == true) " pie" else "",1204 if (params.pie == true) " pie" else "",
1182 if (params.link_libc == true) " libc" else "",1205 if (params.link_libc == true) " libc" else "",
1183 if (params.linkage) |linkage| switch (linkage) {1206 if (params.linkage) |linkage| switch (linkage) {
...@@ -1210,6 +1233,7 @@ fn addCaseInstance(...@@ -1210,6 +1233,7 @@ fn addCaseInstance(
1210 .use_llvm = params.use_llvm,1233 .use_llvm = params.use_llvm,
1211 .use_lld = params.use_lld,1234 .use_lld = params.use_lld,
1212 });1235 });
1236 exe.use_new_linker = params.use_new_linker;
1213 exe.linkage = params.linkage;1237 exe.linkage = params.linkage;
1214 exe.pie = params.pie;1238 exe.pie = params.pie;
1215 exe.bundle_ubsan_rt = false;1239 exe.bundle_ubsan_rt = false;