authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-05 01:55:35-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-23 00:26:56-04:00
logdc8dd5c08a4715c39de2e6ca8f4d4c6c4aa1f96b
treee1a0bce3cc27e9585a40917c61fc63cba7f765e1
parent769b5eaf9415f25cd68d6cd525614373f162ea90

Coff: more debug output

- Track non-global input symbol names, for use in debug output and error messages - Output COMDAT section names where possible

1 files changed, 108 insertions(+), 34 deletions(-)

src/link/Coff.zig+108-34
......@@ -44,7 +44,7 @@ pending_default_libs: std.ArrayList(struct {
4444}),
4545alternate_names: std.AutoArrayHashMapUnmanaged(String, String),
4646input_objects: std.ArrayList(InputObject),
47input_symbols: std.ArrayList(Symbol.Index),
47input_symbols: std.ArrayList(struct { si: Symbol.Index, name: String }),
4848input_sections: std.ArrayList(Node.InputSection),
4949input_section_pending_index: u32,
5050inputs_complete: bool,
......@@ -300,6 +300,7 @@ pub const Node = union(enum) {
300300 const InputSection = struct {
301301 ioi: InputObject.Index,
302302 si: Symbol.Index,
303 comdat_si: Symbol.Index,
303304 file_location: MappedFile.Node.FileLocation,
304305 first_li: Node.InputSection.LocalIndex,
305306 crc: u32,
......@@ -918,9 +919,13 @@ pub const Symbol = struct {
918919 /// Relocations targeting this symbol
919920 target_relocs: Reloc.Index,
920921 section_number: SectionNumber,
921 /// Only used when outputting objects
922 sti: SymbolTable.Index,
923922 gmi: Node.GlobalMapIndex,
923 extra: union {
924 /// Only valid when outputting objects
925 sti: SymbolTable.Index,
926 /// Only valid when .ni == .input_section and .value_tag == .node_offset
927 isli: Node.InputSection.LocalIndex,
928 },
924929
925930 pub const DllStorageClass = enum(u2) {
926931 default,
......@@ -1062,7 +1067,7 @@ pub const Symbol = struct {
10621067
10631068 pub fn flushSymbolTableIndex(si: Symbol.Index, coff: *Coff) void {
10641069 const sym = si.get(coff);
1065 const index = sym.sti.unwrap() orelse return;
1070 const index = sym.extra.sti.unwrap() orelse return;
10661071 var ri = sym.target_relocs;
10671072 while (ri != .none) {
10681073 const reloc = ri.get(coff);
......@@ -2496,7 +2501,7 @@ pub fn symbolTableEntryPtr(coff: *Coff, sti: SymbolTable.Index) ?*align(2) std.c
24962501}
24972502
24982503pub fn symbolTableSectionAuxEntryPtr(coff: *Coff, si: Symbol.Index) *align(2) std.coff.SectionDefinition {
2499 const sti = si.get(coff).sti;
2504 const sti = si.get(coff).extra.sti;
25002505 const entry = symbolTableEntryPtr(coff, sti).?;
25012506 assert(entry.storage_class == .STATIC and entry.number_of_aux_symbols == 1);
25022507 return @ptrCast(@alignCast(symbolTableEntryStoragePtr(coff, sti.unwrap().? + 1)));
......@@ -2546,8 +2551,8 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {
25462551 .loc_relocs = .none,
25472552 .target_relocs = .none,
25482553 .section_number = .UNDEFINED,
2549 .sti = .none,
25502554 .gmi = .none,
2555 .extra = .{ .sti = .none },
25512556 };
25522557 return @enumFromInt(coff.symbols.items.len);
25532558}
......@@ -2973,7 +2978,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
29732978 const sym = si.get(coff);
29742979 assert(sym.ni != .none or sym.gmi != .none);
29752980
2976 const entry = coff.symbolTableEntryPtr(sym.sti) orelse entry: {
2981 const entry = coff.symbolTableEntryPtr(sym.extra.sti) orelse entry: {
29772982 var buf: [15]u8 = undefined;
29782983 const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType =
29792984 if (sym.gmi != .none) blk: {
......@@ -3038,10 +3043,10 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
30383043 try coff.symbol_table.ni.resize(&coff.mf, gpa, new_num_symbols * std.coff.Symbol.sizeOf());
30393044
30403045 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);
3041 sym.sti = .wrap(old_num_symbols);
3046 sym.extra = .{ .sti = .wrap(old_num_symbols) };
30423047 si.flushSymbolTableIndex(coff);
30433048
3044 const entry = coff.symbolTableEntryPtr(sym.sti).?;
3049 const entry = coff.symbolTableEntryPtr(sym.extra.sti).?;
30453050 symbol_name.store(coff, &entry.name);
30463051
30473052 entry.section_number = @enumFromInt(@intFromEnum(sym.section_number));
......@@ -3071,7 +3076,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
30713076 },
30723077 });
30733078
3074 log.debug("flushSymbolTableEntry({d}) = {d}", .{ si, sym.sti });
3079 log.debug("flushSymbolTableEntry({d}) = {d}", .{ si, sym.extra.sti });
30753080}
30763081
30773082fn flushInputMember(coff: *Coff, iami: InputArchive.Member.Index) !void {
......@@ -3467,8 +3472,8 @@ pub fn addReloc(
34673472 else => |loc_sn| sri: {
34683473 // The target may not have a node yet, or it could be an extern that will never
34693474 // have a node. In that case, flushGlobal will create the symbol table entry.
3470 const sti: SymbolTable.Index = if (target.sti != .none)
3471 target.sti
3475 const sti: SymbolTable.Index = if (target.extra.sti != .none)
3476 target.extra.sti
34723477 else if (target.ni != .none) sti: {
34733478 try coff.pendingSymbolTableEntry(target_si);
34743479 break :sti .none;
......@@ -4381,6 +4386,10 @@ fn loadObject(
43814386 },
43824387 .first_li = @enumFromInt(coff.input_symbols.items.len),
43834388 .crc = section.comdat_crc,
4389 .comdat_si = if (section.comdat_psi.unwrap()) |psi|
4390 pending_symbols.values()[psi].si
4391 else
4392 .null,
43844393 };
43854394
43864395 log.debug(
......@@ -4489,6 +4498,9 @@ fn loadObject(
44894498 .weak_external_aux,
44904499 => unreachable,
44914500 }
4501
4502 if (section.comdat_psi.unwrap() == @as(u32, @intCast(i)))
4503 coff.getNode(section.si.get(coff).ni).input_section.inputSection(coff).comdat_si = symbol.si;
44924504 }
44934505
44944506 if (symbol.weak_external_psi.unwrap()) |weak_external_i| {
......@@ -4610,7 +4622,11 @@ fn loadObject(
46104622
46114623 if (include_section) {
46124624 assert(coff.getNode(symbol.si.get(coff).ni) == .input_section);
4613 coff.input_symbols.addOneAssumeCapacity().* = symbol.si;
4625 symbol.si.get(coff).extra = .{ .isli = @enumFromInt(coff.input_symbols.items.len) };
4626 coff.input_symbols.addOneAssumeCapacity().* = .{
4627 .si = symbol.si,
4628 .name = symbol.name,
4629 };
46144630 }
46154631 }
46164632}
......@@ -5450,11 +5466,30 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {
54505466 .input_section => |isi| {
54515467 const other_ioi = isi.input(coff);
54525468 if (loc_sym.gmi == .none) {
5453 // TODO: We could report non-global names here if we intern them in loadObject
5454 err.addNote("referenced by input '{f}{f}'", .{
5455 other_ioi.path(coff).fmtEscapeString(),
5456 fmtMemberNameString(other_ioi.memberName(coff)),
5457 });
5469 const section = isi.inputSection(coff);
5470 const section_name = coff.getNode(loc_sym.ni.parent(&coff.mf))
5471 .object_section.name(coff).toSlice(coff);
5472
5473 if (section.comdat_si != .null) {
5474 const comdat_sym = section.comdat_si.get(coff);
5475 const comdat_name = if (comdat_sym.gmi != .none)
5476 comdat_sym.gmi.globalName(coff).name.toSlice(coff)
5477 else
5478 coff.input_symbols.items[@intFromEnum(comdat_sym.extra.isli)].name.toSlice(coff);
5479
5480 err.addNote("referenced by input COMDAT section '{s}={s}' '{f}{f}'", .{
5481 section_name,
5482 comdat_name,
5483 other_ioi.path(coff).fmtEscapeString(),
5484 fmtMemberNameString(other_ioi.memberName(coff)),
5485 });
5486 } else {
5487 err.addNote("referenced by input section '{s}' '{f}{f}'", .{
5488 section_name,
5489 other_ioi.path(coff).fmtEscapeString(),
5490 fmtMemberNameString(other_ioi.memberName(coff)),
5491 });
5492 }
54585493 } else {
54595494 err.addNote("referenced by input symbol '{s}' from '{f}{f}'", .{
54605495 loc_sym.gmi.globalName(coff).name.toSlice(coff),
......@@ -6558,9 +6593,9 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
65586593 },
65596594 .input_section => |isi| {
65606595 isi.symbol(coff).flushMoved(coff);
6561 for (coff.input_symbols.items[@intFromEnum(isi.firstSymbol(coff))..]) |si| {
6562 if (si.get(coff).ni != ni) break;
6563 si.flushMoved(coff);
6596 for (coff.input_symbols.items[@intFromEnum(isi.firstSymbol(coff))..]) |input_symbol| {
6597 if (input_symbol.si.get(coff).ni != ni) break;
6598 input_symbol.si.flushMoved(coff);
65646599 }
65656600 },
65666601 .import_directory_table => coff.targetStore(
......@@ -7165,7 +7200,7 @@ pub fn dump(coff: *Coff, w: *Io.Writer, tid: Zcu.PerThread.Id) !link.File.DumpRe
71657200 try coff.printSection(w, name, sec.si);
71667201 try w.writeAll("Symbol table:\n");
71677202 for (1..coff.symbols.items.len) |si|
7168 try coff.printSymbol(w, @enumFromInt(si));
7203 try coff.printSymbol(w, tid, @enumFromInt(si));
71697204
71707205 return .enabled;
71717206 }
......@@ -7183,10 +7218,15 @@ fn printSection(coff: *Coff, w: *Io.Writer, name: String, si: Symbol.Index) !voi
71837218 });
71847219}
71857220
7186fn printSymbol(coff: *Coff, w: *Io.Writer, si: Symbol.Index) !void {
7221fn printSymbol(
7222 coff: *Coff,
7223 w: *Io.Writer,
7224 tid: Zcu.PerThread.Id,
7225 si: Symbol.Index,
7226) !void {
71877227 const sym = si.get(coff);
71887228 const node = coff.getNode(sym.ni);
7189 try w.print("{d:0>6}@{d:0>2} {x:08} {s} n{d:0>8}+{x:08}:{t: <26} | {x:08} | {f}\n", .{
7229 try w.print("{d:0>6}@{d:0>2} {x:08} {s} {s} n{d:0>8}+{x:08}:{t: <26} | {x:08} ", .{
71907230 si,
71917231 sym.section_number,
71927232 if (sym.flags.value_tag == .size)
......@@ -7195,6 +7235,12 @@ fn printSymbol(coff: *Coff, w: *Io.Writer, si: Symbol.Index) !void {
71957235 sym.ni.location(&coff.mf).resolve(&coff.mf)[1]
71967236 else
71977237 0,
7238 switch (sym.flags.value_tag) {
7239 .alias_name => "an",
7240 .alias_si => "as",
7241 .node_offset => "no",
7242 .size => "sz",
7243 },
71987244 switch (sym.flags.type) {
71997245 .unknown => "u",
72007246 .code => "c",
......@@ -7204,8 +7250,15 @@ fn printSymbol(coff: *Coff, w: *Io.Writer, si: Symbol.Index) !void {
72047250 if (sym.flags.value_tag == .node_offset) sym.value.node_offset else 0,
72057251 node,
72067252 sym.rva,
7207 fmtGlobalName(coff, sym.gmi),
72087253 });
7254
7255 if (sym.gmi != .none) {
7256 try w.print("G {f}\n", .{fmtGlobalName(coff, sym.gmi)});
7257 } else {
7258 try w.writeAll("| ");
7259 try coff.printNodeName(w, tid, node);
7260 try w.writeByte('\n');
7261 }
72097262}
72107263
72117264const FmtGlobalName = struct { coff: *Coff, gmi: Node.GlobalMapIndex };
......@@ -7222,16 +7275,12 @@ fn globalNameEscape(data: FmtGlobalName, w: *std.Io.Writer) std.Io.Writer.Error!
72227275 try w.print("({s})", .{lib_name.toSlice(data.coff)});
72237276}
72247277
7225pub fn printNode(
7278fn printNodeName(
72267279 coff: *Coff,
7280 w: *std.Io.Writer,
72277281 tid: Zcu.PerThread.Id,
7228 w: *Io.Writer,
7229 ni: MappedFile.Node.Index,
7230 indent: usize,
7282 node: Node,
72317283) !void {
7232 const node = coff.getNode(ni);
7233 try w.splatByteAll(' ', indent);
7234 try w.writeAll(@tagName(node));
72357284 switch (node) {
72367285 else => {},
72377286 .image_section => |si| try w.print("({s})", .{
......@@ -7239,11 +7288,23 @@ pub fn printNode(
72397288 }),
72407289 .input_section => |isi| {
72417290 const ioi = isi.input(coff);
7242 try w.print("({f}{f}, {s})", .{
7291 const is = isi.inputSection(coff);
7292 // TODO: Use only filename from these paths, they are long
7293 try w.print("({f}{f}, {s}", .{
72437294 ioi.path(coff).fmtEscapeString(),
72447295 fmtMemberNameString(ioi.memberName(coff)),
7245 coff.getNode(isi.symbol(coff).node(coff).parent(&coff.mf)).object_section.name(coff).toSlice(coff),
7296 coff.getNode(is.si.node(coff).parent(&coff.mf)).object_section.name(coff).toSlice(coff),
72467297 });
7298 if (is.comdat_si != .null) {
7299 const comdat_sym = is.comdat_si.get(coff);
7300 const comdat_name = if (comdat_sym.gmi != .none)
7301 comdat_sym.gmi.globalName(coff).name.toSlice(coff)
7302 else
7303 coff.input_symbols.items[@intFromEnum(comdat_sym.extra.isli)].name.toSlice(coff);
7304
7305 try w.print("={s}", .{comdat_name});
7306 }
7307 try w.writeAll(")");
72477308 },
72487309 .import_lookup_table,
72497310 .import_address_table,
......@@ -7284,6 +7345,19 @@ pub fn printNode(
72847345 }),
72857346 }),
72867347 }
7348}
7349
7350pub fn printNode(
7351 coff: *Coff,
7352 tid: Zcu.PerThread.Id,
7353 w: *Io.Writer,
7354 ni: MappedFile.Node.Index,
7355 indent: usize,
7356) !void {
7357 const node = coff.getNode(ni);
7358 try w.splatByteAll(' ', indent);
7359 try w.writeAll(@tagName(node));
7360 try coff.printNodeName(w, tid, node);
72877361 {
72887362 const mf_node = &coff.mf.nodes.items[@intFromEnum(ni)];
72897363 const off, const size = mf_node.location().resolve(&coff.mf);