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 {
387387 const next_offset = unit_header.header_length + unit_header.unit_length;
388388
389389 const version = try fr.takeInt(u16, endian);
390 if (version < 2 or version > 5) return bad();
391
392390 var address_size: u8 = undefined;
393391 var debug_abbrev_offset: u64 = undefined;
394 if (version >= 5) {
392 if (version == 5) {
395393 const unit_type = try fr.takeByte();
396394 if (unit_type != DW.UT.compile) return bad();
397395 address_size = try fr.takeByte();
398396 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
399 } else {
397 } else if (version >= 2 and version < 5) {
400398 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
401399 address_size = try fr.takeByte();
400 } else {
401 this_unit_offset += next_offset;
402 continue;
402403 }
403404
404405 const abbrev_table = try di.getAbbrevTable(gpa, debug_abbrev_offset);
......@@ -585,18 +586,19 @@ fn scanAllCompileUnits(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!voi
585586 const next_offset = unit_header.header_length + unit_header.unit_length;
586587
587588 const version = try fr.takeInt(u16, endian);
588 if (version < 2 or version > 5) return bad();
589
590589 var address_size: u8 = undefined;
591590 var debug_abbrev_offset: u64 = undefined;
592 if (version >= 5) {
591 if (version == 5) {
593592 const unit_type = try fr.takeByte();
594593 if (unit_type != UT.compile) return bad();
595594 address_size = try fr.takeByte();
596595 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
597 } else {
596 } else if (version >= 2 and version < 5) {
598597 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
599598 address_size = try fr.takeByte();
599 } else {
600 this_unit_offset += next_offset;
601 continue;
600602 }
601603
602604 const abbrev_table = try di.getAbbrevTable(gpa, debug_abbrev_offset);
src/link/Dwarf2.zig-6
......@@ -1058,7 +1058,6 @@ pub const WipNav = struct {
10581058 0
10591059 else
10601060 zcu.navSrcLine(zcu.funcInfo(debug.wip_nav.func).owner_nav) + 1) + line);
1061 try di_w.writeUleb128(line);
10621061 try di_w.writeUleb128(column + 1);
10631062 block.low_pc_off = code_off;
10641063 try dwarf.addrSym(di_nw, debug.wip_nav.func_si, code_off);
......@@ -2898,11 +2897,6 @@ fn updateConstInner(
28982897
28992898 else => return,
29002899 .func => |func| {
2901 const fi = try dwarf.getFunc(func.owner_nav);
2902 switch (fi.get(dwarf).state) {
2903 .unresolved => {},
2904 .resolved => return,
2905 }
29062900 const fn_ty = ip.indexToKey(func.ty).func_type;
29072901 const nav = ip.getNav(func.owner_nav);
29082902 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
src/link/Elf2.zig+19-21
......@@ -8753,7 +8753,7 @@ pub fn updateConst(
87538753) link.Error!void {
87548754 switch (val) {
87558755 .anyerror_type => {}, // handled in `updateErrorData` instead
8756 else => try elf.updateConstInner(pt, cpi, val),
8756 else => try elf.updateConstInner(pt, cpi, val, .complete),
87578757 }
87588758}
87598759fn updateConstInner(
......@@ -8761,11 +8761,22 @@ fn updateConstInner(
87618761 pt: Zcu.PerThread,
87628762 cpi: link.ConstPool.Index,
87638763 val: InternPool.Index,
8764 complete: enum { incomplete, complete },
87648765) link.Error!void {
87658766 switch (elf.base.comp.config.debug_format) {
87668767 .strip => {},
87678768 .dwarf => {
87688769 {
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 }
87698780 const gpa = elf.base.comp.gpa;
87708781 const debug_info_ni = Dwarf.Const.get(cpi, &elf.dwarf).debug_info_ni.unwrap().?;
87718782 try debug_info_ni.moved(gpa, &elf.mf);
......@@ -8773,7 +8784,10 @@ fn updateConstInner(
87738784 debug_info_ni.writer(gpa, &elf.mf, &di_nw);
87748785 defer di_nw.deinit();
87758786 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 }
87778791 }
87788792 try elf.genPending(pt);
87798793 },
......@@ -8787,23 +8801,7 @@ pub fn updateConstIncomplete(
87878801 cpi: link.ConstPool.Index,
87888802 val: InternPool.Index,
87898803) link.Error!void {
8790 switch (elf.base.comp.config.debug_format) {
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 }
8804 return elf.updateConstInner(pt, cpi, val, .incomplete);
88078805}
88088806
88098807pub fn updateFunc(
......@@ -9032,7 +9030,7 @@ fn updateFuncInner(
90329030 if (func.analysisUnordered(ip).inferred_error_set) {
90339031 const ies = ip.getIfExists(.{ .inferred_error_set_type = func_index }).?;
90349032 if (elf.dwarf.const_pool.getIfExists(ies)) |cpi|
9035 try elf.updateConstInner(pt, cpi, ies);
9033 try elf.updateConstInner(pt, cpi, ies, .complete);
90369034 }
90379035 },
90389036 .none => {},
......@@ -9083,7 +9081,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void {
90839081 .index = @intCast(lmi),
90849082 });
90859083 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);
90879085}
90889086
90899087pub fn flush(
test/src/ErrorTrace.zig+29-5
......@@ -36,6 +36,7 @@ pub const CaseParameters = struct {
3636 optimize: OptimizeMode = .debug,
3737 use_llvm: ?bool = null,
3838 use_lld: ?bool = null,
39 use_new_linker: ?bool = null,
3940
4041 // This is intended for targets that, for any reason, shouldn't be run as part of a normal test
4142 // invocation. This could be because of a slow backend, requiring a newer LLVM version, being
......@@ -256,6 +257,14 @@ pub const param_sets = [_]CaseParameters{
256257 .abi = .none,
257258 },
258259 },
260 .{
261 .target = .{
262 .cpu_arch = .x86_64,
263 .os_tag = .linux,
264 .abi = .none,
265 },
266 .use_new_linker = true,
267 },
259268 .{
260269 .target = .{
261270 .cpu_arch = .x86_64,
......@@ -265,6 +274,15 @@ pub const param_sets = [_]CaseParameters{
265274 .use_llvm = true,
266275 .use_lld = true,
267276 },
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 },
268286 .{
269287 .target = .{
270288 .cpu_arch = .x86_64,
......@@ -439,18 +457,23 @@ pub fn addCase(self: *ErrorTrace, case: Case) void {
439457 };
440458
441459 const backend_string = if (params.use_llvm == true)
442 "-llvm"
460 " llvm"
443461 else if (params.use_llvm == false)
444 "-selfhosted"
462 " selfhosted"
445463 else
446464 "";
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})", .{
449467 case.name,
450 triple orelse "",
451 if (triple != null) " " else "",
468 triple orelse "native",
452469 params.optimize,
453470 backend_string,
471 if (params.use_new_linker == true)
472 " new_linker"
473 else if (params.use_lld == true)
474 " lld"
475 else
476 "",
454477 });
455478 if (self.options.test_filters.len > 0) {
456479 for (self.options.test_filters) |test_filter| {
......@@ -472,6 +495,7 @@ pub fn addCase(self: *ErrorTrace, case: Case) void {
472495 .use_llvm = params.use_llvm,
473496 .use_lld = params.use_lld,
474497 });
498 exe.use_new_linker = params.use_new_linker;
475499 exe.bundle_ubsan_rt = false;
476500
477501 const run = b.addRunArtifact(exe);
test/src/StackTrace.zig+26-2
......@@ -38,6 +38,7 @@ pub const CaseParameters = struct {
3838 link_libc: ?bool = null,
3939 use_llvm: ?bool = null,
4040 use_lld: ?bool = null,
41 use_new_linker: ?bool = null,
4142 pie: ?bool = null,
4243 /// To enable this coverage, one of two things needs to happen:
4344 /// * The compiler needs to gain the ability to strip only debug info (not symbols)
......@@ -752,6 +753,14 @@ pub const param_sets = [_]CaseParameters{
752753 .abi = .none,
753754 },
754755 },
756 .{
757 .target = .{
758 .cpu_arch = .x86_64,
759 .os_tag = .linux,
760 .abi = .none,
761 },
762 .use_new_linker = true,
763 },
755764 .{
756765 .target = .{
757766 .cpu_arch = .x86_64,
......@@ -761,6 +770,15 @@ pub const param_sets = [_]CaseParameters{
761770 .use_llvm = true,
762771 .use_lld = true,
763772 },
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 },
764782 .{
765783 .target = .{
766784 .cpu_arch = .x86_64,
......@@ -1175,9 +1193,14 @@ fn addCaseInstance(
11751193
11761194 const annotated_case_name = b.fmt("check {s} ({s}{s}{s}{s}{s}{s}{s}{s}{s})", .{
11771195 name,
1178 triple orelse "",
1179 if (triple != null) " " else "",
1196 triple orelse "native",
11801197 backend_string,
1198 if (params.use_new_linker == true)
1199 " new_linker"
1200 else if (params.use_lld == true)
1201 " lld"
1202 else
1203 "",
11811204 if (params.pie == true) " pie" else "",
11821205 if (params.link_libc == true) " libc" else "",
11831206 if (params.linkage) |linkage| switch (linkage) {
......@@ -1210,6 +1233,7 @@ fn addCaseInstance(
12101233 .use_llvm = params.use_llvm,
12111234 .use_lld = params.use_lld,
12121235 });
1236 exe.use_new_linker = params.use_new_linker;
12131237 exe.linkage = params.linkage;
12141238 exe.pie = params.pie;
12151239 exe.bundle_ubsan_rt = false;