authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-10-17 15:28:48+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-10-19 18:30:34+01:00
log51cd726f86e0036e9cc19339a70655a149f9d79f
treecec8c2f8e82a3ee7b94033dffe79b18f5dc24911
parentae7911ac25dfa12cd194c3801f996510824848d1
signature Commit is signed but in an unrecognized format.

Elf2: more tracy integration

Also moves the logic for printing node names for debug purposes (used by the `--debug-link-snapshot` logic) to a formatter so it can be reused.

1 files changed, 154 insertions(+), 104 deletions(-)

src/link/Elf2.zig+154-104
......@@ -461,6 +461,135 @@ const Node = union(enum) {
461461 fn fromAtom(atom: link.File.AtomId) MappedFile.Node.Index {
462462 return @fromBackingInt(@backingInt(atom));
463463 }
464
465 fn fmtDebug(ni: MappedFile.Node.Index, elf: *Elf) FormatDebug {
466 return .{ .ni = ni, .elf = elf };
467 }
468 const FormatDebug = struct {
469 ni: MappedFile.Node.Index,
470 elf: *Elf,
471 pub fn format(ctx: FormatDebug, w: *Io.Writer) Io.Writer.Error!void {
472 const elf = ctx.elf;
473 const node = elf.getNode(ctx.ni);
474 try w.writeAll(@tagName(node));
475 switch (node) {
476 // nodes with no payload
477 .deleted,
478 .archive,
479 .archive_header,
480 .elf,
481 .ehdr,
482 .shdr,
483 .debug_addr,
484 .eh_frame_footer,
485 .debug_str_offsets,
486 .unit_padding,
487 .archive_elf_member_header,
488 => |tag| comptime assert(@TypeOf(tag) == void),
489
490 .archive_input_member => |ii| try w.print("({f}{f})", .{
491 ii.path(elf).fmtEscapeString(),
492 fmtMemberString(ii.member(elf)),
493 }),
494 .segment => |phndx| switch (elf.phdrSlice()) {
495 inline else => |phdr| {
496 const ph = &phdr[phndx];
497 try w.writeByte('(');
498 const pt = elf.targetLoad(&ph.type);
499 if (std.enums.tagName(std.elf.PT, pt)) |pt_name|
500 try w.writeAll(pt_name)
501 else inline for (@typeInfo(std.elf.PT).@"enum".decl_names) |decl_name| {
502 const decl_val = @field(std.elf.PT, decl_name);
503 if (@TypeOf(decl_val) != std.elf.PT) continue;
504 if (pt == @field(std.elf.PT, decl_name)) break try w.writeAll(decl_name);
505 } else try w.print("0x{x}", .{pt});
506 try w.writeAll(", ");
507 const pf = elf.targetLoad(&ph.flags);
508 if (pf.R) try w.writeByte('R');
509 if (pf.W) try w.writeByte('W');
510 if (pf.X) try w.writeByte('X');
511 try w.writeByte(')');
512 },
513 },
514 .section, .section_manual_size => |shndx| try w.print("({q})", .{
515 shndx.name(elf).slice(elf),
516 }),
517 .input_section => |isi| {
518 const ii = isi.input(elf);
519 try w.print("({f}{f}, {q})", .{
520 ii.path(elf).fmtEscapeString(),
521 fmtMemberString(ii.member(elf)),
522 elf.getNodeShndx(isi.node(elf)).name(elf).slice(elf),
523 });
524 },
525 .copied_global => |gsi| try w.print("({q})", .{
526 gsi.rawName(elf).slice(elf),
527 }),
528 .nav => |nmi| {
529 const ip = &elf.base.comp.zcu.?.intern_pool;
530 try w.print("({qf})", .{
531 ip.getNav(nmi.nav(elf)).fqn.fmt(ip),
532 });
533 },
534 .uav => |umi| {
535 const zcu = elf.base.comp.zcu.?;
536 const val: Value = .fromInterned(umi.uavValue(elf));
537 try w.print("({f}, {f})", .{
538 val.typeOf(zcu).fmt(zcu),
539 val.fmtValue(zcu),
540 });
541 },
542 inline .lazy_code, .lazy_const_data => |lmi| try w.print("({f})", .{
543 Type.fromInterned(lmi.lazySymbol(elf).ty).fmt(elf.base.comp.zcu.?),
544 }),
545
546 .debug_shared => |ss| try w.print("({t})", .{ss}),
547
548 .unit_frame,
549 .unit_frame_cie,
550 .unit_debug_info,
551 .unit_debug_info_header,
552 .unit_debug_info_footer,
553 .unit_debug_line,
554 .unit_debug_line_header,
555 .unit_debug_rnglists,
556 => |ui| try w.print("({q})", .{
557 ui.mod(&elf.dwarf).fully_qualified_name,
558 }),
559
560 .const_debug_info => |cpi| switch (cpi.val(&elf.dwarf.const_pool)) {
561 .generic_poison_type => try w.writeAll("(anytype)"),
562 else => |val| try w.print("({f})", .{
563 Value.fromInterned(val).fmtValue(elf.base.comp.zcu.?),
564 }),
565 },
566 .global_debug_info => |gi| {
567 const ip = &elf.base.comp.zcu.?.intern_pool;
568 try w.print("({qf})", .{
569 ip.getNav(gi.nav(&elf.dwarf)).fqn.fmt(ip),
570 });
571 },
572 .func_frame_fde, .func_debug_info, .func_debug_line => |fi| {
573 const ip = &elf.base.comp.zcu.?.intern_pool;
574 try w.print("({qf})", .{
575 ip.getNav(fi.nav(&elf.dwarf)).fqn.fmt(ip),
576 });
577 },
578 .decl_debug_info => |di| {
579 const comp = elf.base.comp;
580 const zcu = comp.zcu.?;
581 const ip = &zcu.intern_pool;
582 const src_inst = di.srcInst(&elf.dwarf);
583 const path = zcu.fileByIndex(src_inst.resolveFile(ip)).path;
584 if (src_inst.resolve(ip)) |inst| {
585 try w.print("({f}, %{d})", .{ path.fmt(comp), inst });
586 } else {
587 try w.print("({f}, lost)", .{path.fmt(comp)});
588 }
589 },
590 }
591 }
592 };
464593};
465594
466595const InputSection = struct {
......@@ -2985,10 +3114,15 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{
29853114/// some operation which requires relocations to be re-applied, it can pass `force_apply_relocs` as
29863115/// `true` to guarantee this function to do so.
29873116fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_relocs: bool) Error!void {
3117 const trace = tracy.trace(@src());
3118 defer trace.end();
3119
29883120 const gpa = elf.base.comp.gpa;
29893121
29903122 const gsi = orig_gsi.resolveAlias(elf);
29913123
3124 trace.addText(gsi.rawName(elf).slice(elf));
3125
29923126 const maybe_alias_gsi = gsi.findAliaser(elf);
29933127
29943128 var apply_relocs: bool = force_apply_relocs;
......@@ -4132,7 +4266,20 @@ const Symbol = struct {
41324266 }
41334267
41344268 fn flushMoved(sym_id: Symbol.Id, elf: *Elf, new_value: u64) void {
4269 const trace = tracy.trace(@src());
4270 defer trace.end();
4271
41354272 const sym_index = sym_id.index(elf);
4273
4274 trace.addText(name: {
4275 // There isn't a general `name` method on `Symbol.Id` because it would be incorrect
4276 // to ever actually care about the name of a local symbol.
4277 const name: String(.strtab) = switch (elf.symPtr(sym_index)) {
4278 inline else => |sym| @fromBackingInt(elf.targetLoad(&sym.name)),
4279 };
4280 break :name name.slice(elf);
4281 });
4282
41364283 switch (elf.symPtr(sym_index)) {
41374284 inline else => |sym| elf.targetStore(&sym.value, @intCast(new_value)),
41384285 }
......@@ -10717,6 +10864,9 @@ pub fn idle(elf: *Elf) link.Error!bool {
1071710864 elf.mf.nodes_lock.lock();
1071810865 defer elf.mf.nodes_lock.unlock();
1071910866
10867 const trace = tracy.trace(@src());
10868 defer trace.end();
10869
1072010870 const comp = elf.base.comp;
1072110871 const diags = &comp.link_diags;
1072210872
......@@ -11285,6 +11435,7 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {
1128511435fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void {
1128611436 const trace = tracy.trace(@src());
1128711437 defer trace.end();
11438 trace.addTextFmt("{f}", .{Node.fmtDebug(ni, elf)});
1128811439
1128911440 switch (elf.getNode(ni)) {
1129011441 .deleted => unreachable,
......@@ -11904,6 +12055,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro
1190412055fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void {
1190512056 const trace = tracy.trace(@src());
1190612057 defer trace.end();
12058 trace.addTextFmt("{f}", .{Node.fmtDebug(ni, elf)});
1190712059
1190812060 _, const size = ni.location(&elf.mf).resolve(&elf.mf);
1190912061 switch (elf.getNode(ni)) {
......@@ -12039,6 +12191,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
1203912191fn flushPadding(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void {
1204012192 const trace = tracy.trace(@src());
1204112193 defer trace.end();
12194 trace.addTextFmt("{f}", .{Node.fmtDebug(ni, elf)});
1204212195
1204312196 const node = elf.getNode(ni);
1204412197 switch (node) {
......@@ -12798,111 +12951,8 @@ pub fn printNode(
1279812951 ni: MappedFile.Node.Index,
1279912952 indent: usize,
1280012953) Io.Writer.Error!void {
12801 const node = elf.getNode(ni);
1280212954 try w.splatByteAll(' ', indent);
12803 try w.writeAll(@tagName(node));
12804 switch (node) {
12805 else => {},
12806 .segment => |phndx| switch (elf.phdrSlice()) {
12807 inline else => |phdr| {
12808 const ph = &phdr[phndx];
12809 try w.writeByte('(');
12810 const pt = elf.targetLoad(&ph.type);
12811 if (std.enums.tagName(std.elf.PT, pt)) |pt_name|
12812 try w.writeAll(pt_name)
12813 else inline for (@typeInfo(std.elf.PT).@"enum".decl_names) |decl_name| {
12814 const decl_val = @field(std.elf.PT, decl_name);
12815 if (@TypeOf(decl_val) != std.elf.PT) continue;
12816 if (pt == @field(std.elf.PT, decl_name)) break try w.writeAll(decl_name);
12817 } else try w.print("0x{x}", .{pt});
12818 try w.writeAll(", ");
12819 const pf = elf.targetLoad(&ph.flags);
12820 if (pf.R) try w.writeByte('R');
12821 if (pf.W) try w.writeByte('W');
12822 if (pf.X) try w.writeByte('X');
12823 try w.writeByte(')');
12824 },
12825 },
12826 .section, .section_manual_size => |shndx| try w.print("({s})", .{shndx.name(elf).slice(elf)}),
12827 .input_section => |isi| {
12828 const ii = isi.input(elf);
12829 try w.print("({f}{f}, {s})", .{
12830 ii.path(elf).fmtEscapeString(),
12831 fmtMemberString(ii.member(elf)),
12832 elf.getNodeShndx(isi.node(elf)).name(elf).slice(elf),
12833 });
12834 },
12835 .copied_global => |gsi| try w.print("(copy:{s})", .{gsi.rawName(elf).slice(elf)}),
12836 .nav => |nmi| {
12837 const zcu = elf.base.comp.zcu.?;
12838 const ip = &zcu.intern_pool;
12839 const nav = ip.getNav(nmi.nav(elf));
12840 try w.print("({f}, {f})", .{
12841 Type.fromInterned(nav.resolved.?.type).fmt(zcu),
12842 nav.fqn.fmt(ip),
12843 });
12844 },
12845 .uav => |umi| {
12846 const zcu = elf.base.comp.zcu.?;
12847 const val: Value = .fromInterned(umi.uavValue(elf));
12848 try w.print("({f}, {f})", .{
12849 val.typeOf(zcu).fmt(zcu),
12850 val.fmtValue(zcu),
12851 });
12852 },
12853 inline .lazy_code, .lazy_const_data => |lmi| try w.print("({f})", .{
12854 Type.fromInterned(lmi.lazySymbol(elf).ty).fmt(elf.base.comp.zcu.?),
12855 }),
12856 .debug_shared => |ss| try w.print("({})", .{ss}),
12857 .unit_frame,
12858 .unit_frame_cie,
12859 .unit_debug_info,
12860 .unit_debug_info_header,
12861 .unit_debug_info_footer,
12862 .unit_debug_line,
12863 .unit_debug_line_header,
12864 .unit_debug_rnglists,
12865 => |ui| try w.print("({s})", .{ui.mod(&elf.dwarf).fully_qualified_name}),
12866 .const_debug_info => |cpi| switch (cpi.val(&elf.dwarf.const_pool)) {
12867 .generic_poison_type => try w.writeAll("(anytype)"),
12868 else => |val| try w.print("({f})", .{
12869 Value.fromInterned(val).fmtValue(elf.base.comp.zcu.?),
12870 }),
12871 },
12872 .global_debug_info => |gi| {
12873 const zcu = elf.base.comp.zcu.?;
12874 const ip = &zcu.intern_pool;
12875 const nav = ip.getNav(gi.nav(&elf.dwarf));
12876 try w.writeByte('(');
12877 if (nav.resolved) |resolved| try w.print("{f}, ", .{
12878 Type.fromInterned(resolved.type).fmt(zcu),
12879 });
12880 try w.print("{f}", .{nav.fqn.fmt(ip)});
12881 if (nav.resolved) |resolved| try w.print(", {f}", .{
12882 Value.fromInterned(resolved.value).fmtValue(zcu),
12883 });
12884 try w.writeByte(')');
12885 },
12886 .func_frame_fde, .func_debug_info, .func_debug_line => |fi| {
12887 const zcu = elf.base.comp.zcu.?;
12888 const ip = &zcu.intern_pool;
12889 const nav = ip.getNav(fi.nav(&elf.dwarf));
12890 try w.writeByte('(');
12891 if (nav.resolved) |resolved| try w.print("{f}, ", .{
12892 Type.fromInterned(resolved.type).fmt(zcu),
12893 });
12894 try w.print("{f})", .{nav.fqn.fmt(ip)});
12895 },
12896 .decl_debug_info => |di| {
12897 const comp = elf.base.comp;
12898 const zcu = comp.zcu.?;
12899 const ip = &zcu.intern_pool;
12900 const src_inst = di.srcInst(&elf.dwarf);
12901 try w.print("({f}, ", .{zcu.fileByIndex(src_inst.resolveFile(ip)).path.fmt(comp)});
12902 if (src_inst.resolve(ip)) |inst| try w.print("%{d}", .{inst}) else try w.writeAll("lost");
12903 try w.writeByte(')');
12904 },
12905 }
12955 try w.print("{f}", .{Node.fmtDebug(ni, elf)});
1290612956 {
1290712957 const mf_node = &elf.mf.nodes.items[@backingInt(ni)];
1290812958 const off, const size = mf_node.location().resolve(&elf.mf);