authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-04 05:40:46+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-04 05:40:46+02:00
log3fdcbc03d43246a39411725b1e4e23e862d32b82
tree24dae16c0a65be5e9656d31473b37e15cf64b2e3
parent8a3fc2fecf365927a470a25d43e0bd26a01eb9ed
parentd44db8ea0c35122aefbb1d86bed820b382eec988

Merge pull request 'Elf2: start implementing debug info' (#36413) from jacobly/dwarf2 into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36413 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

76 files changed, 10355 insertions(+), 2620 deletions(-)

CMakeLists.txt+1
...@@ -383,6 +383,7 @@ set(ZIG_STAGE2_SOURCES...@@ -383,6 +383,7 @@ set(ZIG_STAGE2_SOURCES
383 src/link/ConstPool.zig383 src/link/ConstPool.zig
384 src/link/Coff.zig384 src/link/Coff.zig
385 src/link/Dwarf.zig385 src/link/Dwarf.zig
386 src/link/Dwarf2.zig
386 src/link/Elf.zig387 src/link/Elf.zig
387 src/link/Elf/Archive.zig388 src/link/Elf/Archive.zig
388 src/link/Elf/Atom.zig389 src/link/Elf/Atom.zig
README.md+13-6
...@@ -781,12 +781,20 @@ If you will be debugging the Zig compiler itself, or if you will be debugging...@@ -781,12 +781,20 @@ If you will be debugging the Zig compiler itself, or if you will be debugging
781any project compiled with Zig's LLVM backend (not recommended with the LLDB781any project compiled with Zig's LLVM backend (not recommended with the LLDB
782fork, prefer vanilla LLDB with a version that matches the version of LLVM that782fork, prefer vanilla LLDB with a version that matches the version of LLVM that
783Zig is using), you can get a better debugging experience by using783Zig is using), you can get a better debugging experience by using
784[`lldb_pretty_printers.py`](https://codeberg.org/ziglang/zig/src/branch/master/tools/lldb_pretty_printers.py).784[`lldb/pretty_printers.py`](https://codeberg.org/ziglang/zig/src/branch/master/lib/lldb/pretty_printers.py)
785which is included in Zig's installed lib dir.
785786
786Put this line in `~/.lldbinit`:787Put this line in `~/.lldbinit`:
787788
788```789```
789command script import /path/to/zig/tools/lldb_pretty_printers.py790command script import /path/to/zig/lib/lldb/pretty_printers.py
791```
792
793If you will be debugging a Zig compiler built using Zig's self-hosted backends,
794you will also want this line:
795
796```
797type category enable zig.compiler
790```798```
791799
792If you will be using Zig's LLVM backend (again, not recommended with the LLDB800If you will be using Zig's LLVM backend (again, not recommended with the LLDB
...@@ -797,10 +805,9 @@ type category enable zig.lang...@@ -797,10 +805,9 @@ type category enable zig.lang
797type category enable zig.std805type category enable zig.std
798```806```
799807
800If you will be debugging a Zig compiler built using Zig's LLVM backend (again,808If you will be debugging a Zig compiler built using Zig's LLVM backend without
801not recommended with the LLDB fork), you will also want this line:809using the LLDB fork, you will also want this line:
802810
803```811```
804type category enable zig.stage2812type category enable zig
805```813```
806
ci/x86_64-linux-debug-llvm.sh+1-1
...@@ -53,7 +53,7 @@ stage3-debug/bin/zig build \...@@ -53,7 +53,7 @@ stage3-debug/bin/zig build \
5353
54stage3-debug/bin/zig build test docs \54stage3-debug/bin/zig build test docs \
55 --maxrss ${ZSF_MAX_RSS:-0} \55 --maxrss ${ZSF_MAX_RSS:-0} \
56 -Dlldb=$HOME/deps/lldb-zig/Debug-7c1090fd46/bin/lldb \56 -Dlldb=$HOME/deps/lldb-zig/Debug-aad646607a/bin/lldb \
57 -Dlibc-test-path=$HOME/deps/libc-test-b95fe84 \57 -Dlibc-test-path=$HOME/deps/libc-test-b95fe84 \
58 -fqemu \58 -fqemu \
59 --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \59 --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \
ci/x86_64-linux-debug.sh+1-1
...@@ -53,7 +53,7 @@ stage3-debug/bin/zig build \...@@ -53,7 +53,7 @@ stage3-debug/bin/zig build \
5353
54stage3-debug/bin/zig build test docs \54stage3-debug/bin/zig build test docs \
55 --maxrss ${ZSF_MAX_RSS:-0} \55 --maxrss ${ZSF_MAX_RSS:-0} \
56 -Dlldb=$HOME/deps/lldb-zig/Debug-7c1090fd46/bin/lldb \56 -Dlldb=$HOME/deps/lldb-zig/Debug-aad646607a/bin/lldb \
57 -fqemu \57 -fqemu \
58 --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \58 --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \
59 -fwasmtime \59 -fwasmtime \
ci/x86_64-linux-release.sh+1-1
...@@ -61,7 +61,7 @@ stage3-release/bin/zig build \...@@ -61,7 +61,7 @@ stage3-release/bin/zig build \
6161
62stage3-release/bin/zig build test docs \62stage3-release/bin/zig build test docs \
63 --maxrss ${ZSF_MAX_RSS:-0} \63 --maxrss ${ZSF_MAX_RSS:-0} \
64 -Dlldb=$HOME/deps/lldb-zig/Release-7c1090fd46/bin/lldb \64 -Dlldb=$HOME/deps/lldb-zig/Release-aad646607a/bin/lldb \
65 -Dlibc-test-path=$HOME/deps/libc-test-b95fe84 \65 -Dlibc-test-path=$HOME/deps/libc-test-b95fe84 \
66 -fqemu \66 -fqemu \
67 --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \67 --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \
lib/std/Io/Writer.zig+4-7
...@@ -487,7 +487,7 @@ pub fn writableSliceGreedyPreserve(w: *Writer, preserve: usize, minimum_len: usi...@@ -487,7 +487,7 @@ pub fn writableSliceGreedyPreserve(w: *Writer, preserve: usize, minimum_len: usi
487 @branchHint(.likely);487 @branchHint(.likely);
488 return w.buffer[w.end..];488 return w.buffer[w.end..];
489 }489 }
490 try rebase(w, preserve, minimum_len);490 try w.vtable.rebase(w, preserve, minimum_len);
491 assert(w.buffer.len >= preserve + minimum_len);491 assert(w.buffer.len >= preserve + minimum_len);
492 return w.buffer[w.end..];492 return w.buffer[w.end..];
493}493}
...@@ -845,13 +845,10 @@ pub fn writeByte(w: *Writer, byte: u8) Error!void {...@@ -845,13 +845,10 @@ pub fn writeByte(w: *Writer, byte: u8) Error!void {
845///845///
846/// Asserts buffer capacity is at least `preserve`.846/// Asserts buffer capacity is at least `preserve`.
847pub fn writeBytePreserve(w: *Writer, preserve: usize, byte: u8) Error!void {847pub fn writeBytePreserve(w: *Writer, preserve: usize, byte: u8) Error!void {
848 if (w.buffer.len - w.end != 0) {848 if (w.buffer.len - w.end == 0) {
849 @branchHint(.likely);849 @branchHint(.unlikely);
850 w.buffer[w.end] = byte;850 try w.vtable.rebase(w, preserve -| 1, 1);
851 w.end += 1;
852 return;
853 }851 }
854 try w.vtable.rebase(w, preserve -| 1, 1);
855 w.buffer[w.end] = byte;852 w.buffer[w.end] = byte;
856 w.end += 1;853 w.end += 1;
857}854}
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);
lib/std/debug/Dwarf/Unwind.zig+16-7
...@@ -362,8 +362,7 @@ pub const CommonInformationEntry = struct {...@@ -362,8 +362,7 @@ pub const CommonInformationEntry = struct {
362 if (aug_str.len == 0) break :aug .none;362 if (aug_str.len == 0) break :aug .none;
363 if (aug_str[0] == 'z') break :aug .lsb_z;363 if (aug_str[0] == 'z') break :aug .lsb_z;
364 if (std.mem.eql(u8, aug_str, "eh")) break :aug .gcc_eh;364 if (std.mem.eql(u8, aug_str, "eh")) break :aug .gcc_eh;
365 // We can't finish parsing the CIE if we don't know what its augmentation means.365 return error.UnsupportedAugmentation;
366 return bad();
367 };366 };
368367
369 switch (aug_kind) {368 switch (aug_kind) {
...@@ -396,7 +395,7 @@ pub const CommonInformationEntry = struct {...@@ -396,7 +395,7 @@ pub const CommonInformationEntry = struct {
396 'R' => fde_pointer_enc = @bitCast(try aug_data.takeByte()),395 'R' => fde_pointer_enc = @bitCast(try aug_data.takeByte()),
397 'S' => is_signal_frame = true,396 'S' => is_signal_frame = true,
398 'B', 'G' => {},397 'B', 'G' => {},
399 else => return bad(),398 else => return error.UnsupportedAugmentation,
400 };399 };
401 break :aug .{ fde_pointer_enc, is_signal_frame };400 break :aug .{ fde_pointer_enc, is_signal_frame };
402 };401 };
...@@ -502,7 +501,15 @@ pub fn prepare(...@@ -502,7 +501,15 @@ pub fn prepare(
502 const idx = unwind.cie_list.len;501 const idx = unwind.cie_list.len;
503 try unwind.cie_list.append(gpa, .{502 try unwind.cie_list.append(gpa, .{
504 .offset = entry_offset,503 .offset = entry_offset,
505 .cie = try .parse(cie_info.format, try r.take(bytes_len), section.id, addr_size_bytes),504 .cie = CommonInformationEntry.parse(cie_info.format, try r.take(bytes_len), section.id, addr_size_bytes) catch |err| switch (err) {
505 error.UnsupportedDwarfVersion,
506 error.UnsupportedAugmentation,
507 => {
508 // These are recoverable by just skipping the CIE.
509 continue;
510 },
511 else => |e| return e,
512 },
506 });513 });
507 errdefer _ = unwind.cie_list.pop().?;514 errdefer _ = unwind.cie_list.pop().?;
508 try VirtualMachine.populateCieLastRow(gpa, &unwind.cie_list.items(.cie)[idx], addr_size_bytes, endian);515 try VirtualMachine.populateCieLastRow(gpa, &unwind.cie_list.items(.cie)[idx], addr_size_bytes, endian);
...@@ -514,8 +521,10 @@ pub fn prepare(...@@ -514,8 +521,10 @@ pub fn prepare(
514 try r.discardAll(bytes_len);521 try r.discardAll(bytes_len);
515 continue;522 continue;
516 }523 }
517 const cie = unwind.findCie(fde_info.cie_offset) orelse return error.InvalidDebugInfo;524 const fde_vaddr = section.vaddr + r.seek;
518 const fde: FrameDescriptionEntry = try .parse(section.vaddr + r.seek, try r.take(bytes_len), cie, endian);525 const fde_bytes = try r.take(bytes_len);
526 const cie = unwind.findCie(fde_info.cie_offset) orelse continue;
527 const fde: FrameDescriptionEntry = try .parse(fde_vaddr, fde_bytes, cie, endian);
519 try fde_list.append(gpa, .{528 try fde_list.append(gpa, .{
520 .pc_begin = fde.pc_begin,529 .pc_begin = fde.pc_begin,
521 .fde_offset = entry_offset,530 .fde_offset = entry_offset,
...@@ -612,7 +621,7 @@ pub fn getFde(unwind: *const Unwind, fde_offset: u64, endian: Endian) !struct {...@@ -612,7 +621,7 @@ pub fn getFde(unwind: *const Unwind, fde_offset: u64, endian: Endian) !struct {
612 .cie, .terminator => return bad(), // This is meant to be an FDE621 .cie, .terminator => return bad(), // This is meant to be an FDE
613 };622 };
614623
615 const cie = unwind.findCie(fde_info.cie_offset) orelse return error.InvalidDebugInfo;624 const cie = unwind.findCie(fde_info.cie_offset) orelse return bad();
616 const fde: FrameDescriptionEntry = try .parse(625 const fde: FrameDescriptionEntry = try .parse(
617 section.vaddr + fde_offset + fde_reader.seek,626 section.vaddr + fde_offset + fde_reader.seek,
618 try fde_reader.take(cast(usize, fde_info.bytes_len) orelse return error.EndOfStream),627 try fde_reader.take(cast(usize, fde_info.bytes_len) orelse return error.EndOfStream),
lib/std/debug/SelfInfo/Elf.zig-1
...@@ -340,7 +340,6 @@ const Module = struct {...@@ -340,7 +340,6 @@ const Module = struct {
340 error.InvalidOperation,340 error.InvalidOperation,
341 => return error.InvalidDebugInfo,341 => return error.InvalidDebugInfo,
342 error.UnsupportedAddrSize,342 error.UnsupportedAddrSize,
343 error.UnsupportedDwarfVersion,
344 error.UnimplementedUserOpcode,343 error.UnimplementedUserOpcode,
345 => return error.UnsupportedDebugInfo,344 => return error.UnsupportedDebugInfo,
346 };345 };
lib/std/debug/SelfInfo/MachO.zig-1
...@@ -578,7 +578,6 @@ const Module = struct {...@@ -578,7 +578,6 @@ const Module = struct {
578 error.InvalidOperation,578 error.InvalidOperation,
579 => return error.InvalidDebugInfo,579 => return error.InvalidDebugInfo,
580 error.UnsupportedAddrSize,580 error.UnsupportedAddrSize,
581 error.UnsupportedDwarfVersion,
582 error.UnimplementedUserOpcode,581 error.UnimplementedUserOpcode,
583 => return error.UnsupportedDebugInfo,582 => return error.UnsupportedDebugInfo,
584 };583 };
lib/std/dwarf/AT.zig+1
...@@ -225,6 +225,7 @@ pub const ZIG_padding = 0x2cce;...@@ -225,6 +225,7 @@ pub const ZIG_padding = 0x2cce;
225pub const ZIG_relative_decl = 0x2cd0;225pub const ZIG_relative_decl = 0x2cd0;
226pub const ZIG_decl_line_relative = 0x2cd1;226pub const ZIG_decl_line_relative = 0x2cd1;
227pub const ZIG_comptime_value = 0x2cd2;227pub const ZIG_comptime_value = 0x2cd2;
228pub const ZIG_call_line_relative = 0x2cd3;
228pub const ZIG_sentinel = 0x2ce2;229pub const ZIG_sentinel = 0x2ce2;
229230
230// UPC extension.231// UPC extension.
lib/std/dwarf/TAG.zig+3-2
...@@ -40,8 +40,8 @@ pub const namelist = 0x2b;...@@ -40,8 +40,8 @@ pub const namelist = 0x2b;
40pub const namelist_item = 0x2c;40pub const namelist_item = 0x2c;
41pub const packed_type = 0x2d;41pub const packed_type = 0x2d;
42pub const subprogram = 0x2e;42pub const subprogram = 0x2e;
43pub const template_type_param = 0x2f;43pub const template_type_parameter = 0x2f;
44pub const template_value_param = 0x30;44pub const template_value_parameter = 0x30;
45pub const thrown_type = 0x31;45pub const thrown_type = 0x31;
46pub const try_block = 0x32;46pub const try_block = 0x32;
47pub const variant_part = 0x33;47pub const variant_part = 0x33;
...@@ -120,3 +120,4 @@ pub const PGI_interface_block = 0xA020;...@@ -120,3 +120,4 @@ pub const PGI_interface_block = 0xA020;
120// ZIG extensions.120// ZIG extensions.
121pub const ZIG_padding = 0xfdb1;121pub const ZIG_padding = 0xfdb1;
122pub const ZIG_comptime_value = 0xfdb2;122pub const ZIG_comptime_value = 0xfdb2;
123pub const ZIG_lost_declaration = 0xfdb3;
lib/std/zig/AstGen.zig+42-6
...@@ -1884,7 +1884,8 @@ fn structInitExprAnon(...@@ -1884,7 +1884,8 @@ fn structInitExprAnon(
18841884
1885 const payload_index = try addExtra(astgen, Zir.Inst.StructInitAnon{1885 const payload_index = try addExtra(astgen, Zir.Inst.StructInitAnon{
1886 .abs_node = node,1886 .abs_node = node,
1887 .abs_line = astgen.source_line,1887 .src_line = astgen.source_line,
1888 .src_column = astgen.source_column,
1888 .fields_len = @intCast(struct_init.ast.fields.len),1889 .fields_len = @intCast(struct_init.ast.fields.len),
1889 });1890 });
1890 const field_size = @typeInfo(Zir.Inst.StructInitAnon.Item).@"struct".field_names.len;1891 const field_size = @typeInfo(Zir.Inst.StructInitAnon.Item).@"struct".field_names.len;
...@@ -1917,7 +1918,8 @@ fn structInitExprTyped(...@@ -1917,7 +1918,8 @@ fn structInitExprTyped(
19171918
1918 const payload_index = try addExtra(astgen, Zir.Inst.StructInit{1919 const payload_index = try addExtra(astgen, Zir.Inst.StructInit{
1919 .abs_node = node,1920 .abs_node = node,
1920 .abs_line = astgen.source_line,1921 .src_line = astgen.source_line,
1922 .src_column = astgen.source_column,
1921 .fields_len = @intCast(struct_init.ast.fields.len),1923 .fields_len = @intCast(struct_init.ast.fields.len),
1922 });1924 });
1923 const field_size = @typeInfo(Zir.Inst.StructInit.Item).@"struct".field_names.len;1925 const field_size = @typeInfo(Zir.Inst.StructInit.Item).@"struct".field_names.len;
...@@ -4846,9 +4848,13 @@ fn structDeclInner(...@@ -4846,9 +4848,13 @@ fn structDeclInner(
4846 astgen.advanceSourceCursorToNode(node);4848 astgen.advanceSourceCursorToNode(node);
48474849
4848 const decl_inst = try gz.reserveInstructionIndex();4850 const decl_inst = try gz.reserveInstructionIndex();
4851 const src_line = astgen.source_line;
4852 const src_column = astgen.source_column;
48494853
4850 if (container_decl.ast.members.len == 0 and maybe_backing_int_node == .none) {4854 if (container_decl.ast.members.len == 0 and maybe_backing_int_node == .none) {
4851 try gz.setStruct(decl_inst, .{4855 try gz.setStruct(decl_inst, .{
4856 .src_line = src_line,
4857 .src_column = src_column,
4852 .src_node = node,4858 .src_node = node,
4853 .name_strat = name_strat,4859 .name_strat = name_strat,
4854 .layout = layout,4860 .layout = layout,
...@@ -5003,6 +5009,8 @@ fn structDeclInner(...@@ -5003,6 +5009,8 @@ fn structDeclInner(
5003 astgen.src_hasher.final(&fields_hash);5009 astgen.src_hasher.final(&fields_hash);
50045010
5005 try gz.setStruct(decl_inst, .{5011 try gz.setStruct(decl_inst, .{
5012 .src_line = src_line,
5013 .src_column = src_column,
5006 .src_node = node,5014 .src_node = node,
5007 .name_strat = name_strat,5015 .name_strat = name_strat,
5008 .layout = layout,5016 .layout = layout,
...@@ -5151,6 +5159,8 @@ fn unionDeclInner(...@@ -5151,6 +5159,8 @@ fn unionDeclInner(
5151 astgen.advanceSourceCursorToNode(node);5159 astgen.advanceSourceCursorToNode(node);
51525160
5153 const decl_inst = try gz.reserveInstructionIndex();5161 const decl_inst = try gz.reserveInstructionIndex();
5162 const src_line = astgen.source_line;
5163 const src_column = astgen.source_column;
51545164
5155 var namespace: Scope.Namespace = .{5165 var namespace: Scope.Namespace = .{
5156 .parent = scope,5166 .parent = scope,
...@@ -5284,6 +5294,8 @@ fn unionDeclInner(...@@ -5284,6 +5294,8 @@ fn unionDeclInner(
5284 astgen.src_hasher.final(&fields_hash);5294 astgen.src_hasher.final(&fields_hash);
52855295
5286 try gz.setUnion(decl_inst, .{5296 try gz.setUnion(decl_inst, .{
5297 .src_line = src_line,
5298 .src_column = src_column,
5287 .src_node = node,5299 .src_node = node,
5288 .name_strat = name_strat,5300 .name_strat = name_strat,
5289 .kind = switch (layout) {5301 .kind = switch (layout) {
...@@ -5358,6 +5370,8 @@ fn containerDecl(...@@ -5358,6 +5370,8 @@ fn containerDecl(
5358 astgen.advanceSourceCursorToNode(node);5370 astgen.advanceSourceCursorToNode(node);
53595371
5360 const decl_inst = try gz.reserveInstructionIndex();5372 const decl_inst = try gz.reserveInstructionIndex();
5373 const src_line = astgen.source_line;
5374 const src_column = astgen.source_column;
53615375
5362 var namespace: Scope.Namespace = .{5376 var namespace: Scope.Namespace = .{
5363 .parent = scope,5377 .parent = scope,
...@@ -5482,6 +5496,8 @@ fn containerDecl(...@@ -5482,6 +5496,8 @@ fn containerDecl(
5482 astgen.src_hasher.final(&fields_hash);5496 astgen.src_hasher.final(&fields_hash);
54835497
5484 try gz.setEnum(decl_inst, .{5498 try gz.setEnum(decl_inst, .{
5499 .src_line = src_line,
5500 .src_column = src_column,
5485 .src_node = node,5501 .src_node = node,
5486 .name_strat = name_strat,5502 .name_strat = name_strat,
5487 .tag_type_body_len = tag_type_body_len,5503 .tag_type_body_len = tag_type_body_len,
...@@ -5504,6 +5520,8 @@ fn containerDecl(...@@ -5504,6 +5520,8 @@ fn containerDecl(
5504 astgen.advanceSourceCursorToNode(node);5520 astgen.advanceSourceCursorToNode(node);
55055521
5506 const decl_inst = try gz.reserveInstructionIndex();5522 const decl_inst = try gz.reserveInstructionIndex();
5523 const src_line = astgen.source_line;
5524 const src_column = astgen.source_column;
55075525
5508 var namespace: Scope.Namespace = .{5526 var namespace: Scope.Namespace = .{
5509 .parent = scope,5527 .parent = scope,
...@@ -5545,6 +5563,8 @@ fn containerDecl(...@@ -5545,6 +5563,8 @@ fn containerDecl(
5545 wip_decls.finish();5563 wip_decls.finish();
55465564
5547 try gz.setOpaque(decl_inst, .{5565 try gz.setOpaque(decl_inst, .{
5566 .src_line = src_line,
5567 .src_column = src_column,
5548 .src_node = node,5568 .src_node = node,
5549 .name_strat = name_strat,5569 .name_strat = name_strat,
5550 .decls_len = scan_result.decls_len,5570 .decls_len = scan_result.decls_len,
...@@ -9302,6 +9322,7 @@ fn builtinCall(...@@ -9302,6 +9322,7 @@ fn builtinCall(
9302 const field_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_attrs_ty } }, params[4], .struct_field_attrs);9322 const field_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_attrs_ty } }, params[4], .struct_field_attrs);
9303 const result = try gz.addExtendedPayloadSmall(.reify_struct, @backingInt(reify_name_strat), Zir.Inst.ReifyStruct{9323 const result = try gz.addExtendedPayloadSmall(.reify_struct, @backingInt(reify_name_strat), Zir.Inst.ReifyStruct{
9304 .src_line = gz.astgen.source_line,9324 .src_line = gz.astgen.source_line,
9325 .src_column = gz.astgen.source_column,
9305 .node = node,9326 .node = node,
9306 .layout = layout,9327 .layout = layout,
9307 .backing_ty = backing_ty,9328 .backing_ty = backing_ty,
...@@ -9330,6 +9351,7 @@ fn builtinCall(...@@ -9330,6 +9351,7 @@ fn builtinCall(
9330 const field_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_attrs_ty } }, params[4], .union_field_attrs);9351 const field_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_attrs_ty } }, params[4], .union_field_attrs);
9331 const result = try gz.addExtendedPayloadSmall(.reify_union, @backingInt(reify_name_strat), Zir.Inst.ReifyUnion{9352 const result = try gz.addExtendedPayloadSmall(.reify_union, @backingInt(reify_name_strat), Zir.Inst.ReifyUnion{
9332 .src_line = gz.astgen.source_line,9353 .src_line = gz.astgen.source_line,
9354 .src_column = gz.astgen.source_column,
9333 .node = node,9355 .node = node,
9334 .layout = layout,9356 .layout = layout,
9335 .arg_ty = arg_ty,9357 .arg_ty = arg_ty,
...@@ -9352,6 +9374,7 @@ fn builtinCall(...@@ -9352,6 +9374,7 @@ fn builtinCall(
9352 const field_values = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_values_ty } }, params[3], .enum_field_values);9374 const field_values = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_values_ty } }, params[3], .enum_field_values);
9353 const result = try gz.addExtendedPayloadSmall(.reify_enum, @backingInt(reify_name_strat), Zir.Inst.ReifyEnum{9375 const result = try gz.addExtendedPayloadSmall(.reify_enum, @backingInt(reify_name_strat), Zir.Inst.ReifyEnum{
9354 .src_line = gz.astgen.source_line,9376 .src_line = gz.astgen.source_line,
9377 .src_column = gz.astgen.source_column,
9355 .node = node,9378 .node = node,
9356 .tag_ty = tag_ty,9379 .tag_ty = tag_ty,
9357 .mode = mode,9380 .mode = mode,
...@@ -9365,6 +9388,7 @@ fn builtinCall(...@@ -9365,6 +9388,7 @@ fn builtinCall(
9365 const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = spirv_type_options_ty } }, params[0], .type);9388 const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = spirv_type_options_ty } }, params[0], .type);
9366 const result = try gz.addExtendedPayload(.reify_spirv_type, Zir.Inst.ReifySpirvType{9389 const result = try gz.addExtendedPayload(.reify_spirv_type, Zir.Inst.ReifySpirvType{
9367 .src_line = gz.astgen.source_line,9390 .src_line = gz.astgen.source_line,
9391 .src_column = gz.astgen.source_column,
9368 .node = node,9392 .node = node,
9369 .operand = operand,9393 .operand = operand,
9370 });9394 });
...@@ -12392,6 +12416,8 @@ const GenZir = struct {...@@ -12392,6 +12416,8 @@ const GenZir = struct {
12392 }12416 }
1239312417
12394 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {12418 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
12419 src_line: u32,
12420 src_column: u32,
12395 src_node: Ast.Node.Index,12421 src_node: Ast.Node.Index,
12396 name_strat: Zir.Inst.NameStrategy,12422 name_strat: Zir.Inst.NameStrategy,
12397 layout: std.lang.Type.ContainerLayout,12423 layout: std.lang.Type.ContainerLayout,
...@@ -12428,7 +12454,8 @@ const GenZir = struct {...@@ -12428,7 +12454,8 @@ const GenZir = struct {
12428 .fields_hash_1 = fields_hash_arr[1],12454 .fields_hash_1 = fields_hash_arr[1],
12429 .fields_hash_2 = fields_hash_arr[2],12455 .fields_hash_2 = fields_hash_arr[2],
12430 .fields_hash_3 = fields_hash_arr[3],12456 .fields_hash_3 = fields_hash_arr[3],
12431 .src_line = astgen.source_line,12457 .src_line = args.src_line,
12458 .src_column = args.src_column,
12432 .src_node = args.src_node,12459 .src_node = args.src_node,
12433 });12460 });
1243412461
...@@ -12461,6 +12488,8 @@ const GenZir = struct {...@@ -12461,6 +12488,8 @@ const GenZir = struct {
12461 }12488 }
1246212489
12463 fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct {12490 fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
12491 src_line: u32,
12492 src_column: u32,
12464 src_node: Ast.Node.Index,12493 src_node: Ast.Node.Index,
12465 name_strat: Zir.Inst.NameStrategy,12494 name_strat: Zir.Inst.NameStrategy,
12466 kind: Zir.Inst.UnionDecl.Kind,12495 kind: Zir.Inst.UnionDecl.Kind,
...@@ -12495,7 +12524,8 @@ const GenZir = struct {...@@ -12495,7 +12524,8 @@ const GenZir = struct {
12495 .fields_hash_1 = fields_hash_arr[1],12524 .fields_hash_1 = fields_hash_arr[1],
12496 .fields_hash_2 = fields_hash_arr[2],12525 .fields_hash_2 = fields_hash_arr[2],
12497 .fields_hash_3 = fields_hash_arr[3],12526 .fields_hash_3 = fields_hash_arr[3],
12498 .src_line = astgen.source_line,12527 .src_line = args.src_line,
12528 .src_column = args.src_column,
12499 .src_node = args.src_node,12529 .src_node = args.src_node,
12500 });12530 });
1250112531
...@@ -12530,6 +12560,8 @@ const GenZir = struct {...@@ -12530,6 +12560,8 @@ const GenZir = struct {
12530 }12560 }
1253112561
12532 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {12562 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
12563 src_line: u32,
12564 src_column: u32,
12533 src_node: Ast.Node.Index,12565 src_node: Ast.Node.Index,
12534 name_strat: Zir.Inst.NameStrategy,12566 name_strat: Zir.Inst.NameStrategy,
12535 tag_type_body_len: ?u32,12567 tag_type_body_len: ?u32,
...@@ -12563,7 +12595,8 @@ const GenZir = struct {...@@ -12563,7 +12595,8 @@ const GenZir = struct {
12563 .fields_hash_1 = fields_hash_arr[1],12595 .fields_hash_1 = fields_hash_arr[1],
12564 .fields_hash_2 = fields_hash_arr[2],12596 .fields_hash_2 = fields_hash_arr[2],
12565 .fields_hash_3 = fields_hash_arr[3],12597 .fields_hash_3 = fields_hash_arr[3],
12566 .src_line = astgen.source_line,12598 .src_line = args.src_line,
12599 .src_column = args.src_column,
12567 .src_node = args.src_node,12600 .src_node = args.src_node,
12568 });12601 });
1256912602
...@@ -12594,6 +12627,8 @@ const GenZir = struct {...@@ -12594,6 +12627,8 @@ const GenZir = struct {
12594 }12627 }
1259512628
12596 fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct {12629 fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
12630 src_line: u32,
12631 src_column: u32,
12597 src_node: Ast.Node.Index,12632 src_node: Ast.Node.Index,
12598 name_strat: Zir.Inst.NameStrategy,12633 name_strat: Zir.Inst.NameStrategy,
12599 decls_len: u32,12634 decls_len: u32,
...@@ -12615,7 +12650,8 @@ const GenZir = struct {...@@ -12615,7 +12650,8 @@ const GenZir = struct {
12615 args.decls.len);12650 args.decls.len);
1261612651
12617 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{12652 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{
12618 .src_line = astgen.source_line,12653 .src_line = args.src_line,
12654 .src_column = args.src_column,
12619 .src_node = args.src_node,12655 .src_node = args.src_node,
12620 });12656 });
12621 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);12657 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
lib/std/zig/Zir.zig+20-4
...@@ -3277,6 +3277,7 @@ pub const Inst = struct {...@@ -3277,6 +3277,7 @@ pub const Inst = struct {
32773277
3278 pub const ReifyStruct = struct {3278 pub const ReifyStruct = struct {
3279 src_line: u32,3279 src_line: u32,
3280 src_column: u32,
3280 /// This node is absolute, because `reify` instructions are tracked across updates, and3281 /// This node is absolute, because `reify` instructions are tracked across updates, and
3281 /// this simplifies the logic for getting source locations for types.3282 /// this simplifies the logic for getting source locations for types.
3282 node: Ast.Node.Index,3283 node: Ast.Node.Index,
...@@ -3289,6 +3290,7 @@ pub const Inst = struct {...@@ -3289,6 +3290,7 @@ pub const Inst = struct {
32893290
3290 pub const ReifyUnion = struct {3291 pub const ReifyUnion = struct {
3291 src_line: u32,3292 src_line: u32,
3293 src_column: u32,
3292 /// This node is absolute, because `reify` instructions are tracked across updates, and3294 /// This node is absolute, because `reify` instructions are tracked across updates, and
3293 /// this simplifies the logic for getting source locations for types.3295 /// this simplifies the logic for getting source locations for types.
3294 node: Ast.Node.Index,3296 node: Ast.Node.Index,
...@@ -3301,6 +3303,7 @@ pub const Inst = struct {...@@ -3301,6 +3303,7 @@ pub const Inst = struct {
33013303
3302 pub const ReifyEnum = struct {3304 pub const ReifyEnum = struct {
3303 src_line: u32,3305 src_line: u32,
3306 src_column: u32,
3304 /// This node is absolute, because `reify` instructions are tracked across updates, and3307 /// This node is absolute, because `reify` instructions are tracked across updates, and
3305 /// this simplifies the logic for getting source locations for types.3308 /// this simplifies the logic for getting source locations for types.
3306 node: Ast.Node.Index,3309 node: Ast.Node.Index,
...@@ -3312,6 +3315,7 @@ pub const Inst = struct {...@@ -3312,6 +3315,7 @@ pub const Inst = struct {
33123315
3313 pub const ReifySpirvType = struct {3316 pub const ReifySpirvType = struct {
3314 src_line: u32,3317 src_line: u32,
3318 src_column: u32,
3315 /// This node is absolute, because `reify` instructions are tracked across updates, and3319 /// This node is absolute, because `reify` instructions are tracked across updates, and
3316 /// this simplifies the logic for getting source locations for types.3320 /// this simplifies the logic for getting source locations for types.
3317 node: Ast.Node.Index,3321 node: Ast.Node.Index,
...@@ -3509,6 +3513,7 @@ pub const Inst = struct {...@@ -3509,6 +3513,7 @@ pub const Inst = struct {
3509 fields_hash_2: u32,3513 fields_hash_2: u32,
3510 fields_hash_3: u32,3514 fields_hash_3: u32,
3511 src_line: u32,3515 src_line: u32,
3516 src_column: u32,
3512 /// This node provides a new absolute baseline node for all instructions within this struct.3517 /// This node provides a new absolute baseline node for all instructions within this struct.
3513 src_node: Ast.Node.Index,3518 src_node: Ast.Node.Index,
35143519
...@@ -3664,6 +3669,7 @@ pub const Inst = struct {...@@ -3664,6 +3669,7 @@ pub const Inst = struct {
3664 fields_hash_2: u32,3669 fields_hash_2: u32,
3665 fields_hash_3: u32,3670 fields_hash_3: u32,
3666 src_line: u32,3671 src_line: u32,
3672 src_column: u32,
3667 /// This node provides a new absolute baseline node for all instructions within this struct.3673 /// This node provides a new absolute baseline node for all instructions within this struct.
3668 src_node: Ast.Node.Index,3674 src_node: Ast.Node.Index,
36693675
...@@ -3701,6 +3707,7 @@ pub const Inst = struct {...@@ -3701,6 +3707,7 @@ pub const Inst = struct {
3701 fields_hash_2: u32,3707 fields_hash_2: u32,
3702 fields_hash_3: u32,3708 fields_hash_3: u32,
3703 src_line: u32,3709 src_line: u32,
3710 src_column: u32,
3704 /// This node provides a new absolute baseline node for all instructions within this struct.3711 /// This node provides a new absolute baseline node for all instructions within this struct.
3705 src_node: Ast.Node.Index,3712 src_node: Ast.Node.Index,
37063713
...@@ -3756,6 +3763,7 @@ pub const Inst = struct {...@@ -3756,6 +3763,7 @@ pub const Inst = struct {
3756 /// 4. decl: Index, // for every decls_len; points to a `declaration` instruction3763 /// 4. decl: Index, // for every decls_len; points to a `declaration` instruction
3757 pub const OpaqueDecl = struct {3764 pub const OpaqueDecl = struct {
3758 src_line: u32,3765 src_line: u32,
3766 src_column: u32,
3759 /// This node provides a new absolute baseline node for all instructions within this struct.3767 /// This node provides a new absolute baseline node for all instructions within this struct.
3760 src_node: Ast.Node.Index,3768 src_node: Ast.Node.Index,
37613769
...@@ -3803,8 +3811,8 @@ pub const Inst = struct {...@@ -3803,8 +3811,8 @@ pub const Inst = struct {
3803 /// If this is an anonymous initialization (the operand is poison), this instruction becomes the owner of a type.3811 /// If this is an anonymous initialization (the operand is poison), this instruction becomes the owner of a type.
3804 /// To resolve source locations, we need an absolute source node.3812 /// To resolve source locations, we need an absolute source node.
3805 abs_node: Ast.Node.Index,3813 abs_node: Ast.Node.Index,
3806 /// Likewise, we need an absolute line number.3814 src_line: u32,
3807 abs_line: u32,3815 src_column: u32,
3808 fields_len: u32,3816 fields_len: u32,
38093817
3810 pub const Item = struct {3818 pub const Item = struct {
...@@ -3823,8 +3831,8 @@ pub const Inst = struct {...@@ -3823,8 +3831,8 @@ pub const Inst = struct {
3823 /// This is an anonymous initialization, meaning this instruction becomes the owner of a type.3831 /// This is an anonymous initialization, meaning this instruction becomes the owner of a type.
3824 /// To resolve source locations, we need an absolute source node.3832 /// To resolve source locations, we need an absolute source node.
3825 abs_node: Ast.Node.Index,3833 abs_node: Ast.Node.Index,
3826 /// Likewise, we need an absolute line number.3834 src_line: u32,
3827 abs_line: u32,3835 src_column: u32,
3828 fields_len: u32,3836 fields_len: u32,
38293837
3830 pub const Item = struct {3838 pub const Item = struct {
...@@ -5318,6 +5326,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe...@@ -5318,6 +5326,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe
5318 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);5326 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
5319 return .{5327 return .{
5320 .src_line = extra.data.src_line,5328 .src_line = extra.data.src_line,
5329 .src_column = extra.data.src_column,
5321 .src_node = extra.data.src_node,5330 .src_node = extra.data.src_node,
5322 .name_strategy = small.name_strategy,5331 .name_strategy = small.name_strategy,
5323 .captures = captures,5332 .captures = captures,
...@@ -5335,6 +5344,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe...@@ -5335,6 +5344,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe
5335}5344}
5336pub const UnwrappedStructDecl = struct {5345pub const UnwrappedStructDecl = struct {
5337 src_line: u32,5346 src_line: u32,
5347 src_column: u32,
5338 src_node: Ast.Node.Index,5348 src_node: Ast.Node.Index,
5339 name_strategy: Inst.NameStrategy,5349 name_strategy: Inst.NameStrategy,
53405350
...@@ -5463,6 +5473,7 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl...@@ -5463,6 +5473,7 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl
5463 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);5473 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
5464 return .{5474 return .{
5465 .src_line = extra.data.src_line,5475 .src_line = extra.data.src_line,
5476 .src_column = extra.data.src_column,
5466 .src_node = extra.data.src_node,5477 .src_node = extra.data.src_node,
5467 .name_strategy = small.name_strategy,5478 .name_strategy = small.name_strategy,
5468 .captures = captures,5479 .captures = captures,
...@@ -5479,6 +5490,7 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl...@@ -5479,6 +5490,7 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl
5479}5490}
5480pub const UnwrappedUnionDecl = struct {5491pub const UnwrappedUnionDecl = struct {
5481 src_line: u32,5492 src_line: u32,
5493 src_column: u32,
5482 src_node: Ast.Node.Index,5494 src_node: Ast.Node.Index,
5483 name_strategy: Inst.NameStrategy,5495 name_strategy: Inst.NameStrategy,
54845496
...@@ -5590,6 +5602,7 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {...@@ -5590,6 +5602,7 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {
5590 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);5602 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
5591 return .{5603 return .{
5592 .src_line = extra.data.src_line,5604 .src_line = extra.data.src_line,
5605 .src_column = extra.data.src_column,
5593 .src_node = extra.data.src_node,5606 .src_node = extra.data.src_node,
5594 .name_strategy = small.name_strategy,5607 .name_strategy = small.name_strategy,
5595 .captures = captures,5608 .captures = captures,
...@@ -5604,6 +5617,7 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {...@@ -5604,6 +5617,7 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {
5604}5617}
5605pub const UnwrappedEnumDecl = struct {5618pub const UnwrappedEnumDecl = struct {
5606 src_line: u32,5619 src_line: u32,
5620 src_column: u32,
5607 src_node: Ast.Node.Index,5621 src_node: Ast.Node.Index,
5608 name_strategy: Inst.NameStrategy,5622 name_strategy: Inst.NameStrategy,
56095623
...@@ -5682,6 +5696,7 @@ pub fn getOpaqueDecl(zir: *const Zir, opaque_decl: Inst.Index) UnwrappedOpaqueDe...@@ -5682,6 +5696,7 @@ pub fn getOpaqueDecl(zir: *const Zir, opaque_decl: Inst.Index) UnwrappedOpaqueDe
5682 extra_index += decls_len;5696 extra_index += decls_len;
5683 return .{5697 return .{
5684 .src_line = extra.data.src_line,5698 .src_line = extra.data.src_line,
5699 .src_column = extra.data.src_column,
5685 .src_node = extra.data.src_node,5700 .src_node = extra.data.src_node,
5686 .name_strategy = small.name_strategy,5701 .name_strategy = small.name_strategy,
5687 .captures = captures,5702 .captures = captures,
...@@ -5691,6 +5706,7 @@ pub fn getOpaqueDecl(zir: *const Zir, opaque_decl: Inst.Index) UnwrappedOpaqueDe...@@ -5691,6 +5706,7 @@ pub fn getOpaqueDecl(zir: *const Zir, opaque_decl: Inst.Index) UnwrappedOpaqueDe
5691}5706}
5692pub const UnwrappedOpaqueDecl = struct {5707pub const UnwrappedOpaqueDecl = struct {
5693 src_line: u32,5708 src_line: u32,
5709 src_column: u32,
5694 src_node: Ast.Node.Index,5710 src_node: Ast.Node.Index,
5695 name_strategy: Inst.NameStrategy,5711 name_strategy: Inst.NameStrategy,
5696 captures: []const Inst.Capture,5712 captures: []const Inst.Capture,
lib/std/zig/llvm/Builder.zig+1-2
...@@ -3461,8 +3461,7 @@ pub const Global = struct {...@@ -3461,8 +3461,7 @@ pub const Global = struct {
3461 const old_name = self.name(builder);3461 const old_name = self.name(builder);
3462 if (new_name == old_name) return;3462 if (new_name == old_name) return;
3463 const index = @backingInt(self.unwrap(builder));3463 const index = @backingInt(self.unwrap(builder));
3464 _ = builder.addGlobalAssumeCapacity(new_name, builder.globals.values()[index]);3464 builder.globals.setKey(index, new_name);
3465 builder.globals.swapRemoveAt(index);
3466 if (!old_name.isAnon()) return;3465 if (!old_name.isAnon()) return;
3467 builder.next_unnamed_global = @fromBackingInt(@backingInt(builder.next_unnamed_global) - 1);3466 builder.next_unnamed_global = @fromBackingInt(@backingInt(builder.next_unnamed_global) - 1);
3468 if (builder.next_unnamed_global == old_name) return;3467 if (builder.next_unnamed_global == old_name) return;
src/Compilation.zig+14-5
...@@ -2101,6 +2101,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2101,6 +2101,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2101 .analysis_roots_buffer = undefined,2101 .analysis_roots_buffer = undefined,
2102 .analysis_roots_len = 0,2102 .analysis_roots_len = 0,
2103 .codegen_task_pool = try .init(arena),2103 .codegen_task_pool = try .init(arena),
2104 .anon_name_counter = 0,
2104 };2105 };
2105 try zcu.init(gpa, io, options.thread_limit);2106 try zcu.init(gpa, io, options.thread_limit);
2106 break :blk zcu;2107 break :blk zcu;
...@@ -2383,6 +2384,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2383,6 +2384,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2383 comp.verbose_llvm_bc != null))2384 comp.verbose_llvm_bc != null))
2384 {2385 {
2385 if (opt_zcu) |zcu| {2386 if (opt_zcu) |zcu| {
2387 dev.check(.llvm_backend);
2386 zcu.llvm_object = try LlvmObject.create(arena, zcu);2388 zcu.llvm_object = try LlvmObject.create(arena, zcu);
2387 }2389 }
2388 }2390 }
...@@ -2829,6 +2831,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2829,6 +2831,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2829 }2831 }
28302832
2831 const is_hit = man.hit(main_progress_node) catch |err| switch (err) {2833 const is_hit = man.hit(main_progress_node) catch |err| switch (err) {
2834 error.Canceled, error.OutOfMemory => |e| return e,
2832 error.CacheCheckFailed => switch (man.diagnostic) {2835 error.CacheCheckFailed => switch (man.diagnostic) {
2833 .none => unreachable,2836 .none => unreachable,
2834 .manifest_create, .manifest_read, .manifest_lock => |e| return comp.setMiscFailure(2837 .manifest_create, .manifest_read, .manifest_lock => |e| return comp.setMiscFailure(
...@@ -2844,7 +2847,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2844,7 +2847,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2844 });2847 });
2845 },2848 },
2846 },2849 },
2847 error.OutOfMemory, error.Canceled => |e| return e,
2848 error.InvalidFormat => return comp.setMiscFailure(2850 error.InvalidFormat => return comp.setMiscFailure(
2849 .check_whole_cache,2851 .check_whole_cache,
2850 "failed to check cache: invalid manifest file format",2852 "failed to check cache: invalid manifest file format",
...@@ -3283,8 +3285,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error...@@ -3283,8 +3285,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
3283 .fuzz = comp.config.any_fuzz,3285 .fuzz = comp.config.any_fuzz,
3284 .lto = comp.config.lto,3286 .lto = comp.config.lto,
3285 }) catch |err| switch (err) {3287 }) catch |err| switch (err) {
3288 error.Canceled, error.OutOfMemory => |e| return e,
3286 error.AlreadyReported => {},3289 error.AlreadyReported => {},
3287 error.OutOfMemory => |e| return e,
3288 };3290 };
32893291
3290 if (zcu_obj_path) |path| {3292 if (zcu_obj_path) |path| {
...@@ -3293,8 +3295,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error...@@ -3293,8 +3295,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
3293 // `link.Queue` has not called `prelink` because it knew we would want to send that3295 // `link.Queue` has not called `prelink` because it knew we would want to send that
3294 // final link input. It is *our* responsibility to call `prelink` now we're done.3296 // final link input. It is *our* responsibility to call `prelink` now we're done.
3295 comp.bin_file.?.prelink() catch |err| switch (err) {3297 comp.bin_file.?.prelink() catch |err| switch (err) {
3298 error.Canceled, error.OutOfMemory => |e| return e,
3296 error.AlreadyReported => return,3299 error.AlreadyReported => return,
3297 else => |e| return e,
3298 };3300 };
3299 }3301 }
3300 }3302 }
...@@ -3308,8 +3310,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error...@@ -3308,8 +3310,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
3308 };3310 };
3309 // This is needed before reading the error flags.3311 // This is needed before reading the error flags.
3310 lf.flush(arena, tid, comp.link_prog_node) catch |err| switch (err) {3312 lf.flush(arena, tid, comp.link_prog_node) catch |err| switch (err) {
3313 error.Canceled, error.OutOfMemory => |e| return e,
3311 error.AlreadyReported => return,3314 error.AlreadyReported => return,
3312 error.OutOfMemory, error.Canceled => |e| return e,
3313 };3315 };
3314 }3316 }
3315}3317}
...@@ -3709,8 +3711,15 @@ pub fn saveState(comp: *Compilation) !void {...@@ -3709,8 +3711,15 @@ pub fn saveState(comp: *Compilation) !void {
37093711
3710 // linker state3712 // linker state
3711 switch (lf.tag) {3713 switch (lf.tag) {
3714 .elf => {},
3715 .elf2 => {
3716 const elf = lf.cast(.elf2).?;
3717 try bufs.ensureUnusedCapacity(3);
3718 addBuf(&bufs, @ptrCast(elf.mf.nodes.items));
3719 addBuf(&bufs, @ptrCast(&elf.mf.free_ni));
3720 addBuf(&bufs, @ptrCast(elf.mf.large.items));
3721 },
3712 .wasm => {3722 .wasm => {
3713 dev.check(link.File.Tag.wasm.devFeature());
3714 const wasm = lf.cast(.wasm).?;3723 const wasm = lf.cast(.wasm).?;
3715 const is_obj = comp.config.output_mode == .Obj;3724 const is_obj = comp.config.output_mode == .Obj;
3716 try bufs.ensureUnusedCapacity(85);3725 try bufs.ensureUnusedCapacity(85);
src/IncrementalDebugServer.zig+3-3
...@@ -243,7 +243,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const...@@ -243,7 +243,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const
243 var num_results: usize = 0;243 var num_results: usize = 0;
244 for (zcu.incremental_debug_state.types.keys()) |type_ip_index| {244 for (zcu.incremental_debug_state.types.keys()) |type_ip_index| {
245 const ty: Type = .fromInterned(type_ip_index);245 const ty: Type = .fromInterned(type_ip_index);
246 const ty_name = ty.containerTypeName(ip).toSlice(ip);246 const ty_name = ty.containerTypeName(ip).fqn.toSlice(ip);
247 const success = switch (@as(u2, @intFromBool(anchor_start)) << 1 | @intFromBool(anchor_end)) {247 const success = switch (@as(u2, @intFromBool(anchor_start)) << 1 | @intFromBool(anchor_end)) {
248 0b00 => std.mem.find(u8, ty_name, query) != null,248 0b00 => std.mem.find(u8, ty_name, query) != null,
249 0b01 => std.mem.endsWith(u8, ty_name, query),249 0b01 => std.mem.endsWith(u8, ty_name, query),
...@@ -347,7 +347,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const...@@ -347,7 +347,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const
347 \\created on generation: {d}347 \\created on generation: {d}
348 \\348 \\
349 , .{349 , .{
350 Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip),350 Type.fromInterned(ip_index).containerTypeName(ip).fqn.fmt(ip),
351 create_gen,351 create_gen,
352 });352 });
353 } else if (std.mem.eql(u8, cmd_str, "type_namespace")) {353 } else if (std.mem.eql(u8, cmd_str, "type_namespace")) {
...@@ -451,7 +451,7 @@ fn printType(ty: Type, zcu: *const Zcu, w: *Io.Writer) Io.Writer.Error!void {...@@ -451,7 +451,7 @@ fn printType(ty: Type, zcu: *const Zcu, w: *Io.Writer) Io.Writer.Error!void {
451 .union_type,451 .union_type,
452 .enum_type,452 .enum_type,
453 .opaque_type,453 .opaque_type,
454 => try w.print("{f}[{d}]", .{ ty.containerTypeName(ip).fmt(ip), @backingInt(ty.toIntern()) }),454 => try w.print("{f}[{d}]", .{ ty.containerTypeName(ip).fqn.fmt(ip), @backingInt(ty.toIntern()) }),
455455
456 else => unreachable,456 else => unreachable,
457 }457 }
src/InternPool.zig+54-6
...@@ -3207,9 +3207,10 @@ pub const LoadedStructType = struct {...@@ -3207,9 +3207,10 @@ pub const LoadedStructType = struct {
3207 captures: CaptureValue.Slice,3207 captures: CaptureValue.Slice,
3208 is_reified: bool,3208 is_reified: bool,
32093209
3210 // TODO: the non-fqn will be needed by the new dwarf structure
3211 /// The name of this struct type.3210 /// The name of this struct type.
3212 name: NullTerminatedString,3211 name: NullTerminatedString,
3212 /// The fully-qualified name of this struct type.
3213 fqn: NullTerminatedString,
3213 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.3214 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
3214 /// Otherwise, or if this is a file's root struct type, this is `.none`.3215 /// Otherwise, or if this is a file's root struct type, this is `.none`.
3215 name_nav: Nav.Index.Optional,3216 name_nav: Nav.Index.Optional,
...@@ -3390,9 +3391,10 @@ pub const LoadedUnionType = struct {...@@ -3390,9 +3391,10 @@ pub const LoadedUnionType = struct {
3390 captures: CaptureValue.Slice,3391 captures: CaptureValue.Slice,
3391 is_reified: bool,3392 is_reified: bool,
33923393
3393 // TODO: the non-fqn will be needed by the new dwarf structure
3394 /// The name of this union type.3394 /// The name of this union type.
3395 name: NullTerminatedString,3395 name: NullTerminatedString,
3396 /// The fully-qualified name of this union type.
3397 fqn: NullTerminatedString,
3396 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.3398 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
3397 /// Otherwise, this is `.none`.3399 /// Otherwise, this is `.none`.
3398 name_nav: Nav.Index.Optional,3400 name_nav: Nav.Index.Optional,
...@@ -3457,9 +3459,10 @@ pub const LoadedEnumType = struct {...@@ -3457,9 +3459,10 @@ pub const LoadedEnumType = struct {
3457 owner_union: Index,3459 owner_union: Index,
3458 is_reified: bool,3460 is_reified: bool,
34593461
3460 // TODO: the non-fqn will be needed by the new dwarf structure
3461 /// The name of this enum type.3462 /// The name of this enum type.
3462 name: NullTerminatedString,3463 name: NullTerminatedString,
3464 /// The fully-qualified name of this enum type.
3465 fqn: NullTerminatedString,
3463 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.3466 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
3464 /// Otherwise, this is `.none`.3467 /// Otherwise, this is `.none`.
3465 name_nav: Nav.Index.Optional,3468 name_nav: Nav.Index.Optional,
...@@ -3519,9 +3522,10 @@ pub const LoadedOpaqueType = struct {...@@ -3519,9 +3522,10 @@ pub const LoadedOpaqueType = struct {
3519 zir_index: TrackedInst.Index,3522 zir_index: TrackedInst.Index,
3520 captures: CaptureValue.Slice,3523 captures: CaptureValue.Slice,
35213524
3522 // TODO: the non-fqn will be needed by the new dwarf structure
3523 /// The name of this opaque type.3525 /// The name of this opaque type.
3524 name: NullTerminatedString,3526 name: NullTerminatedString,
3527 /// The fully-qualified name of this opaque type.
3528 fqn: NullTerminatedString,
3525 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.3529 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
3526 /// Otherwise, this is `.none`.3530 /// Otherwise, this is `.none`.
3527 name_nav: Nav.Index.Optional,3531 name_nav: Nav.Index.Optional,
...@@ -3607,6 +3611,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {...@@ -3607,6 +3611,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
3607 .captures = captures,3611 .captures = captures,
3608 .is_reified = extra.data.flags.any_captures == .reified,3612 .is_reified = extra.data.flags.any_captures == .reified,
3609 .name = extra.data.name,3613 .name = extra.data.name,
3614 .fqn = extra.data.fqn,
3610 .name_nav = extra.data.name_nav,3615 .name_nav = extra.data.name_nav,
3611 .namespace = extra.data.namespace,3616 .namespace = extra.data.namespace,
3612 .layout = switch (extra.data.flags.layout) {3617 .layout = switch (extra.data.flags.layout) {
...@@ -3670,6 +3675,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {...@@ -3670,6 +3675,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
3670 .captures = captures,3675 .captures = captures,
3671 .is_reified = extra.data.bits.captures_len == .reified,3676 .is_reified = extra.data.bits.captures_len == .reified,
3672 .name = extra.data.name,3677 .name = extra.data.name,
3678 .fqn = extra.data.fqn,
3673 .name_nav = extra.data.name_nav,3679 .name_nav = extra.data.name_nav,
3674 .namespace = extra.data.namespace,3680 .namespace = extra.data.namespace,
3675 .layout = .@"packed",3681 .layout = .@"packed",
...@@ -3745,6 +3751,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {...@@ -3745,6 +3751,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3745 .captures = captures,3751 .captures = captures,
3746 .is_reified = extra.data.flags.any_captures == .reified,3752 .is_reified = extra.data.flags.any_captures == .reified,
3747 .name = extra.data.name,3753 .name = extra.data.name,
3754 .fqn = extra.data.fqn,
3748 .name_nav = extra.data.name_nav,3755 .name_nav = extra.data.name_nav,
3749 .namespace = extra.data.namespace,3756 .namespace = extra.data.namespace,
3750 .layout = switch (extra.data.flags.layout) {3757 .layout = switch (extra.data.flags.layout) {
...@@ -3800,6 +3807,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {...@@ -3800,6 +3807,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3800 .captures = captures,3807 .captures = captures,
3801 .is_reified = extra.data.bits.captures_len == .reified,3808 .is_reified = extra.data.bits.captures_len == .reified,
3802 .name = extra.data.name,3809 .name = extra.data.name,
3810 .fqn = extra.data.fqn,
3803 .name_nav = extra.data.name_nav,3811 .name_nav = extra.data.name_nav,
3804 .namespace = extra.data.namespace,3812 .namespace = extra.data.namespace,
3805 .layout = .@"packed",3813 .layout = .@"packed",
...@@ -3880,6 +3888,7 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {...@@ -3880,6 +3888,7 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
3880 .is_reified = extra.data.bits.captures_len == .reified,3888 .is_reified = extra.data.bits.captures_len == .reified,
3881 .owner_union = owner_union,3889 .owner_union = owner_union,
3882 .name = extra.data.name,3890 .name = extra.data.name,
3891 .fqn = extra.data.fqn,
3883 .name_nav = extra.data.name_nav,3892 .name_nav = extra.data.name_nav,
3884 .namespace = extra.data.namespace,3893 .namespace = extra.data.namespace,
3885 .int_tag_type = extra.data.int_tag_type,3894 .int_tag_type = extra.data.int_tag_type,
...@@ -3906,6 +3915,7 @@ pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType {...@@ -3906,6 +3915,7 @@ pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType {
3906 .len = extra.data.captures_len,3915 .len = extra.data.captures_len,
3907 },3916 },
3908 .name = extra.data.name,3917 .name = extra.data.name,
3918 .fqn = extra.data.fqn,
3909 .name_nav = extra.data.name_nav,3919 .name_nav = extra.data.name_nav,
3910 .namespace = extra.data.namespace,3920 .namespace = extra.data.namespace,
3911 };3921 };
...@@ -5538,6 +5548,7 @@ pub const Tag = enum(u8) {...@@ -5538,6 +5548,7 @@ pub const Tag = enum(u8) {
5538 zir_index: TrackedInst.Index,5548 zir_index: TrackedInst.Index,
55395549
5540 name: NullTerminatedString,5550 name: NullTerminatedString,
5551 fqn: NullTerminatedString,
5541 name_nav: Nav.Index.Optional,5552 name_nav: Nav.Index.Optional,
5542 namespace: NamespaceIndex,5553 namespace: NamespaceIndex,
55435554
...@@ -5580,6 +5591,7 @@ pub const Tag = enum(u8) {...@@ -5580,6 +5591,7 @@ pub const Tag = enum(u8) {
5580 bits: Bits,5591 bits: Bits,
55815592
5582 name: NullTerminatedString,5593 name: NullTerminatedString,
5594 fqn: NullTerminatedString,
5583 name_nav: Nav.Index.Optional,5595 name_nav: Nav.Index.Optional,
5584 namespace: NamespaceIndex,5596 namespace: NamespaceIndex,
55855597
...@@ -5614,6 +5626,7 @@ pub const Tag = enum(u8) {...@@ -5614,6 +5626,7 @@ pub const Tag = enum(u8) {
5614 zir_index: TrackedInst.Index,5626 zir_index: TrackedInst.Index,
56155627
5616 name: NullTerminatedString,5628 name: NullTerminatedString,
5629 fqn: NullTerminatedString,
5617 name_nav: Nav.Index.Optional,5630 name_nav: Nav.Index.Optional,
5618 namespace: NamespaceIndex,5631 namespace: NamespaceIndex,
5619 /// The enum that provides the list of field names and values.5632 /// The enum that provides the list of field names and values.
...@@ -5673,6 +5686,7 @@ pub const Tag = enum(u8) {...@@ -5673,6 +5686,7 @@ pub const Tag = enum(u8) {
5673 bits: Bits,5686 bits: Bits,
56745687
5675 name: NullTerminatedString,5688 name: NullTerminatedString,
5689 fqn: NullTerminatedString,
5676 name_nav: Nav.Index.Optional,5690 name_nav: Nav.Index.Optional,
5677 namespace: NamespaceIndex,5691 namespace: NamespaceIndex,
56785692
...@@ -5708,6 +5722,7 @@ pub const Tag = enum(u8) {...@@ -5708,6 +5722,7 @@ pub const Tag = enum(u8) {
5708 bits: Bits,5722 bits: Bits,
57095723
5710 name: NullTerminatedString,5724 name: NullTerminatedString,
5725 fqn: NullTerminatedString,
5711 name_nav: Nav.Index.Optional,5726 name_nav: Nav.Index.Optional,
5712 namespace: NamespaceIndex,5727 namespace: NamespaceIndex,
57135728
...@@ -5735,6 +5750,7 @@ pub const Tag = enum(u8) {...@@ -5735,6 +5750,7 @@ pub const Tag = enum(u8) {
5735 captures_len: u32,5750 captures_len: u32,
57365751
5737 name: NullTerminatedString,5752 name: NullTerminatedString,
5753 fqn: NullTerminatedString,
5738 name_nav: Nav.Index.Optional,5754 name_nav: Nav.Index.Optional,
5739 namespace: NamespaceIndex,5755 namespace: NamespaceIndex,
5740 };5756 };
...@@ -8063,6 +8079,7 @@ pub fn getDeclaredStructType(...@@ -8063,6 +8079,7 @@ pub fn getDeclaredStructType(
8063 .want_layout = false,8079 .want_layout = false,
8064 },8080 },
8065 .name = undefined, // set by `finish`8081 .name = undefined, // set by `finish`
8082 .fqn = undefined, // set by `finish`
8066 .name_nav = undefined, // set by `finish`8083 .name_nav = undefined, // set by `finish`
8067 .namespace = undefined, // set by `finish`8084 .namespace = undefined, // set by `finish`
8068 .backing_int_type = .none,8085 .backing_int_type = .none,
...@@ -8086,6 +8103,7 @@ pub fn getDeclaredStructType(...@@ -8086,6 +8103,7 @@ pub fn getDeclaredStructType(
8086 .index = gop.put(),8103 .index = gop.put(),
8087 .tid = tid,8104 .tid = tid,
8088 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,8105 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
8106 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "fqn").?,
8089 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,8107 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,
8090 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,8108 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
8091 .field_names = undefined,8109 .field_names = undefined,
...@@ -8111,6 +8129,7 @@ pub fn getDeclaredStructType(...@@ -8111,6 +8129,7 @@ pub fn getDeclaredStructType(
8111 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{8129 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
8112 .zir_index = ini.zir_index,8130 .zir_index = ini.zir_index,
8113 .name = undefined, // set by `finish`8131 .name = undefined, // set by `finish`
8132 .fqn = undefined, // set by `finish`
8114 .name_nav = undefined, // set by `finish`8133 .name_nav = undefined, // set by `finish`
8115 .namespace = undefined, // set by `finish`8134 .namespace = undefined, // set by `finish`
8116 .fields_len = ini.fields_len,8135 .fields_len = ini.fields_len,
...@@ -8154,6 +8173,7 @@ pub fn getDeclaredStructType(...@@ -8154,6 +8173,7 @@ pub fn getDeclaredStructType(
8154 .index = gop.put(),8173 .index = gop.put(),
8155 .tid = tid,8174 .tid = tid,
8156 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,8175 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
8176 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "fqn").?,
8157 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,8177 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,
8158 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,8178 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,
8159 .field_names = undefined,8179 .field_names = undefined,
...@@ -8207,6 +8227,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe...@@ -8207,6 +8227,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe
8207 .want_layout = false,8227 .want_layout = false,
8208 },8228 },
8209 .name = undefined, // set by `finish`8229 .name = undefined, // set by `finish`
8230 .fqn = undefined, // set by `finish`
8210 .name_nav = undefined, // set by `finish`8231 .name_nav = undefined, // set by `finish`
8211 .namespace = undefined, // set by `finish`8232 .namespace = undefined, // set by `finish`
8212 .backing_int_type = ini.packed_backing_int_type,8233 .backing_int_type = ini.packed_backing_int_type,
...@@ -8233,6 +8254,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe...@@ -8233,6 +8254,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe
8233 .index = gop.put(),8254 .index = gop.put(),
8234 .tid = tid,8255 .tid = tid,
8235 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,8256 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
8257 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "fqn").?,
8236 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,8258 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,
8237 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,8259 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
8238 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },8260 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
...@@ -8260,6 +8282,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe...@@ -8260,6 +8282,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe
8260 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{8282 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
8261 .zir_index = ini.zir_index,8283 .zir_index = ini.zir_index,
8262 .name = undefined, // set by `finish`8284 .name = undefined, // set by `finish`
8285 .fqn = undefined, // set by `finish`
8263 .name_nav = undefined, // set by `finish`8286 .name_nav = undefined, // set by `finish`
8264 .namespace = undefined, // set by `finish`8287 .namespace = undefined, // set by `finish`
8265 .fields_len = ini.fields_len,8288 .fields_len = ini.fields_len,
...@@ -8305,6 +8328,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe...@@ -8305,6 +8328,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe
8305 .index = gop.put(),8328 .index = gop.put(),
8306 .tid = tid,8329 .tid = tid,
8307 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,8330 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
8331 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "fqn").?,
8308 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,8332 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,
8309 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,8333 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,
8310 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },8334 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
...@@ -8378,6 +8402,7 @@ pub fn getDeclaredUnionType(...@@ -8378,6 +8402,7 @@ pub fn getDeclaredUnionType(
8378 .want_layout = false,8402 .want_layout = false,
8379 },8403 },
8380 .name = undefined, // set by `finish`8404 .name = undefined, // set by `finish`
8405 .fqn = undefined, // set by `finish`
8381 .name_nav = undefined, // set by `finish`8406 .name_nav = undefined, // set by `finish`
8382 .namespace = undefined, // set by `finish`8407 .namespace = undefined, // set by `finish`
8383 .backing_int_type = .none,8408 .backing_int_type = .none,
...@@ -8397,6 +8422,7 @@ pub fn getDeclaredUnionType(...@@ -8397,6 +8422,7 @@ pub fn getDeclaredUnionType(
8397 .index = gop.put(),8422 .index = gop.put(),
8398 .tid = tid,8423 .tid = tid,
8399 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,8424 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,
8425 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "fqn").?,
8400 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,8426 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,
8401 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,8427 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,
8402 .field_names = undefined,8428 .field_names = undefined,
...@@ -8417,6 +8443,7 @@ pub fn getDeclaredUnionType(...@@ -8417,6 +8443,7 @@ pub fn getDeclaredUnionType(
8417 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{8443 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{
8418 .zir_index = ini.zir_index,8444 .zir_index = ini.zir_index,
8419 .name = undefined, // set by `finish`8445 .name = undefined, // set by `finish`
8446 .fqn = undefined, // set by `finish`
8420 .name_nav = undefined, // set by `finish`8447 .name_nav = undefined, // set by `finish`
8421 .namespace = undefined, // set by `finish`8448 .namespace = undefined, // set by `finish`
8422 .enum_tag_type = .none,8449 .enum_tag_type = .none,
...@@ -8451,6 +8478,7 @@ pub fn getDeclaredUnionType(...@@ -8451,6 +8478,7 @@ pub fn getDeclaredUnionType(
8451 .index = gop.put(),8478 .index = gop.put(),
8452 .tid = tid,8479 .tid = tid,
8453 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,8480 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
8481 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "fqn").?,
8454 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,8482 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,
8455 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,8483 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
8456 .field_names = undefined,8484 .field_names = undefined,
...@@ -8501,6 +8529,7 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per...@@ -8501,6 +8529,7 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per
8501 .want_layout = false,8529 .want_layout = false,
8502 },8530 },
8503 .name = undefined, // set by `finish`8531 .name = undefined, // set by `finish`
8532 .fqn = undefined, // set by `finish`
8504 .name_nav = undefined, // set by `finish`8533 .name_nav = undefined, // set by `finish`
8505 .namespace = undefined, // set by `finish`8534 .namespace = undefined, // set by `finish`
8506 .backing_int_type = ini.packed_backing_int_type,8535 .backing_int_type = ini.packed_backing_int_type,
...@@ -8523,6 +8552,7 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per...@@ -8523,6 +8552,7 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per
8523 .index = gop.put(),8552 .index = gop.put(),
8524 .tid = tid,8553 .tid = tid,
8525 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,8554 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,
8555 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "fqn").?,
8526 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,8556 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,
8527 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,8557 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,
8528 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },8558 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
...@@ -8543,6 +8573,7 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per...@@ -8543,6 +8573,7 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per
8543 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{8573 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{
8544 .zir_index = ini.zir_index,8574 .zir_index = ini.zir_index,
8545 .name = undefined, // set by `finish`8575 .name = undefined, // set by `finish`
8576 .fqn = undefined, // set by `finish`
8546 .name_nav = undefined, // set by `finish`8577 .name_nav = undefined, // set by `finish`
8547 .namespace = undefined, // set by `finish`8578 .namespace = undefined, // set by `finish`
8548 .enum_tag_type = ini.enum_tag_type,8579 .enum_tag_type = ini.enum_tag_type,
...@@ -8578,6 +8609,7 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per...@@ -8578,6 +8609,7 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per
8578 .index = gop.put(),8609 .index = gop.put(),
8579 .tid = tid,8610 .tid = tid,
8580 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,8611 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
8612 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "fqn").?,
8581 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,8613 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,
8582 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,8614 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
8583 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },8615 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
...@@ -8654,6 +8686,7 @@ pub fn getDeclaredEnumType(...@@ -8654,6 +8686,7 @@ pub fn getDeclaredEnumType(
8654 .want_layout = false,8686 .want_layout = false,
8655 },8687 },
8656 .name = undefined, // set by `finish`8688 .name = undefined, // set by `finish`
8689 .fqn = undefined, // set by `finish`
8657 .name_nav = undefined, // set by `finish`8690 .name_nav = undefined, // set by `finish`
8658 .namespace = undefined, // set by `finish`8691 .namespace = undefined, // set by `finish`
8659 .int_tag_type = .none,8692 .int_tag_type = .none,
...@@ -8673,6 +8706,7 @@ pub fn getDeclaredEnumType(...@@ -8673,6 +8706,7 @@ pub fn getDeclaredEnumType(
8673 .index = gop.put(),8706 .index = gop.put(),
8674 .tid = tid,8707 .tid = tid,
8675 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,8708 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
8709 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "fqn").?,
8676 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,8710 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
8677 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,8711 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
8678 .field_names = undefined,8712 .field_names = undefined,
...@@ -8729,6 +8763,7 @@ pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerT...@@ -8729,6 +8763,7 @@ pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerT
8729 .want_layout = false,8763 .want_layout = false,
8730 },8764 },
8731 .name = undefined, // set by `finish`8765 .name = undefined, // set by `finish`
8766 .fqn = undefined, // set by `finish`
8732 .name_nav = undefined, // set by `finish`8767 .name_nav = undefined, // set by `finish`
8733 .namespace = undefined, // set by `finish`8768 .namespace = undefined, // set by `finish`
8734 .int_tag_type = ini.int_tag_type,8769 .int_tag_type = ini.int_tag_type,
...@@ -8750,6 +8785,7 @@ pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerT...@@ -8750,6 +8785,7 @@ pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerT
8750 .index = gop.put(),8785 .index = gop.put(),
8751 .tid = tid,8786 .tid = tid,
8752 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,8787 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
8788 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "fqn").?,
8753 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,8789 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
8754 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,8790 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
8755 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },8791 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
...@@ -8828,6 +8864,7 @@ pub fn getGeneratedEnumTagType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu...@@ -8828,6 +8864,7 @@ pub fn getGeneratedEnumTagType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu
8828 .want_layout = false,8864 .want_layout = false,
8829 },8865 },
8830 .name = undefined, // set by `finish`8866 .name = undefined, // set by `finish`
8867 .fqn = undefined, // set by `finish`
8831 .name_nav = undefined, // set by `finish`8868 .name_nav = undefined, // set by `finish`
8832 .namespace = undefined, // set by `finish`8869 .namespace = undefined, // set by `finish`
8833 .int_tag_type = .none,8870 .int_tag_type = .none,
...@@ -8849,6 +8886,7 @@ pub fn getGeneratedEnumTagType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu...@@ -8849,6 +8886,7 @@ pub fn getGeneratedEnumTagType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu
8849 .index = gop.put(),8886 .index = gop.put(),
8850 .tid = tid,8887 .tid = tid,
8851 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,8888 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
8889 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "fqn").?,
8852 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,8890 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
8853 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,8891 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
8854 .field_names = undefined,8892 .field_names = undefined,
...@@ -8880,6 +8918,7 @@ pub fn getDeclaredOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.P...@@ -8880,6 +8918,7 @@ pub fn getDeclaredOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.P
8880 .zir_index = ini.zir_index,8918 .zir_index = ini.zir_index,
8881 .captures_len = @intCast(ini.captures.len),8919 .captures_len = @intCast(ini.captures.len),
8882 .name = undefined, // set by `finish`8920 .name = undefined, // set by `finish`
8921 .fqn = undefined, // set by `finish`
8883 .name_nav = undefined, // set by `finish`8922 .name_nav = undefined, // set by `finish`
8884 .namespace = undefined, // set by `finish`8923 .namespace = undefined, // set by `finish`
8885 });8924 });
...@@ -8892,6 +8931,7 @@ pub fn getDeclaredOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.P...@@ -8892,6 +8931,7 @@ pub fn getDeclaredOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.P
8892 .index = gop.put(),8931 .index = gop.put(),
8893 .tid = tid,8932 .tid = tid,
8894 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?,8933 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?,
8934 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "fqn").?,
8895 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?,8935 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?,
8896 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?,8936 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?,
8897 .field_names = undefined,8937 .field_names = undefined,
...@@ -8906,6 +8946,7 @@ pub const WipContainerType = struct {...@@ -8906,6 +8946,7 @@ pub const WipContainerType = struct {
8906 index: Index,8946 index: Index,
8907 tid: Zcu.PerThread.Id,8947 tid: Zcu.PerThread.Id,
8908 type_name_index: u32,8948 type_name_index: u32,
8949 type_fqn_index: u32,
8909 name_nav_index: u32,8950 name_nav_index: u32,
8910 namespace_index: u32,8951 namespace_index: u32,
89118952
...@@ -8923,6 +8964,7 @@ pub const WipContainerType = struct {...@@ -8923,6 +8964,7 @@ pub const WipContainerType = struct {
8923 wip: WipContainerType,8964 wip: WipContainerType,
8924 ip: *InternPool,8965 ip: *InternPool,
8925 type_name: NullTerminatedString,8966 type_name: NullTerminatedString,
8967 type_fqn: NullTerminatedString,
8926 /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise.8968 /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise.
8927 /// This is also `.none` if we use `.parent` because we are the root struct type for a file.8969 /// This is also `.none` if we use `.parent` because we are the root struct type for a file.
8928 name_nav: Nav.Index.Optional,8970 name_nav: Nav.Index.Optional,
...@@ -8930,6 +8972,7 @@ pub const WipContainerType = struct {...@@ -8930,6 +8972,7 @@ pub const WipContainerType = struct {
8930 const extra = ip.getLocalShared(wip.tid).extra.acquire();8972 const extra = ip.getLocalShared(wip.tid).extra.acquire();
8931 const extra_items = extra.view().items(.@"0");8973 const extra_items = extra.view().items(.@"0");
8932 extra_items[wip.type_name_index] = @backingInt(type_name);8974 extra_items[wip.type_name_index] = @backingInt(type_name);
8975 extra_items[wip.type_fqn_index] = @backingInt(type_fqn);
8933 extra_items[wip.name_nav_index] = @backingInt(name_nav);8976 extra_items[wip.name_nav_index] = @backingInt(name_nav);
8934 }8977 }
89358978
...@@ -9503,6 +9546,7 @@ pub const GetFuncInstanceKey = struct {...@@ -9503,6 +9546,7 @@ pub const GetFuncInstanceKey = struct {
9503 is_noinline: bool,9546 is_noinline: bool,
9504 generic_owner: Index,9547 generic_owner: Index,
9505 inferred_error_set: bool,9548 inferred_error_set: bool,
9549 anon_name_counter: *u32,
9506};9550};
95079551
9508pub fn getFuncInstance(9552pub fn getFuncInstance(
...@@ -9580,6 +9624,7 @@ pub fn getFuncInstance(...@@ -9580,6 +9624,7 @@ pub fn getFuncInstance(
9580 generic_owner,9624 generic_owner,
9581 func_index,9625 func_index,
9582 func_extra_index,9626 func_extra_index,
9627 arg.anon_name_counter,
9583 );9628 );
9584 return gop.put();9629 return gop.put();
9585}9630}
...@@ -9731,6 +9776,7 @@ fn getFuncInstanceIes(...@@ -9731,6 +9776,7 @@ fn getFuncInstanceIes(
9731 generic_owner,9776 generic_owner,
9732 func_index,9777 func_index,
9733 func_extra_index,9778 func_extra_index,
9779 arg.anon_name_counter,
9734 );9780 );
97359781
9736 func_gop.putFinal(func_index);9782 func_gop.putFinal(func_index);
...@@ -9749,14 +9795,16 @@ fn finishFuncInstance(...@@ -9749,14 +9795,16 @@ fn finishFuncInstance(
9749 generic_owner: Index,9795 generic_owner: Index,
9750 func_index: Index,9796 func_index: Index,
9751 func_extra_index: u32,9797 func_extra_index: u32,
9798 anon_name_counter: *u32,
9752) Allocator.Error!void {9799) Allocator.Error!void {
9753 const fn_owner_nav = ip.getNav(ip.funcDeclInfo(generic_owner).owner_nav);9800 const fn_owner_nav = ip.getNav(ip.funcDeclInfo(generic_owner).owner_nav);
9754 const fn_namespace = fn_owner_nav.analysis.?.namespace;9801 const fn_namespace = fn_owner_nav.analysis.?.namespace;
97559802
9756 // TODO: improve this name9803 // TODO: improve this name
9757 const nav_name = try ip.getOrPutStringFmt(gpa, io, tid, "{f}__anon_{d}", .{9804 const nav_name = try ip.getOrPutStringFmt(gpa, io, tid, "{f}__func_{d}", .{
9758 fn_owner_nav.name.fmt(ip), @backingInt(func_index),9805 fn_owner_nav.name.fmt(ip), anon_name_counter.*,
9759 }, .no_embedded_nulls);9806 }, .no_embedded_nulls);
9807 anon_name_counter.* += 1;
9760 const nav_fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, io, tid, nav_name);9808 const nav_fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, io, tid, nav_name);
9761 const nav_index = try ip.createNav(gpa, io, tid, nav_name, nav_fqn, .{9809 const nav_index = try ip.createNav(gpa, io, tid, nav_name, nav_fqn, .{
9762 .type = ip.typeOf(func_index),9810 .type = ip.typeOf(func_index),
src/Sema.zig+40-12
...@@ -403,6 +403,7 @@ pub const Block = struct {...@@ -403,6 +403,7 @@ pub const Block = struct {
403 /// is always incorporated into the type name somehow.403 /// is always incorporated into the type name somehow.
404 /// See `Sema.setTypeName`.404 /// See `Sema.setTypeName`.
405 type_name_ctx: InternPool.NullTerminatedString,405 type_name_ctx: InternPool.NullTerminatedString,
406 type_fqn_ctx: InternPool.NullTerminatedString,
406407
407 /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block.408 /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block.
408 /// Specifically, the given `Offset` is treated as relative to `block.src_base_inst`.409 /// Specifically, the given `Offset` is treated as relative to `block.src_base_inst`.
...@@ -531,6 +532,7 @@ pub const Block = struct {...@@ -531,6 +532,7 @@ pub const Block = struct {
531 .need_debug_scope = parent.need_debug_scope,532 .need_debug_scope = parent.need_debug_scope,
532 .src_base_inst = parent.src_base_inst,533 .src_base_inst = parent.src_base_inst,
533 .type_name_ctx = parent.type_name_ctx,534 .type_name_ctx = parent.type_name_ctx,
535 .type_fqn_ctx = parent.type_fqn_ctx,
534 };536 };
535 }537 }
536538
...@@ -4782,7 +4784,7 @@ fn failWithBadStructFieldAccess(...@@ -4782,7 +4784,7 @@ fn failWithBadStructFieldAccess(
4782 const msg = try sema.errMsg(4784 const msg = try sema.errMsg(
4783 field_src,4785 field_src,
4784 "no field named '{f}' in struct '{f}'",4786 "no field named '{f}' in struct '{f}'",
4785 .{ field_name.fmt(ip), struct_type.name.fmt(ip) },4787 .{ field_name.fmt(ip), struct_type.fqn.fmt(ip) },
4786 );4788 );
4787 errdefer msg.destroy(sema.gpa);4789 errdefer msg.destroy(sema.gpa);
4788 try sema.errNote(struct_ty.srcLoc(zcu), msg, "struct declared here", .{});4790 try sema.errNote(struct_ty.srcLoc(zcu), msg, "struct declared here", .{});
...@@ -4808,7 +4810,7 @@ fn failWithBadUnionFieldAccess(...@@ -4808,7 +4810,7 @@ fn failWithBadUnionFieldAccess(
4808 const msg = try sema.errMsg(4810 const msg = try sema.errMsg(
4809 field_src,4811 field_src,
4810 "no field named '{f}' in union '{f}'",4812 "no field named '{f}' in union '{f}'",
4811 .{ field_name.fmt(ip), union_obj.name.fmt(ip) },4813 .{ field_name.fmt(ip), union_obj.fqn.fmt(ip) },
4812 );4814 );
4813 errdefer msg.destroy(gpa);4815 errdefer msg.destroy(gpa);
4814 try sema.errNote(union_ty.srcLoc(zcu), msg, "union declared here", .{});4816 try sema.errNote(union_ty.srcLoc(zcu), msg, "union declared here", .{});
...@@ -5291,6 +5293,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -5291,6 +5293,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
5291 .error_return_trace_index = parent_block.error_return_trace_index,5293 .error_return_trace_index = parent_block.error_return_trace_index,
5292 .src_base_inst = parent_block.src_base_inst,5294 .src_base_inst = parent_block.src_base_inst,
5293 .type_name_ctx = parent_block.type_name_ctx,5295 .type_name_ctx = parent_block.type_name_ctx,
5296 .type_fqn_ctx = parent_block.type_fqn_ctx,
5294 };5297 };
52955298
5296 defer child_block.instructions.deinit(gpa);5299 defer child_block.instructions.deinit(gpa);
...@@ -6773,7 +6776,8 @@ fn analyzeCall(...@@ -6773,7 +6776,8 @@ fn analyzeCall(
6773 .instructions = .empty,6776 .instructions = .empty,
6774 .inlining = &generic_inlining,6777 .inlining = &generic_inlining,
6775 .src_base_inst = fn_nav.analysis.?.zir_index,6778 .src_base_inst = fn_nav.analysis.?.zir_index,
6776 .type_name_ctx = fn_nav.fqn,6779 .type_name_ctx = fn_nav.name,
6780 .type_fqn_ctx = fn_nav.fqn,
6777 } else undefined;6781 } else undefined;
6778 defer if (any_generic_types) generic_block.instructions.deinit(gpa);6782 defer if (any_generic_types) generic_block.instructions.deinit(gpa);
67796783
...@@ -7039,6 +7043,7 @@ fn analyzeCall(...@@ -7039,6 +7043,7 @@ fn analyzeCall(
7039 .inferred_error_set = fn_zir_info.inferred_error_set,7043 .inferred_error_set = fn_zir_info.inferred_error_set,
7040 .generic_owner = func_val.?.toIntern(),7044 .generic_owner = func_val.?.toIntern(),
7041 .comptime_args = comptime_args,7045 .comptime_args = comptime_args,
7046 .anon_name_counter = &zcu.anon_name_counter,
7042 });7047 });
7043 if (zcu.comp.debugIncremental()) {7048 if (zcu.comp.debugIncremental()) {
7044 const nav = ip.indexToKey(func_instance).func.owner_nav;7049 const nav = ip.indexToKey(func_instance).func.owner_nav;
...@@ -7308,7 +7313,8 @@ fn analyzeCall(...@@ -7308,7 +7313,8 @@ fn analyzeCall(
7308 .runtime_loop = block.runtime_loop,7313 .runtime_loop = block.runtime_loop,
7309 .runtime_index = block.runtime_index,7314 .runtime_index = block.runtime_index,
7310 .src_base_inst = fn_nav.analysis.?.zir_index,7315 .src_base_inst = fn_nav.analysis.?.zir_index,
7311 .type_name_ctx = fn_nav.fqn,7316 .type_name_ctx = fn_nav.name,
7317 .type_fqn_ctx = fn_nav.fqn,
7312 };7318 };
73137319
7314 defer child_block.instructions.deinit(gpa);7320 defer child_block.instructions.deinit(gpa);
...@@ -17314,6 +17320,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -17314,6 +17320,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
17314 .error_return_trace_index = block.error_return_trace_index,17320 .error_return_trace_index = block.error_return_trace_index,
17315 .src_base_inst = block.src_base_inst,17321 .src_base_inst = block.src_base_inst,
17316 .type_name_ctx = block.type_name_ctx,17322 .type_name_ctx = block.type_name_ctx,
17323 .type_fqn_ctx = block.type_fqn_ctx,
17317 };17324 };
17318 defer child_block.instructions.deinit(sema.gpa);17325 defer child_block.instructions.deinit(sema.gpa);
1731917326
...@@ -17380,6 +17387,7 @@ fn zirTypeofPeer(...@@ -17380,6 +17387,7 @@ fn zirTypeofPeer(
17380 .runtime_index = block.runtime_index,17387 .runtime_index = block.runtime_index,
17381 .src_base_inst = block.src_base_inst,17388 .src_base_inst = block.src_base_inst,
17382 .type_name_ctx = block.type_name_ctx,17389 .type_name_ctx = block.type_name_ctx,
17390 .type_fqn_ctx = block.type_fqn_ctx,
17383 };17391 };
17384 defer child_block.instructions.deinit(sema.gpa);17392 defer child_block.instructions.deinit(sema.gpa);
17385 // Ignore the result, we only care about the instructions in `args`.17393 // Ignore the result, we only care about the instructions in `args`.
...@@ -17939,6 +17947,7 @@ fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*Label...@@ -17939,6 +17947,7 @@ fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*Label
17939 .comptime_reason = block.comptime_reason,17947 .comptime_reason = block.comptime_reason,
17940 .src_base_inst = block.src_base_inst,17948 .src_base_inst = block.src_base_inst,
17941 .type_name_ctx = block.type_name_ctx,17949 .type_name_ctx = block.type_name_ctx,
17950 .type_fqn_ctx = block.type_fqn_ctx,
17942 },17951 },
17943 };17952 };
17944 sema.post_hoc_blocks.putAssumeCapacityNoClobber(new_block_inst, labeled_block);17953 sema.post_hoc_blocks.putAssumeCapacityNoClobber(new_block_inst, labeled_block);
...@@ -25934,6 +25943,7 @@ fn addSafetyCheck(...@@ -25934,6 +25943,7 @@ fn addSafetyCheck(
25934 .comptime_reason = null,25943 .comptime_reason = null,
25935 .src_base_inst = parent_block.src_base_inst,25944 .src_base_inst = parent_block.src_base_inst,
25936 .type_name_ctx = parent_block.type_name_ctx,25945 .type_name_ctx = parent_block.type_name_ctx,
25946 .type_fqn_ctx = parent_block.type_fqn_ctx,
25937 };25947 };
2593825948
25939 defer fail_block.instructions.deinit(gpa);25949 defer fail_block.instructions.deinit(gpa);
...@@ -26028,6 +26038,7 @@ fn addSafetyCheckUnwrapError(...@@ -26028,6 +26038,7 @@ fn addSafetyCheckUnwrapError(
26028 .comptime_reason = null,26038 .comptime_reason = null,
26029 .src_base_inst = parent_block.src_base_inst,26039 .src_base_inst = parent_block.src_base_inst,
26030 .type_name_ctx = parent_block.type_name_ctx,26040 .type_name_ctx = parent_block.type_name_ctx,
26041 .type_fqn_ctx = parent_block.type_fqn_ctx,
26031 };26042 };
2603226043
26033 defer fail_block.instructions.deinit(gpa);26044 defer fail_block.instructions.deinit(gpa);
...@@ -26151,6 +26162,7 @@ fn addSafetyCheckCall(...@@ -26151,6 +26162,7 @@ fn addSafetyCheckCall(
26151 .comptime_reason = null,26162 .comptime_reason = null,
26152 .src_base_inst = parent_block.src_base_inst,26163 .src_base_inst = parent_block.src_base_inst,
26153 .type_name_ctx = parent_block.type_name_ctx,26164 .type_name_ctx = parent_block.type_name_ctx,
26165 .type_fqn_ctx = parent_block.type_fqn_ctx,
26154 };26166 };
2615526167
26156 defer fail_block.instructions.deinit(gpa);26168 defer fail_block.instructions.deinit(gpa);
...@@ -34993,6 +35005,7 @@ pub fn analyzeMemoizedState(sema: *Sema, stage: InternPool.MemoizedStateStage) C...@@ -34993,6 +35005,7 @@ pub fn analyzeMemoizedState(sema: *Sema, stage: InternPool.MemoizedStateStage) C
34993 .comptime_reason = null,35005 .comptime_reason = null,
34994 .src_base_inst = std_type.typeDeclInst(zcu).?,35006 .src_base_inst = std_type.typeDeclInst(zcu).?,
34995 .type_name_ctx = .empty,35007 .type_name_ctx = .empty,
35008 .type_fqn_ctx = .empty,
34996 };35009 };
34997 };35010 };
34998 defer block.instructions.deinit(gpa);35011 defer block.instructions.deinit(gpa);
...@@ -35222,11 +35235,19 @@ pub fn setTypeName(...@@ -35222,11 +35235,19 @@ pub fn setTypeName(
35222 io,35235 io,
35223 pt.tid,35236 pt.tid,
35224 "{f}__{s}_{d}",35237 "{f}__{s}_{d}",
35225 .{ block.type_name_ctx.fmt(ip), anon_prefix, @backingInt(wip.index) },35238 .{ block.type_name_ctx.fmt(ip), anon_prefix, zcu.anon_name_counter },
35239 .no_embedded_nulls,
35240 ), try ip.getOrPutStringFmt(
35241 gpa,
35242 io,
35243 pt.tid,
35244 "{f}__{s}_{d}",
35245 .{ block.type_fqn_ctx.fmt(ip), anon_prefix, zcu.anon_name_counter },
35226 .no_embedded_nulls,35246 .no_embedded_nulls,
35227 ), .none);35247 ), .none);
35248 zcu.anon_name_counter += 1;
35228 },35249 },
35229 .parent => wip.setName(ip, block.type_name_ctx, sema.owner.unwrap().nav_val.toOptional()),35250 .parent => wip.setName(ip, block.type_name_ctx, block.type_fqn_ctx, sema.owner.unwrap().nav_val.toOptional()),
35230 .func => {35251 .func => {
35231 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse {35252 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse {
35232 return sema.failTransitive(.{ .lost_tracking = ip.funcZirBodyInst(sema.func_index) });35253 return sema.failTransitive(.{ .lost_tracking = ip.funcZirBodyInst(sema.func_index) });
...@@ -35236,7 +35257,7 @@ pub fn setTypeName(...@@ -35236,7 +35257,7 @@ pub fn setTypeName(
35236 var aw: std.Io.Writer.Allocating = .init(gpa);35257 var aw: std.Io.Writer.Allocating = .init(gpa);
35237 defer aw.deinit();35258 defer aw.deinit();
35238 const w = &aw.writer;35259 const w = &aw.writer;
35239 w.print("{f}(", .{block.type_name_ctx.fmt(ip)}) catch return error.OutOfMemory;35260 w.writeByte('(') catch return error.OutOfMemory;
3524035261
35241 var arg_i: usize = 0;35262 var arg_i: usize = 0;
35242 for (fn_info.param_body) |zir_inst| switch (zir_tags[@backingInt(zir_inst)]) {35263 for (fn_info.param_body) |zir_inst| switch (zir_tags[@backingInt(zir_inst)]) {
...@@ -35271,8 +35292,13 @@ pub fn setTypeName(...@@ -35271,8 +35292,13 @@ pub fn setTypeName(
35271 };35292 };
3527235293
35273 w.writeByte(')') catch return error.OutOfMemory;35294 w.writeByte(')') catch return error.OutOfMemory;
35274 const name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls);35295 wip.setName(ip, try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}{s}", .{
35275 wip.setName(ip, name, .none);35296 block.type_name_ctx.fmt(ip),
35297 aw.written(),
35298 }, .no_embedded_nulls), try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}{s}", .{
35299 block.type_fqn_ctx.fmt(ip),
35300 aw.written(),
35301 }, .no_embedded_nulls), .none);
35276 },35302 },
35277 .dbg_var => {35303 .dbg_var => {
35278 // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions.35304 // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions.
...@@ -35287,10 +35313,12 @@ pub fn setTypeName(...@@ -35287,10 +35313,12 @@ pub fn setTypeName(
35287 } else {35313 } else {
35288 continue :strat .anon;35314 continue :strat .anon;
35289 };35315 };
35290 const name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{35316 wip.setName(ip, try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
35317 // this "{f}." should be elided, but there's currently no way to get the parent function
35291 block.type_name_ctx.fmt(ip), var_name,35318 block.type_name_ctx.fmt(ip), var_name,
35292 }, .no_embedded_nulls);35319 }, .no_embedded_nulls), try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
35293 wip.setName(ip, name, .none);35320 block.type_fqn_ctx.fmt(ip), var_name,
35321 }, .no_embedded_nulls), .none);
35294 },35322 },
35295 }35323 }
35296}35324}
src/Sema/type_resolution.zig+15-4
...@@ -187,7 +187,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -187,7 +187,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
187187
188 const tracy = trace(@src());188 const tracy = trace(@src());
189 defer tracy.end();189 defer tracy.end();
190 tracy.addText(struct_ty.containerTypeName(ip).toSlice(ip));190 tracy.addText(struct_ty.containerTypeName(ip).fqn.toSlice(ip));
191 tracy.addTextFmt("ip_index={d}", .{struct_ty.toIntern()});191 tracy.addTextFmt("ip_index={d}", .{struct_ty.toIntern()});
192192
193 assert(sema.owner.unwrap().type_layout == struct_ty.toIntern());193 assert(sema.owner.unwrap().type_layout == struct_ty.toIntern());
...@@ -207,6 +207,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -207,6 +207,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
207 .comptime_reason = undefined, // always set before using `block`207 .comptime_reason = undefined, // always set before using `block`
208 .src_base_inst = struct_obj.zir_index,208 .src_base_inst = struct_obj.zir_index,
209 .type_name_ctx = struct_obj.name,209 .type_name_ctx = struct_obj.name,
210 .type_fqn_ctx = struct_obj.fqn,
210 };211 };
211 defer block.instructions.deinit(gpa);212 defer block.instructions.deinit(gpa);
212213
...@@ -613,7 +614,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -613,7 +614,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
613614
614 const tracy = trace(@src());615 const tracy = trace(@src());
615 defer tracy.end();616 defer tracy.end();
616 tracy.addText(struct_ty.containerTypeName(ip).toSlice(ip));617 tracy.addText(struct_ty.containerTypeName(ip).fqn.toSlice(ip));
617 tracy.addTextFmt("ip_index={d}", .{struct_ty.toIntern()});618 tracy.addTextFmt("ip_index={d}", .{struct_ty.toIntern()});
618619
619 assert(sema.owner.unwrap().struct_defaults == struct_ty.toIntern());620 assert(sema.owner.unwrap().struct_defaults == struct_ty.toIntern());
...@@ -653,6 +654,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -653,6 +654,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
653 .comptime_reason = undefined, // always set before using `block`654 .comptime_reason = undefined, // always set before using `block`
654 .src_base_inst = struct_obj.zir_index,655 .src_base_inst = struct_obj.zir_index,
655 .type_name_ctx = struct_obj.name,656 .type_name_ctx = struct_obj.name,
657 .type_fqn_ctx = struct_obj.fqn,
656 };658 };
657 defer block.instructions.deinit(gpa);659 defer block.instructions.deinit(gpa);
658660
...@@ -727,7 +729,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -727,7 +729,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
727729
728 const tracy = trace(@src());730 const tracy = trace(@src());
729 defer tracy.end();731 defer tracy.end();
730 tracy.addText(union_ty.containerTypeName(ip).toSlice(ip));732 tracy.addText(union_ty.containerTypeName(ip).fqn.toSlice(ip));
731 tracy.addTextFmt("ip_index={d}", .{union_ty.toIntern()});733 tracy.addTextFmt("ip_index={d}", .{union_ty.toIntern()});
732734
733 assert(sema.owner.unwrap().type_layout == union_ty.toIntern());735 assert(sema.owner.unwrap().type_layout == union_ty.toIntern());
...@@ -747,6 +749,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -747,6 +749,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
747 .comptime_reason = undefined, // always set before using `block`749 .comptime_reason = undefined, // always set before using `block`
748 .src_base_inst = union_obj.zir_index,750 .src_base_inst = union_obj.zir_index,
749 .type_name_ctx = union_obj.name,751 .type_name_ctx = union_obj.name,
752 .type_fqn_ctx = union_obj.fqn,
750 };753 };
751 defer block.instructions.deinit(gpa);754 defer block.instructions.deinit(gpa);
752755
...@@ -801,6 +804,13 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -801,6 +804,13 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
801 "@typeInfo({f}).@\"union\".tag_type.?",804 "@typeInfo({f}).@\"union\".tag_type.?",
802 .{union_obj.name.fmt(ip)},805 .{union_obj.name.fmt(ip)},
803 .no_embedded_nulls,806 .no_embedded_nulls,
807 ), try ip.getOrPutStringFmt(
808 gpa,
809 io,
810 pt.tid,
811 "@typeInfo({f}).@\"union\".tag_type.?",
812 .{union_obj.fqn.fmt(ip)},
813 .no_embedded_nulls,
804 ), .none);814 ), .none);
805 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{815 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
806 .parent = union_obj.namespace.toOptional(),816 .parent = union_obj.namespace.toOptional(),
...@@ -1221,7 +1231,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {...@@ -1221,7 +1231,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {
12211231
1222 const tracy = trace(@src());1232 const tracy = trace(@src());
1223 defer tracy.end();1233 defer tracy.end();
1224 tracy.addText(enum_ty.containerTypeName(ip).toSlice(ip));1234 tracy.addText(enum_ty.containerTypeName(ip).fqn.toSlice(ip));
1225 tracy.addTextFmt("ip_index={d}", .{enum_ty.toIntern()});1235 tracy.addTextFmt("ip_index={d}", .{enum_ty.toIntern()});
12261236
1227 assert(sema.owner.unwrap().type_layout == enum_ty.toIntern());1237 assert(sema.owner.unwrap().type_layout == enum_ty.toIntern());
...@@ -1248,6 +1258,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {...@@ -1248,6 +1258,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {
1248 .comptime_reason = undefined, // always set before using `block`1258 .comptime_reason = undefined, // always set before using `block`
1249 .src_base_inst = tracked_inst,1259 .src_base_inst = tracked_inst,
1250 .type_name_ctx = enum_obj.name,1260 .type_name_ctx = enum_obj.name,
1261 .type_fqn_ctx = enum_obj.fqn,
1251 };1262 };
1252 defer block.instructions.deinit(gpa);1263 defer block.instructions.deinit(gpa);
12531264
src/Type.zig+48-25
...@@ -109,6 +109,20 @@ pub const Class = enum(u3) {...@@ -109,6 +109,20 @@ pub const Class = enum(u3) {
109 /// Then, aggregates containing fully-comptime types may themselves be either fully-comptime or109 /// Then, aggregates containing fully-comptime types may themselves be either fully-comptime or
110 /// partially-comptime; see the doc comment on `.partially_comptime` for details.110 /// partially-comptime; see the doc comment on `.partially_comptime` for details.
111 fully_comptime,111 fully_comptime,
112
113 pub fn hasRuntimeBits(class: Class) bool {
114 return switch (class) {
115 .no_possible_value, .one_possible_value, .fully_comptime => false,
116 .runtime, .partially_comptime => true,
117 };
118 }
119
120 pub fn comptimeOnly(class: Class) bool {
121 return switch (class) {
122 .no_possible_value, .one_possible_value, .runtime => false,
123 .partially_comptime, .fully_comptime => true,
124 };
125 }
112};126};
113127
114/// Returns the `Class` for the type `ty`. Asserts that the layout of `ty` is resolved.128/// Returns the `Class` for the type `ty`. Asserts that the layout of `ty` is resolved.
...@@ -593,8 +607,8 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari...@@ -593,8 +607,8 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari
593 .generic_poison => unreachable,607 .generic_poison => unreachable,
594 },608 },
595 .struct_type => {609 .struct_type => {
596 const name = ip.loadStructType(ty.toIntern()).name;610 const fqn = ip.loadStructType(ty.toIntern()).fqn;
597 try writer.print("{f}", .{name.fmt(ip)});611 try writer.print("{f}", .{fqn.fmt(ip)});
598 },612 },
599 .tuple_type => |tuple| {613 .tuple_type => |tuple| {
600 if (tuple.types.len == 0) {614 if (tuple.types.len == 0) {
...@@ -611,16 +625,16 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari...@@ -611,16 +625,16 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari
611 },625 },
612626
613 .union_type => {627 .union_type => {
614 const name = ip.loadUnionType(ty.toIntern()).name;628 const fqn = ip.loadUnionType(ty.toIntern()).fqn;
615 try writer.print("{f}", .{name.fmt(ip)});629 try writer.print("{f}", .{fqn.fmt(ip)});
616 },630 },
617 .opaque_type => {631 .opaque_type => {
618 const name = ip.loadOpaqueType(ty.toIntern()).name;632 const fqn = ip.loadOpaqueType(ty.toIntern()).fqn;
619 try writer.print("{f}", .{name.fmt(ip)});633 try writer.print("{f}", .{fqn.fmt(ip)});
620 },634 },
621 .enum_type => {635 .enum_type => {
622 const name = ip.loadEnumType(ty.toIntern()).name;636 const fqn = ip.loadEnumType(ty.toIntern()).fqn;
623 try writer.print("{f}", .{name.fmt(ip)});637 try writer.print("{f}", .{fqn.fmt(ip)});
624 },638 },
625 .spirv_type => {639 .spirv_type => {
626 const info = ip.loadSpirvType(ty.toIntern());640 const info = ip.loadSpirvType(ty.toIntern());
...@@ -761,10 +775,7 @@ pub fn toValue(self: Type) Value {...@@ -761,10 +775,7 @@ pub fn toValue(self: Type) Value {
761///775///
762/// * All other types contain some runtime state, so have runtime bits and a non-zero ABI size.776/// * All other types contain some runtime state, so have runtime bits and a non-zero ABI size.
763pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {777pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
764 return switch (ty.classify(zcu)) {778 return ty.classify(zcu).hasRuntimeBits();
765 .no_possible_value, .one_possible_value, .fully_comptime => false,
766 .runtime, .partially_comptime => true,
767 };
768}779}
769780
770/// Returns `true` iff the memory layout of `ty` is defined by the Zig language specification.781/// Returns `true` iff the memory layout of `ty` is defined by the Zig language specification.
...@@ -2195,10 +2206,7 @@ pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value {...@@ -2195,10 +2206,7 @@ pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value {
2195pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {2206pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {
2196 if (ty.toIntern() == .generic_poison_type) return false;2207 if (ty.toIntern() == .generic_poison_type) return false;
2197 if (ty.zigTypeTag(zcu) == .error_union and ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) return false;2208 if (ty.zigTypeTag(zcu) == .error_union and ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) return false;
2198 return switch (ty.classify(zcu)) {2209 return ty.classify(zcu).comptimeOnly();
2199 .no_possible_value, .one_possible_value, .runtime => false,
2200 .partially_comptime, .fully_comptime => true,
2201 };
2202}2210}
22032211
2204pub fn isVector(ty: Type, zcu: *const Zcu) bool {2212pub fn isVector(ty: Type, zcu: *const Zcu) bool {
...@@ -2685,8 +2693,8 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {...@@ -2685,8 +2693,8 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
2685 };2693 };
2686 const inst = zir.instructions.get(@backingInt(info.inst));2694 const inst = zir.instructions.get(@backingInt(info.inst));
2687 return switch (inst.tag) {2695 return switch (inst.tag) {
2688 .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_line,2696 .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.src_line,
2689 .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_line,2697 .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.src_line,
2690 .extended => switch (inst.data.extended.opcode) {2698 .extended => switch (inst.data.extended.opcode) {
2691 .struct_decl => zir.getStructDecl(info.inst).src_line,2699 .struct_decl => zir.getStructDecl(info.inst).src_line,
2692 .union_decl => zir.getUnionDecl(info.inst).src_line,2700 .union_decl => zir.getUnionDecl(info.inst).src_line,
...@@ -3012,14 +3020,29 @@ pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator...@@ -3012,14 +3020,29 @@ pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator
3012 return pt.ptrType(field_ptr_info);3020 return pt.ptrType(field_ptr_info);
3013}3021}
30143022
3015pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTerminatedString {3023pub fn containerTypeName(ty: Type, ip: *const InternPool) struct {
3016 return switch (ip.indexToKey(ty.toIntern())) {3024 name: InternPool.NullTerminatedString,
3017 .struct_type => ip.loadStructType(ty.toIntern()).name,3025 fqn: InternPool.NullTerminatedString,
3018 .union_type => ip.loadUnionType(ty.toIntern()).name,3026} {
3019 .enum_type => ip.loadEnumType(ty.toIntern()).name,3027 switch (ip.indexToKey(ty.toIntern())) {
3020 .opaque_type => ip.loadOpaqueType(ty.toIntern()).name,3028 .struct_type => {
3029 const loaded_struct = ip.loadStructType(ty.toIntern());
3030 return .{ .name = loaded_struct.name, .fqn = loaded_struct.fqn };
3031 },
3032 .union_type => {
3033 const loaded_union = ip.loadUnionType(ty.toIntern());
3034 return .{ .name = loaded_union.name, .fqn = loaded_union.fqn };
3035 },
3036 .enum_type => {
3037 const loaded_enum = ip.loadEnumType(ty.toIntern());
3038 return .{ .name = loaded_enum.name, .fqn = loaded_enum.fqn };
3039 },
3040 .opaque_type => {
3041 const loaded_opaque = ip.loadOpaqueType(ty.toIntern());
3042 return .{ .name = loaded_opaque.name, .fqn = loaded_opaque.fqn };
3043 },
3021 else => unreachable,3044 else => unreachable,
3022 };3045 }
3023}3046}
30243047
3025pub fn destructurable(ty: Type, zcu: *const Zcu) bool {3048pub fn destructurable(ty: Type, zcu: *const Zcu) bool {
src/Zcu.zig+121-81
...@@ -348,6 +348,9 @@ codegen_task_pool: CodegenTaskPool,...@@ -348,6 +348,9 @@ codegen_task_pool: CodegenTaskPool,
348348
349generation: u32 = 0,349generation: u32 = 0,
350350
351/// Only access from the Sema thread.
352anon_name_counter: u32,
353
351pub const DependencyReason = struct {354pub const DependencyReason = struct {
352 src: LazySrcLoc,355 src: LazySrcLoc,
353 /// Only populated if this is for a `.type_layout` unit.356 /// Only populated if this is for a `.type_layout` unit.
...@@ -944,9 +947,9 @@ pub const Namespace = struct {...@@ -944,9 +947,9 @@ pub const Namespace = struct {
944 tid: Zcu.PerThread.Id,947 tid: Zcu.PerThread.Id,
945 name: InternPool.NullTerminatedString,948 name: InternPool.NullTerminatedString,
946 ) !InternPool.NullTerminatedString {949 ) !InternPool.NullTerminatedString {
947 const ns_name = Type.fromInterned(ns.owner_type).containerTypeName(ip);950 const ns_fqn = Type.fromInterned(ns.owner_type).containerTypeName(ip).fqn;
948 if (name == .empty) return ns_name;951 if (name == .empty) return ns_fqn;
949 return ip.getOrPutStringFmt(gpa, io, tid, "{f}.{f}", .{ ns_name.fmt(ip), name.fmt(ip) }, .no_embedded_nulls);952 return ip.getOrPutStringFmt(gpa, io, tid, "{f}.{f}", .{ ns_fqn.fmt(ip), name.fmt(ip) }, .no_embedded_nulls);
950 }953 }
951};954};
952955
...@@ -4234,7 +4237,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana...@@ -4234,7 +4237,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
4234 const referencer = types.values()[type_idx];4237 const referencer = types.values()[type_idx];
4235 type_idx += 1;4238 type_idx += 1;
42364239
4237 refs_log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)});4240 refs_log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip)});
42384241
4239 // Queue any decls within this type which would be automatically analyzed.4242 // Queue any decls within this type which would be automatically analyzed.
4240 // Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`.4243 // Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`.
...@@ -4245,7 +4248,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana...@@ -4245,7 +4248,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
4245 const gop = try units.getOrPut(gpa, unit);4248 const gop = try units.getOrPut(gpa, unit);
4246 if (!gop.found_existing) {4249 if (!gop.found_existing) {
4247 refs_log.debug("type '{f}': ref comptime %{}", .{4250 refs_log.debug("type '{f}': ref comptime %{}", .{
4248 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),4251 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip),
4249 @backingInt(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue),4252 @backingInt(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue),
4250 });4253 });
4251 gop.value_ptr.* = referencer;4254 gop.value_ptr.* = referencer;
...@@ -4279,7 +4282,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana...@@ -4279,7 +4282,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
4279 const gop = try units.getOrPut(gpa, .wrap(.{ .nav_val = nav_id }));4282 const gop = try units.getOrPut(gpa, .wrap(.{ .nav_val = nav_id }));
4280 if (!gop.found_existing) {4283 if (!gop.found_existing) {
4281 refs_log.debug("type '{f}': ref test %{}", .{4284 refs_log.debug("type '{f}': ref test %{}", .{
4282 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),4285 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip),
4283 @backingInt(inst_info.inst),4286 @backingInt(inst_info.inst),
4284 });4287 });
4285 gop.value_ptr.* = referencer;4288 gop.value_ptr.* = referencer;
...@@ -4302,7 +4305,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana...@@ -4302,7 +4305,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
4302 const gop = try units.getOrPut(gpa, unit);4305 const gop = try units.getOrPut(gpa, unit);
4303 if (!gop.found_existing) {4306 if (!gop.found_existing) {
4304 refs_log.debug("type '{f}': ref named %{}", .{4307 refs_log.debug("type '{f}': ref named %{}", .{
4305 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),4308 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip),
4306 @backingInt(inst_info.inst),4309 @backingInt(inst_info.inst),
4307 });4310 });
4308 gop.value_ptr.* = referencer;4311 gop.value_ptr.* = referencer;
...@@ -4319,7 +4322,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana...@@ -4319,7 +4322,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
4319 const gop = try units.getOrPut(gpa, unit);4322 const gop = try units.getOrPut(gpa, unit);
4320 if (!gop.found_existing) {4323 if (!gop.found_existing) {
4321 refs_log.debug("type '{f}': ref named %{}", .{4324 refs_log.debug("type '{f}': ref named %{}", .{
4322 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),4325 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip),
4323 @backingInt(inst_info.inst),4326 @backingInt(inst_info.inst),
4324 });4327 });
4325 gop.value_ptr.* = referencer;4328 gop.value_ptr.* = referencer;
...@@ -4382,7 +4385,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana...@@ -4382,7 +4385,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
4382 if (!gop.found_existing) {4385 if (!gop.found_existing) {
4383 refs_log.debug("unit '{f}': ref type '{f}'", .{4386 refs_log.debug("unit '{f}': ref type '{f}'", .{
4384 zcu.fmtAnalUnit(unit),4387 zcu.fmtAnalUnit(unit),
4385 Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip),4388 Type.fromInterned(ref.referenced).containerTypeName(ip).fqn.fmt(ip),
4386 });4389 });
4387 gop.value_ptr.* = .{4390 gop.value_ptr.* = .{
4388 .referencer = unit,4391 .referencer = unit,
...@@ -4495,7 +4498,7 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void...@@ -4495,7 +4498,7 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void
4495 }4498 }
4496 },4499 },
4497 .nav_val, .nav_ty => |nav, tag| return writer.print("{t}('{f}' [{}])", .{ tag, ip.getNav(nav).fqn.fmt(ip), @backingInt(nav) }),4500 .nav_val, .nav_ty => |nav, tag| return writer.print("{t}('{f}' [{}])", .{ tag, ip.getNav(nav).fqn.fmt(ip), @backingInt(nav) }),
4498 .type_layout, .struct_defaults => |ty, tag| return writer.print("{t}('{f}' [{}])", .{ tag, Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @backingInt(ty) }),4501 .type_layout, .struct_defaults => |ty, tag| return writer.print("{t}('{f}' [{}])", .{ tag, Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), @backingInt(ty) }),
4499 .func => |func| {4502 .func => |func| {
4500 const nav = zcu.funcInfo(func).owner_nav;4503 const nav = zcu.funcInfo(func).owner_nav;
4501 return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @backingInt(func) });4504 return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @backingInt(func) });
...@@ -4521,8 +4524,8 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void...@@ -4521,8 +4524,8 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void
4521 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) });4524 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) });
4522 },4525 },
4523 .type_layout, .struct_defaults => |ip_index, tag| {4526 .type_layout, .struct_defaults => |ip_index, tag| {
4524 const name = Type.fromInterned(ip_index).containerTypeName(ip);4527 const fqn = Type.fromInterned(ip_index).containerTypeName(ip).fqn;
4525 return writer.print("{t}('{f}')", .{ tag, name.fmt(ip) });4528 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) });
4526 },4529 },
4527 .func_ies => |ip_index| {4530 .func_ies => |ip_index| {
4528 const fqn = ip.getNav(ip.indexToKey(ip_index).func.owner_nav).fqn;4531 const fqn = ip.getNav(ip.indexToKey(ip_index).func.owner_nav).fqn;
...@@ -4569,13 +4572,17 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)...@@ -4569,13 +4572,17 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
4569 if (allowed_arch == target.cpu.arch) break;4572 if (allowed_arch == target.cpu.arch) break;
4570 } else return .{ .bad_arch = cc.archs() },4573 } else return .{ .bad_arch = cc.archs() },
4571 }4574 }
4572 const backend_ok = switch (backend) {4575 const backend_ok = ok: switch (backend) {
4573 .stage1 => unreachable,4576 .stage1 => unreachable,
4574 .other => unreachable,4577 .other => unreachable,
4575 _ => unreachable,4578 _ => unreachable,
45764579
4577 .stage2_llvm => @import("codegen/llvm.zig").toLlvmCallConv(cc, target) != null,4580 .stage2_llvm => {
4578 .stage2_c => ok: {4581 dev.check(.llvm_backend);
4582 break :ok @import("codegen/llvm.zig").toLlvmCallConv(cc, target) != null;
4583 },
4584 .stage2_c => {
4585 dev.check(.c_backend);
4579 if (target.cCallingConvention()) |default_c| {4586 if (target.cCallingConvention()) |default_c| {
4580 if (cc.eql(default_c)) {4587 if (cc.eql(default_c)) {
4581 break :ok true;4588 break :ok true;
...@@ -4633,81 +4640,114 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)...@@ -4633,81 +4640,114 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
4633 else => false,4640 else => false,
4634 };4641 };
4635 },4642 },
4636 .stage2_wasm => switch (cc) {4643 .stage2_wasm => {
4637 .wasm_mvp => |opts| opts.incoming_stack_alignment == null,4644 dev.check(.wasm_backend);
4638 else => false,4645 break :ok switch (cc) {
4639 },4646 .wasm_mvp => |opts| opts.incoming_stack_alignment == null,
4640 .stage2_arm => switch (cc) {4647 else => false,
4641 .arm_aapcs => |opts| opts.incoming_stack_alignment == null,4648 };
4642 .naked => true,
4643 else => false,
4644 },
4645 .stage2_x86_64 => switch (cc) {
4646 .x86_64_sysv, .x86_64_win, .naked => true, // incoming stack alignment supported
4647 else => false,
4648 },4649 },
4649 .stage2_aarch64 => switch (cc) {4650 .stage2_arm => {
4650 .aarch64_aapcs, .aarch64_aapcs_darwin, .naked => true,4651 dev.check(.arm_backend);
4651 else => false,4652 break :ok switch (cc) {
4653 .arm_aapcs => |opts| opts.incoming_stack_alignment == null,
4654 .naked => true,
4655 else => false,
4656 };
4652 },4657 },
4653 .stage2_x86 => switch (cc) {4658 .stage2_x86_64 => {
4654 .x86_sysv,4659 dev.check(.x86_64_backend);
4655 .x86_win,4660 break :ok switch (cc) {
4656 .x86_mingw,4661 .x86_64_sysv, .x86_64_win, .naked => true, // incoming stack alignment supported
4657 => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0,4662 else => false,
4658 .naked => true,4663 };
4659 else => false,
4660 },4664 },
4661 .stage2_powerpc => switch (target.cpu.arch) {4665 .stage2_aarch64 => {
4662 .powerpc, .powerpcle => switch (cc) {4666 dev.check(.aarch64_backend);
4663 .powerpc_sysv,4667 break :ok switch (cc) {
4664 .powerpc_sysv_altivec,4668 .aarch64_aapcs, .aarch64_aapcs_darwin, .naked => true,
4665 .powerpc_aix,
4666 .powerpc_aix_altivec,
4667 .naked,
4668 => true,
4669 else => false,4669 else => false,
4670 },4670 };
4671 .powerpc64, .powerpc64le => switch (cc) {4671 },
4672 .powerpc64_elf,4672 .stage2_x86 => {
4673 .powerpc64_elf_altivec,4673 dev.check(.x86_backend);
4674 .powerpc64_elf_v2,4674 break :ok switch (cc) {
4675 .naked,4675 .x86_sysv,
4676 => true,4676 .x86_win,
4677 .x86_mingw,
4678 => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0,
4679 .naked => true,
4677 else => false,4680 else => false,
4678 },4681 };
4679 else => unreachable,
4680 },4682 },
4681 .stage2_riscv64 => switch (cc) {4683 .stage2_powerpc => {
4682 .riscv64_lp64 => |opts| opts.incoming_stack_alignment == null,4684 dev.check(.powerpc_backend);
4683 .naked => true,4685 break :ok switch (target.cpu.arch) {
4684 else => false,4686 .powerpc, .powerpcle => switch (cc) {
4687 .powerpc_sysv,
4688 .powerpc_sysv_altivec,
4689 .powerpc_aix,
4690 .powerpc_aix_altivec,
4691 .naked,
4692 => true,
4693 else => false,
4694 },
4695 .powerpc64, .powerpc64le => switch (cc) {
4696 .powerpc64_elf,
4697 .powerpc64_elf_altivec,
4698 .powerpc64_elf_v2,
4699 .naked,
4700 => true,
4701 else => false,
4702 },
4703 else => unreachable,
4704 };
4685 },4705 },
4686 .stage2_sparc64 => switch (cc) {4706 .stage2_riscv64 => {
4687 .sparc64_sysv => |opts| opts.incoming_stack_alignment == null,4707 dev.check(.riscv64_backend);
4688 .naked => true,4708 break :ok switch (cc) {
4689 else => false,4709 .riscv64_lp64 => |opts| opts.incoming_stack_alignment == null,
4710 .naked => true,
4711 else => false,
4712 };
4690 },4713 },
4691 .stage2_spirv => switch (cc) {4714 .stage2_sparc64 => {
4692 .spirv_device, .spirv_kernel => true,4715 dev.check(.sparc64_backend);
4693 .spirv_fragment, .spirv_vertex => target.os.tag == .vulkan or target.os.tag == .opengl,4716 break :ok switch (cc) {
4694 .spirv_task, .spirv_mesh => target.os.tag == .vulkan,4717 .sparc64_sysv => |opts| opts.incoming_stack_alignment == null,
4695 else => false,4718 .naked => true,
4719 else => false,
4720 };
4696 },4721 },
4697 .stage2_loongarch => switch (cc) {4722 .stage2_spirv => {
4698 .loongarch64_lp64, .loongarch32_ilp32, .naked => true,4723 dev.check(.spirv_backend);
4699 else => false,4724 break :ok switch (cc) {
4725 .spirv_device, .spirv_kernel => true,
4726 .spirv_fragment, .spirv_vertex => target.os.tag == .vulkan or target.os.tag == .opengl,
4727 .spirv_task, .spirv_mesh => target.os.tag == .vulkan,
4728 else => false,
4729 };
4700 },4730 },
4701 .zsf_spork8 => switch (cc) {4731 .stage2_loongarch => {
4702 .spork8, .naked => true,4732 dev.check(.loongarch_backend);
4703 else => false,4733 break :ok switch (cc) {
4734 .loongarch64_lp64, .loongarch32_ilp32, .naked => true,
4735 else => false,
4736 };
4737 },
4738 .zsf_spork8 => {
4739 dev.check(.spork8_backend);
4740 break :ok switch (cc) {
4741 .spork8, .naked => true,
4742 else => false,
4743 };
4704 },4744 },
4705 };4745 };
4706 if (!backend_ok) return .{ .bad_backend = backend };4746 if (!backend_ok) return .{ .bad_backend = backend };
4707 return .ok;4747 return .ok;
4708}4748}
47094749
4710pub const CodegenFailError = error{4750pub const CodegenFailError = Io.Cancelable || error{
4711 /// Indicates the error message has been already stored at `Zcu.failed_codegen`.4751 /// Indicates the error message has been already stored at `Zcu.failed_codegen`.
4712 AlreadyReported,4752 AlreadyReported,
4713 OutOfMemory,4753 OutOfMemory,
...@@ -4999,7 +5039,7 @@ fn addDependencyLoopErrorLine(...@@ -4999,7 +5039,7 @@ fn addDependencyLoopErrorLine(
4999 }),5039 }),
5000 .struct_defaults => |ty| try eb.printString(5040 .struct_defaults => |ty| try eb.printString(
5001 "default field values of '{f}' depend on themselves for initialization here",5041 "default field values of '{f}' depend on themselves for initialization here",
5002 .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)},5042 .{Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip)},
5003 ),5043 ),
5004 } else switch (dep_node.unit.unwrap()) {5044 } else switch (dep_node.unit.unwrap()) {
5005 .@"comptime" => unreachable, // cannot be involved in a dependency loop5045 .@"comptime" => unreachable, // cannot be involved in a dependency loop
...@@ -5018,12 +5058,12 @@ fn addDependencyLoopErrorLine(...@@ -5018,12 +5058,12 @@ fn addDependencyLoopErrorLine(
5018 }),5058 }),
5019 .type_layout => |ty| try eb.printString("{f} depends on type '{f}' {s}", .{5059 .type_layout => |ty| try eb.printString("{f} depends on type '{f}' {s}", .{
5020 fmt_source,5060 fmt_source,
5021 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),5061 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip),
5022 dep_node.reason.type_layout_reason.msg(),5062 dep_node.reason.type_layout_reason.msg(),
5023 }),5063 }),
5024 .struct_defaults => |ty| try eb.printString(5064 .struct_defaults => |ty| try eb.printString(
5025 "{f} uses default field values of '{f}' here",5065 "{f} uses default field values of '{f}' here",
5026 .{ fmt_source, Type.fromInterned(ty).containerTypeName(ip).fmt(ip) },5066 .{ fmt_source, Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip) },
5027 ),5067 ),
5028 };5068 };
50295069
...@@ -5065,10 +5105,10 @@ fn formatDependencyLoopSourceUnit(data: FormatAnalUnit, w: *Io.Writer) Io.Writer...@@ -5065,10 +5105,10 @@ fn formatDependencyLoopSourceUnit(data: FormatAnalUnit, w: *Io.Writer) Io.Writer
5065 else => try w.writeAll("'std.lang' declarations"),5105 else => try w.writeAll("'std.lang' declarations"),
5066 },5106 },
5067 .type_layout => |ty| try w.print("type '{f}'", .{5107 .type_layout => |ty| try w.print("type '{f}'", .{
5068 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),5108 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip),
5069 }),5109 }),
5070 .struct_defaults => |ty| try w.print("default field value of '{f}'", .{5110 .struct_defaults => |ty| try w.print("default field value of '{f}'", .{
5071 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),5111 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip),
5072 }),5112 }),
5073 .func => |func| try w.print("function '{f}'", .{5113 .func => |func| try w.print("function '{f}'", .{
5074 ip.getNav(zcu.funcInfo(func).owner_nav).fqn.fmt(ip),5114 ip.getNav(zcu.funcInfo(func).owner_nav).fqn.fmt(ip),
...@@ -5118,7 +5158,7 @@ pub fn populateReferenceTrace(...@@ -5118,7 +5158,7 @@ pub fn populateReferenceTrace(
5118 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {5158 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {
5119 .@"comptime" => "comptime",5159 .@"comptime" => "comptime",
5120 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),5160 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
5121 .type_layout, .struct_defaults => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),5161 .type_layout, .struct_defaults => |ty| Type.fromInterned(ty).containerTypeName(ip).fqn.toSlice(ip),
5122 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),5162 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
5123 .memoized_state => null,5163 .memoized_state => null,
5124 };5164 };
...@@ -5240,7 +5280,7 @@ pub const CodegenTaskPool = struct {...@@ -5240,7 +5280,7 @@ pub const CodegenTaskPool = struct {
5240 /// memory on AIR/MIR, we see a limit of around 10 MiB of AIR in-flight.5280 /// memory on AIR/MIR, we see a limit of around 10 MiB of AIR in-flight.
5241 const max_air_bytes_in_flight = 10 * 1024 * 1024;5281 const max_air_bytes_in_flight = 10 * 1024 * 1024;
52425282
5243 const max_funcs_in_flight = @import("link.zig").Queue.buffer_size;5283 const max_funcs_in_flight = link.Queue.buffer_size;
52445284
5245 available_air_bytes: u32,5285 available_air_bytes: u32,
52465286
src/Zcu/PerThread.zig+75-24
...@@ -258,6 +258,8 @@ pub fn update(...@@ -258,6 +258,8 @@ pub fn update(
258 return;258 return;
259 }259 }
260260
261 try comp.link_queue.enqueueZcu(comp, pt.tid, .files_ready);
262
261 if (comp.config.incremental) {263 if (comp.config.incremental) {
262 const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);264 const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);
263 defer update_zir_refs_node.end();265 defer update_zir_refs_node.end();
...@@ -859,25 +861,63 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void {...@@ -859,25 +861,63 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void {
859 log.debug("tracking failed for %{d}", .{old_inst});861 log.debug("tracking failed for %{d}", .{old_inst});
860 tracked_inst.inst = .lost;862 tracked_inst.inst = .lost;
861 try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index });863 try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index });
864 try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .lost_tracking = tracked_inst_index });
862 continue;865 continue;
863 };866 };
864 tracked_inst.inst = InternPool.TrackedInst.MaybeLost.ZirIndex.wrap(new_inst);867 tracked_inst.inst = .wrap(new_inst);
865868
866 const old_zir = file.prev_zir.?.*;869 const old_zir = file.prev_zir.?.*;
867 const new_zir = file.zir.?;
868 const old_tag = old_zir.instructions.items(.tag)[@backingInt(old_inst)];870 const old_tag = old_zir.instructions.items(.tag)[@backingInt(old_inst)];
869 const old_data = old_zir.instructions.items(.data)[@backingInt(old_inst)];871 const old_data = old_zir.instructions.items(.data)[@backingInt(old_inst)];
870872
871 switch (old_tag) {873 const new_zir = file.zir.?;
872 .declaration => {874 const new_data = new_zir.instructions.items(.data)[@backingInt(new_inst)];
873 const old_line = old_zir.getDeclaration(old_inst).src_line;875
874 const new_line = new_zir.getDeclaration(new_inst).src_line;876 debug_update_line_number: {
875 if (old_line != new_line) {877 const old_line, const new_line = switch (old_tag) {
876 comp.link_prog_node.increaseEstimatedTotalItems(1);878 .declaration => .{
877 try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .debug_update_line_number = tracked_inst_index });879 old_zir.getDeclaration(old_inst).src_line,
878 }880 new_zir.getDeclaration(new_inst).src_line,
879 },881 },
880 else => {},882 .extended => switch (old_data.extended.opcode) {
883 .struct_decl => .{
884 old_zir.getStructDecl(old_inst).src_line,
885 new_zir.getStructDecl(new_inst).src_line,
886 },
887 .union_decl => .{
888 old_zir.getUnionDecl(old_inst).src_line,
889 new_zir.getUnionDecl(new_inst).src_line,
890 },
891 .enum_decl => .{
892 old_zir.getEnumDecl(old_inst).src_line,
893 new_zir.getEnumDecl(new_inst).src_line,
894 },
895 .opaque_decl => .{
896 old_zir.getOpaqueDecl(old_inst).src_line,
897 new_zir.getOpaqueDecl(new_inst).src_line,
898 },
899 .reify_enum => .{
900 old_zir.extraData(Zir.Inst.ReifyEnum, old_data.extended.operand).data.src_line,
901 new_zir.extraData(Zir.Inst.ReifyEnum, new_data.extended.operand).data.src_line,
902 },
903 .reify_struct => .{
904 old_zir.extraData(Zir.Inst.ReifyStruct, old_data.extended.operand).data.src_line,
905 new_zir.extraData(Zir.Inst.ReifyStruct, new_data.extended.operand).data.src_line,
906 },
907 .reify_union => .{
908 old_zir.extraData(Zir.Inst.ReifyUnion, old_data.extended.operand).data.src_line,
909 new_zir.extraData(Zir.Inst.ReifyUnion, new_data.extended.operand).data.src_line,
910 },
911 else => break :debug_update_line_number,
912 },
913 else => break :debug_update_line_number,
914 };
915 if (old_line == new_line) break :debug_update_line_number;
916 comp.link_prog_node.increaseEstimatedTotalItems(1);
917 try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .debug_update_line_number = .{
918 .inst = tracked_inst_index,
919 .line = new_line,
920 } });
881 }921 }
882922
883 if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {923 if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {
...@@ -979,7 +1019,7 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void {...@@ -979,7 +1019,7 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void {
979/// Ensures that `zcu.fileRootType` on this `file_index` is populated (not `.none`). This implies1019/// Ensures that `zcu.fileRootType` on this `file_index` is populated (not `.none`). This implies
980/// that the file's namespace is scanned, discovering declarations.1020/// that the file's namespace is scanned, discovering declarations.
981///1021///
982/// Typical Zig compilations begin by claling this function on the root source file of the standard1022/// Typical Zig compilations begin by calling this function on the root source file of the standard
983/// library, `lib/std/std.zig`. The resulting namespace scan discovers a `comptime` declaration in1023/// library, `lib/std/std.zig`. The resulting namespace scan discovers a `comptime` declaration in
984/// that file, which is queued for analysis, and everything goes from there.1024/// that file, which is queued for analysis, and everything goes from there.
985pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Allocator.Error || Io.Cancelable)!void {1025pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Allocator.Error || Io.Cancelable)!void {
...@@ -1020,7 +1060,12 @@ pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloc...@@ -1020,7 +1060,12 @@ pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloc
1020 };1060 };
1021 errdefer wip.cancel(ip, pt.tid);1061 errdefer wip.cancel(ip, pt.tid);
10221062
1023 wip.setName(ip, try file.internFullyQualifiedName(pt), .none);1063 wip.setName(
1064 ip,
1065 try ip.getOrPutString(gpa, io, pt.tid, std.fs.path.stem(file.sub_file_path), .no_embedded_nulls),
1066 try file.internFullyQualifiedName(pt),
1067 .none,
1068 );
1024 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{1069 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
1025 .parent = .none,1070 .parent = .none,
1026 .owner_type = wip.index,1071 .owner_type = wip.index,
...@@ -1261,6 +1306,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu...@@ -1261,6 +1306,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
1261 // The comptime unit declares on the source of the corresponding `comptime` declaration.1306 // The comptime unit declares on the source of the corresponding `comptime` declaration.
1262 try sema.declareDependency(.{ .src_hash = comptime_unit.zir_index });1307 try sema.declareDependency(.{ .src_hash = comptime_unit.zir_index });
12631308
1309 const parent_ns = Type.fromInterned(zcu.namespacePtr(comptime_unit.namespace).owner_type).containerTypeName(ip);
1264 var block: Sema.Block = .{1310 var block: Sema.Block = .{
1265 .parent = null,1311 .parent = null,
1266 .sema = &sema,1312 .sema = &sema,
...@@ -1276,7 +1322,10 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu...@@ -1276,7 +1322,10 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
1276 } },1322 } },
1277 .src_base_inst = comptime_unit.zir_index,1323 .src_base_inst = comptime_unit.zir_index,
1278 .type_name_ctx = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.comptime", .{1324 .type_name_ctx = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.comptime", .{
1279 Type.fromInterned(zcu.namespacePtr(comptime_unit.namespace).owner_type).containerTypeName(ip).fmt(ip),1325 parent_ns.name.fmt(ip),
1326 }, .no_embedded_nulls),
1327 .type_fqn_ctx = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.comptime", .{
1328 parent_ns.fqn.fmt(ip),
1280 }, .no_embedded_nulls),1329 }, .no_embedded_nulls),
1281 };1330 };
1282 defer block.instructions.deinit(gpa);1331 defer block.instructions.deinit(gpa);
...@@ -1352,7 +1401,7 @@ pub fn ensureTypeLayoutUpToDate(...@@ -1352,7 +1401,7 @@ pub fn ensureTypeLayoutUpToDate(
1352 info.deps.clearRetainingCapacity();1401 info.deps.clearRetainingCapacity();
1353 }1402 }
13541403
1355 const unit_tracking = zcu.trackUnitSema(ty.containerTypeName(ip).toSlice(ip), null);1404 const unit_tracking = zcu.trackUnitSema(ty.containerTypeName(ip).fqn.toSlice(ip), null);
1356 defer unit_tracking.end(zcu);1405 defer unit_tracking.end(zcu);
13571406
1358 try zcu.analysis_in_progress.put(gpa, anal_unit, reason);1407 try zcu.analysis_in_progress.put(gpa, anal_unit, reason);
...@@ -1464,7 +1513,7 @@ pub fn ensureStructDefaultsUpToDate(...@@ -1464,7 +1513,7 @@ pub fn ensureStructDefaultsUpToDate(
1464 info.deps.clearRetainingCapacity();1513 info.deps.clearRetainingCapacity();
1465 }1514 }
14661515
1467 const unit_tracking = zcu.trackUnitSema(ty.containerTypeName(ip).toSlice(ip), null);1516 const unit_tracking = zcu.trackUnitSema(ty.containerTypeName(ip).fqn.toSlice(ip), null);
1468 defer unit_tracking.end(zcu);1517 defer unit_tracking.end(zcu);
14691518
1470 try zcu.analysis_in_progress.put(gpa, anal_unit, reason);1519 try zcu.analysis_in_progress.put(gpa, anal_unit, reason);
...@@ -1673,7 +1722,8 @@ fn analyzeNavVal(...@@ -1673,7 +1722,8 @@ fn analyzeNavVal(
1673 .inlining = null,1722 .inlining = null,
1674 .comptime_reason = undefined, // set below1723 .comptime_reason = undefined, // set below
1675 .src_base_inst = old_nav.analysis.?.zir_index,1724 .src_base_inst = old_nav.analysis.?.zir_index,
1676 .type_name_ctx = old_nav.fqn,1725 .type_name_ctx = old_nav.name,
1726 .type_fqn_ctx = old_nav.fqn,
1677 };1727 };
1678 defer block.instructions.deinit(gpa);1728 defer block.instructions.deinit(gpa);
16791729
...@@ -2042,7 +2092,8 @@ fn analyzeNavType(...@@ -2042,7 +2092,8 @@ fn analyzeNavType(
2042 .inlining = null,2092 .inlining = null,
2043 .comptime_reason = undefined, // set below2093 .comptime_reason = undefined, // set below
2044 .src_base_inst = old_nav.analysis.?.zir_index,2094 .src_base_inst = old_nav.analysis.?.zir_index,
2045 .type_name_ctx = old_nav.fqn,2095 .type_name_ctx = old_nav.name,
2096 .type_fqn_ctx = old_nav.fqn,
2046 };2097 };
2047 defer block.instructions.deinit(gpa);2098 defer block.instructions.deinit(gpa);
20482099
...@@ -2983,11 +3034,11 @@ pub fn scanNamespace(...@@ -2983,11 +3034,11 @@ pub fn scanNamespace(
29833034
2984 const tracy_trace = trace(@src());3035 const tracy_trace = trace(@src());
2985 defer tracy_trace.end();3036 defer tracy_trace.end();
2986 tracy_trace.addText(Type.fromInterned(namespace.owner_type).containerTypeName(ip).toSlice(ip));3037 tracy_trace.addText(Type.fromInterned(namespace.owner_type).containerTypeName(ip).fqn.toSlice(ip));
2987 tracy_trace.addTextFmt("type_ip_index={d}", .{namespace.owner_type});3038 tracy_trace.addTextFmt("type_ip_index={d}", .{namespace.owner_type});
29883039
2989 const tracked_unit = zcu.trackUnitSema(3040 const tracked_unit = zcu.trackUnitSema(
2990 Type.fromInterned(namespace.owner_type).containerTypeName(ip).toSlice(ip),3041 Type.fromInterned(namespace.owner_type).containerTypeName(ip).fqn.toSlice(ip),
2991 null,3042 null,
2992 );3043 );
2993 defer tracked_unit.end(zcu);3044 defer tracked_unit.end(zcu);
...@@ -3309,7 +3360,8 @@ fn analyzeFuncBodyInner(...@@ -3309,7 +3360,8 @@ fn analyzeFuncBodyInner(
3309 .inlining = null,3360 .inlining = null,
3310 .comptime_reason = null,3361 .comptime_reason = null,
3311 .src_base_inst = decl_analysis.zir_index,3362 .src_base_inst = decl_analysis.zir_index,
3312 .type_name_ctx = func_nav.fqn,3363 .type_name_ctx = func_nav.name,
3364 .type_fqn_ctx = func_nav.fqn,
3313 };3365 };
3314 defer inner_block.instructions.deinit(gpa);3366 defer inner_block.instructions.deinit(gpa);
33153367
...@@ -4409,8 +4461,7 @@ pub fn runCodegen(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) Ru...@@ -4409,8 +4461,7 @@ pub fn runCodegen(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) Ru
4409 comp.config.use_llvm,4461 comp.config.use_llvm,
4410 )) {4462 )) {
4411 else => unreachable, // assertion failure4463 else => unreachable, // assertion failure
4412 .stage2_llvm,4464 .stage2_llvm => {},
4413 => {},
4414 },4465 },
4415 error.Canceled => |e| return e,4466 error.Canceled => |e| return e,
4416 }4467 }
src/codegen.zig+7-9
...@@ -196,7 +196,7 @@ pub fn emitFunction(...@@ -196,7 +196,7 @@ pub fn emitFunction(
196 any_mir: *const AnyMir,196 any_mir: *const AnyMir,
197 w: *std.Io.Writer,197 w: *std.Io.Writer,
198 debug_output: link.File.DebugInfoOutput,198 debug_output: link.File.DebugInfoOutput,
199) (Error || std.Io.Writer.Error)!void {199) link.EmitError!void {
200 const zcu = pt.zcu;200 const zcu = pt.zcu;
201 const func = zcu.funcInfo(func_index);201 const func = zcu.funcInfo(func_index);
202 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;202 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
...@@ -228,7 +228,7 @@ pub fn generateLazyFunction(...@@ -228,7 +228,7 @@ pub fn generateLazyFunction(
228 atom_id: link.File.AtomId,228 atom_id: link.File.AtomId,
229 w: *std.Io.Writer,229 w: *std.Io.Writer,
230 debug_output: link.File.DebugInfoOutput,230 debug_output: link.File.DebugInfoOutput,
231) (Error || std.Io.Writer.Error)!void {231) link.EmitError!void {
232 const zcu = pt.zcu;232 const zcu = pt.zcu;
233 const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index|233 const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index|
234 &zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result234 &zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result
...@@ -252,7 +252,7 @@ pub fn generateLazySymbol(...@@ -252,7 +252,7 @@ pub fn generateLazySymbol(
252 w: *std.Io.Writer,252 w: *std.Io.Writer,
253 debug_output: link.File.DebugInfoOutput,253 debug_output: link.File.DebugInfoOutput,
254 reloc_parent: link.File.RelocInfo.Parent,254 reloc_parent: link.File.RelocInfo.Parent,
255) (Error || std.Io.Writer.Error)!void {255) link.EmitError!void {
256 const tracy = trace(@src());256 const tracy = trace(@src());
257 defer tracy.end();257 defer tracy.end();
258 tracy.addTextFmt("{t}, {f}", .{ lazy_sym.kind, Type.fromInterned(lazy_sym.ty).fmt(pt) });258 tracy.addTextFmt("{t}, {f}", .{ lazy_sym.kind, Type.fromInterned(lazy_sym.ty).fmt(pt) });
...@@ -314,7 +314,7 @@ pub fn generateSymbol(...@@ -314,7 +314,7 @@ pub fn generateSymbol(
314 val: Value,314 val: Value,
315 w: *std.Io.Writer,315 w: *std.Io.Writer,
316 reloc_parent: link.File.RelocInfo.Parent,316 reloc_parent: link.File.RelocInfo.Parent,
317) (Error || std.Io.Writer.Error)!void {317) link.EmitError!void {
318 const tracy = trace(@src());318 const tracy = trace(@src());
319 defer tracy.end();319 defer tracy.end();
320320
...@@ -665,7 +665,7 @@ fn lowerPtr(...@@ -665,7 +665,7 @@ fn lowerPtr(
665 w: *std.Io.Writer,665 w: *std.Io.Writer,
666 reloc_parent: link.File.RelocInfo.Parent,666 reloc_parent: link.File.RelocInfo.Parent,
667 prev_offset: u64,667 prev_offset: u64,
668) (Error || std.Io.Writer.Error)!void {668) link.EmitError!void {
669 const zcu = pt.zcu;669 const zcu = pt.zcu;
670 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;670 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
671 const offset: u64 = prev_offset + ptr.byte_offset;671 const offset: u64 = prev_offset + ptr.byte_offset;
...@@ -723,7 +723,7 @@ fn lowerUavRef(...@@ -723,7 +723,7 @@ fn lowerUavRef(
723 w: *std.Io.Writer,723 w: *std.Io.Writer,
724 reloc_parent: link.File.RelocInfo.Parent,724 reloc_parent: link.File.RelocInfo.Parent,
725 offset: u64,725 offset: u64,
726) (Error || std.Io.Writer.Error)!void {726) link.EmitError!void {
727 const zcu = pt.zcu;727 const zcu = pt.zcu;
728 const ip = &zcu.intern_pool;728 const ip = &zcu.intern_pool;
729 const comp = lf.comp;729 const comp = lf.comp;
...@@ -744,7 +744,6 @@ fn lowerUavRef(...@@ -744,7 +744,6 @@ fn lowerUavRef(
744 .c => unreachable,744 .c => unreachable,
745 .spirv => unreachable,745 .spirv => unreachable,
746 .wasm => {746 .wasm => {
747 dev.check(link.File.Tag.wasm.devFeature());
748 const wasm = lf.cast(.wasm).?;747 const wasm = lf.cast(.wasm).?;
749 assert(reloc_parent == .none);748 assert(reloc_parent == .none);
750 try wasm.addUavReloc(w.end, uav.val, uav.orig_ty, @intCast(offset));749 try wasm.addUavReloc(w.end, uav.val, uav.orig_ty, @intCast(offset));
...@@ -781,7 +780,7 @@ fn lowerNavRef(...@@ -781,7 +780,7 @@ fn lowerNavRef(
781 w: *std.Io.Writer,780 w: *std.Io.Writer,
782 reloc_parent: link.File.RelocInfo.Parent,781 reloc_parent: link.File.RelocInfo.Parent,
783 offset: u64,782 offset: u64,
784) (Error || std.Io.Writer.Error)!void {783) link.EmitError!void {
785 const zcu = pt.zcu;784 const zcu = pt.zcu;
786 const ip = &zcu.intern_pool;785 const ip = &zcu.intern_pool;
787 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;786 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
...@@ -797,7 +796,6 @@ fn lowerNavRef(...@@ -797,7 +796,6 @@ fn lowerNavRef(
797 .c => unreachable,796 .c => unreachable,
798 .spirv => unreachable,797 .spirv => unreachable,
799 .wasm => {798 .wasm => {
800 dev.check(link.File.Tag.wasm.devFeature());
801 const wasm = lf.cast(.wasm).?;799 const wasm = lf.cast(.wasm).?;
802 assert(reloc_parent == .none);800 assert(reloc_parent == .none);
803 try wasm.addNavReloc(w.end, nav_index, nav_ty, @intCast(offset));801 try wasm.addNavReloc(w.end, nav_index, nav_ty, @intCast(offset));
src/codegen/aarch64/Select.zig+5-5
...@@ -896,7 +896,7 @@ pub fn finishAnalysis(isel: *Select) !void {...@@ -896,7 +896,7 @@ pub fn finishAnalysis(isel: *Select) !void {
896 }896 }
897}897}
898898
899pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, AlreadyReported }!void {899pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void {
900 const zcu = isel.pt.zcu;900 const zcu = isel.pt.zcu;
901 const ip = &zcu.intern_pool;901 const ip = &zcu.intern_pool;
902 const gpa = zcu.gpa;902 const gpa = zcu.gpa;
...@@ -8024,7 +8024,7 @@ fn emitLiteral(isel: *Select, bytes: []const u8) !void {...@@ -8024,7 +8024,7 @@ fn emitLiteral(isel: *Select, bytes: []const u8) !void {
8024 }8024 }
8025}8025}
80268026
8027fn fail(isel: *Select, comptime format: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } {8027fn fail(isel: *Select, comptime format: []const u8, args: anytype) codegen.Error {
8028 @branchHint(.cold);8028 @branchHint(.cold);
8029 return isel.pt.zcu.codegenFail(isel.nav_index, format, args);8029 return isel.pt.zcu.codegenFail(isel.nav_index, format, args);
8030}8030}
...@@ -10618,7 +10618,7 @@ pub const Value = struct {...@@ -10618,7 +10618,7 @@ pub const Value = struct {
10618 vi: Value.Index,10618 vi: Value.Index,
10619 ra: Register.Alias,10619 ra: Register.Alias,
1062010620
10621 fn finish(mat: Value.Materialize, isel: *Select) error{ OutOfMemory, AlreadyReported }!void {10621 fn finish(mat: Value.Materialize, isel: *Select) codegen.Error!void {
10622 const live_vi = isel.live_registers.getPtr(mat.ra);10622 const live_vi = isel.live_registers.getPtr(mat.ra);
10623 assert(live_vi.* == .allocating);10623 assert(live_vi.* == .allocating);
10624 var vi = mat.vi;10624 var vi = mat.vi;
...@@ -11659,7 +11659,7 @@ fn use(isel: *Select, air_ref: Air.Inst.Ref) !Value.Index {...@@ -11659,7 +11659,7 @@ fn use(isel: *Select, air_ref: Air.Inst.Ref) !Value.Index {
11659 return vi;11659 return vi;
11660}11660}
1166111661
11662fn fill(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, AlreadyReported }!bool {11662fn fill(isel: *Select, dst_ra: Register.Alias) codegen.Error!bool {
11663 switch (dst_ra) {11663 switch (dst_ra) {
11664 else => {},11664 else => {},
11665 Register.Alias.fp, .zr, .sp, .pc, .fpcr, .fpsr, .ffr => return false,11665 Register.Alias.fp, .zr, .sp, .pc, .fpcr, .fpsr, .ffr => return false,
...@@ -11692,7 +11692,7 @@ fn fill(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, AlreadyReport...@@ -11692,7 +11692,7 @@ fn fill(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, AlreadyReport
11692 return true;11692 return true;
11693}11693}
1169411694
11695fn fillMemory(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, AlreadyReported }!bool {11695fn fillMemory(isel: *Select, dst_ra: Register.Alias) codegen.Error!bool {
11696 const dst_live_vi = isel.live_registers.getPtr(dst_ra);11696 const dst_live_vi = isel.live_registers.getPtr(dst_ra);
11697 const dst_vi = switch (dst_live_vi.*) {11697 const dst_vi = switch (dst_live_vi.*) {
11698 _ => |dst_vi| dst_vi,11698 _ => |dst_vi| dst_vi,
src/codegen/c.zig+7-7
...@@ -6,7 +6,7 @@ const log = std.log.scoped(.c);...@@ -6,7 +6,7 @@ const log = std.log.scoped(.c);
6const Allocator = mem.Allocator;6const Allocator = mem.Allocator;
7const Writer = std.Io.Writer;7const Writer = std.Io.Writer;
88
9const dev = @import("../dev.zig");9const codegen = @import("../codegen.zig");
10const link = @import("../link.zig");10const link = @import("../link.zig");
11const Zcu = @import("../Zcu.zig");11const Zcu = @import("../Zcu.zig");
12const Module = @import("../Module.zig");12const Module = @import("../Module.zig");
...@@ -24,7 +24,7 @@ const BigIntLimb = std.math.big.Limb;...@@ -24,7 +24,7 @@ const BigIntLimb = std.math.big.Limb;
24const BigInt = std.math.big.int;24const BigInt = std.math.big.int;
2525
26pub fn legalizeFeatures(_: *const std.Target) ?*const Air.Legalize.Features {26pub fn legalizeFeatures(_: *const std.Target) ?*const Air.Legalize.Features {
27 return comptime switch (dev.env.supports(.legalize)) {27 return comptime switch (@import("../dev.zig").env.supports(.legalize)) {
28 inline false, true => |supports_legalize| &.init(.{28 inline false, true => |supports_legalize| &.init(.{
29 // we don't currently ask zig1 to use safe optimization modes29 // we don't currently ask zig1 to use safe optimization modes
30 .expand_bit_cast_safe = supports_legalize,30 .expand_bit_cast_safe = supports_legalize,
...@@ -86,7 +86,7 @@ pub const Mir = struct {...@@ -86,7 +86,7 @@ pub const Mir = struct {
86 }86 }
87};87};
8888
89pub const Error = Writer.Error || Allocator.Error || error{AlreadyReported};89pub const Error = codegen.Error || Writer.Error;
9090
91pub const CType = @import("c/type.zig").CType;91pub const CType = @import("c/type.zig").CType;
9292
...@@ -2174,11 +2174,11 @@ pub fn genTagNameFn(...@@ -2174,11 +2174,11 @@ pub fn genTagNameFn(
2174 }2174 }
21752175
2176 if (!zcu.comp.config.root_strip) try w.print("/* @tagName({f}) */\n", .{2176 if (!zcu.comp.config.root_strip) try w.print("/* @tagName({f}) */\n", .{
2177 loaded_enum.name.fmt(ip),2177 loaded_enum.fqn.fmt(ip),
2178 });2178 });
2179 try w.print("static {s} zig_tagName_{f}__{d}({s} tag) {{\n", .{2179 try w.print("static {s} zig_tagName_{f}__{d}({s} tag) {{\n", .{
2180 slice_const_u8_sentinel_0_type_name,2180 slice_const_u8_sentinel_0_type_name,
2181 fmtIdentUnsolo(loaded_enum.name.toSlice(ip)),2181 fmtIdentUnsolo(loaded_enum.fqn.toSlice(ip)),
2182 @backingInt(enum_ty.toIntern()),2182 @backingInt(enum_ty.toIntern()),
2183 enum_type_name,2183 enum_type_name,
2184 });2184 });
...@@ -2251,7 +2251,7 @@ pub fn generate(...@@ -2251,7 +2251,7 @@ pub fn generate(
2251 func_index: InternPool.Index,2251 func_index: InternPool.Index,
2252 air: *const Air,2252 air: *const Air,
2253 liveness: *const ?Air.Liveness,2253 liveness: *const ?Air.Liveness,
2254) @import("../codegen.zig").Error!Mir {2254) codegen.Error!Mir {
2255 const zcu = pt.zcu;2255 const zcu = pt.zcu;
2256 const gpa = zcu.gpa;2256 const gpa = zcu.gpa;
22572257
...@@ -6666,7 +6666,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6666,7 +6666,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
6666 try f.writeCValue(w, local, .other);6666 try f.writeCValue(w, local, .other);
6667 try f.need_tag_name_funcs.put(gpa, enum_ty.toIntern(), {});6667 try f.need_tag_name_funcs.put(gpa, enum_ty.toIntern(), {});
6668 try w.print(" = zig_tagName_{f}__{d}(", .{6668 try w.print(" = zig_tagName_{f}__{d}(", .{
6669 fmtIdentUnsolo(enum_ty.containerTypeName(ip).toSlice(ip)),6669 fmtIdentUnsolo(enum_ty.containerTypeName(ip).fqn.toSlice(ip)),
6670 @backingInt(enum_ty.toIntern()),6670 @backingInt(enum_ty.toIntern()),
6671 });6671 });
6672 try f.writeCValue(w, operand, .other);6672 try f.writeCValue(w, operand, .other);
src/codegen/c/type.zig+3-3
...@@ -1140,17 +1140,17 @@ pub const CType = union(enum) {...@@ -1140,17 +1140,17 @@ pub const CType = union(enum) {
1140 try w.print("_{f}", .{fmtZigType(field_ty, zcu)});1140 try w.print("_{f}", .{fmtZigType(field_ty, zcu)});
1141 }1141 }
1142 } else {1142 } else {
1143 const name = ty.containerTypeName(ip).toSlice(ip);1143 const name = ty.containerTypeName(ip).fqn.toSlice(ip);
1144 try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});1144 try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});
1145 },1145 },
1146 .@"opaque" => if (ty.toIntern() == .anyopaque_type) {1146 .@"opaque" => if (ty.toIntern() == .anyopaque_type) {
1147 try w.writeAll("anyopaque");1147 try w.writeAll("anyopaque");
1148 } else {1148 } else {
1149 const name = ty.containerTypeName(ip).toSlice(ip);1149 const name = ty.containerTypeName(ip).fqn.toSlice(ip);
1150 try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});1150 try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});
1151 },1151 },
1152 .@"union", .@"enum" => {1152 .@"union", .@"enum" => {
1153 const name = ty.containerTypeName(ip).toSlice(ip);1153 const name = ty.containerTypeName(ip).fqn.toSlice(ip);
1154 try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});1154 try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});
1155 },1155 },
1156 }1156 }
src/codegen/llvm.zig+11-13
...@@ -10,7 +10,6 @@ const build_options = @import("build_options");...@@ -10,7 +10,6 @@ const build_options = @import("build_options");
10const Air = @import("../Air.zig");10const Air = @import("../Air.zig");
11const codegen = @import("../codegen.zig");11const codegen = @import("../codegen.zig");
12const Compilation = @import("../Compilation.zig");12const Compilation = @import("../Compilation.zig");
13const dev = @import("../dev.zig");
14const InternPool = @import("../InternPool.zig");13const InternPool = @import("../InternPool.zig");
15const link = @import("../link.zig");14const link = @import("../link.zig");
16const Module = @import("../Module.zig");15const Module = @import("../Module.zig");
...@@ -155,12 +154,11 @@ pub const Object = struct {...@@ -155,12 +154,11 @@ pub const Object = struct {
155 /// Values for `@llvm.used`.154 /// Values for `@llvm.used`.
156 used: std.ArrayList(Builder.Constant),155 used: std.ArrayList(Builder.Constant),
157156
158 pub const Ptr = if (dev.env.supports(.llvm_backend)) *Object else noreturn;157 pub const Ptr = if (@import("../dev.zig").env.supports(.llvm_backend)) *Object else noreturn;
159158
160 const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type);159 const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type);
161160
162 pub fn create(arena: Allocator, zcu: *Zcu) !Ptr {161 pub fn create(arena: Allocator, zcu: *Zcu) !Ptr {
163 dev.check(.llvm_backend);
164 const comp = zcu.comp;162 const comp = zcu.comp;
165 const gpa = comp.gpa;163 const gpa = comp.gpa;
166 const target = zcu.getTarget();164 const target = zcu.getTarget();
...@@ -348,7 +346,7 @@ pub const Object = struct {...@@ -348,7 +346,7 @@ pub const Object = struct {
348 lto: std.zig.LtoMode,346 lto: std.zig.LtoMode,
349 };347 };
350348
351 pub fn emit(o: *Object, pt: Zcu.PerThread, options: EmitOptions) error{ AlreadyReported, OutOfMemory }!void {349 pub fn emit(o: *Object, pt: Zcu.PerThread, options: EmitOptions) link.Error!void {
352 const zcu = o.zcu;350 const zcu = o.zcu;
353 const comp = zcu.comp;351 const comp = zcu.comp;
354 const io = comp.io;352 const io = comp.io;
...@@ -1141,7 +1139,7 @@ pub const Object = struct {...@@ -1141,7 +1139,7 @@ pub const Object = struct {
1141 }1139 }
1142 }1140 }
11431141
1144 fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void {1142 fn flushTypePool(o: *Object, pt: Zcu.PerThread) link.Error!void {
1145 try o.type_pool.flushPending(pt, .{ .llvm = o });1143 try o.type_pool.flushPending(pt, .{ .llvm = o });
1146 }1144 }
11471145
...@@ -1304,7 +1302,7 @@ pub const Object = struct {...@@ -1304,7 +1302,7 @@ pub const Object = struct {
1304 }, &o.builder);1302 }, &o.builder);
1305 }1303 }
13061304
1307 pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Allocator.Error!void {1305 pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) link.Error!void {
1308 _ = o.type_map.remove(ty);1306 _ = o.type_map.remove(ty);
1309 try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success);1307 try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success);
1310 if (o.named_enum_map.get(ty)) |llvm_function| {1308 if (o.named_enum_map.get(ty)) |llvm_function| {
...@@ -1431,7 +1429,7 @@ pub const Object = struct {...@@ -1431,7 +1429,7 @@ pub const Object = struct {
14311429
1432 pub fn getDebugType(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Metadata {1430 pub fn getDebugType(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Metadata {
1433 assert(!o.builder.strip);1431 assert(!o.builder.strip);
1434 const index = try o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern());1432 const index = o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern()) catch |err| return @errorCast(err);
1435 return o.debug_types.items[@backingInt(index)];1433 return o.debug_types.items[@backingInt(index)];
1436 }1434 }
14371435
...@@ -2893,7 +2891,7 @@ pub const Object = struct {...@@ -2893,7 +2891,7 @@ pub const Object = struct {
2893 }2891 }
2894 }2892 }
28952893
2896 const ty = try o.builder.opaqueType(try o.builder.string(t.containerTypeName(ip).toSlice(ip)));2894 const ty = try o.builder.opaqueType(try o.builder.string(t.containerTypeName(ip).fqn.toSlice(ip)));
2897 try o.type_map.put(o.gpa, t.toIntern(), ty);2895 try o.type_map.put(o.gpa, t.toIntern(), ty);
28982896
2899 o.builder.namedTypeSetBody(2897 o.builder.namedTypeSetBody(
...@@ -2983,7 +2981,7 @@ pub const Object = struct {...@@ -2983,7 +2981,7 @@ pub const Object = struct {
2983 };2981 };
29842982
2985 if (layout.tag_size == 0) {2983 if (layout.tag_size == 0) {
2986 const ty = try o.builder.opaqueType(try o.builder.string(t.containerTypeName(ip).toSlice(ip)));2984 const ty = try o.builder.opaqueType(try o.builder.string(t.containerTypeName(ip).fqn.toSlice(ip)));
2987 try o.type_map.put(o.gpa, t.toIntern(), ty);2985 try o.type_map.put(o.gpa, t.toIntern(), ty);
29882986
2989 o.builder.namedTypeSetBody(2987 o.builder.namedTypeSetBody(
...@@ -3011,7 +3009,7 @@ pub const Object = struct {...@@ -3011,7 +3009,7 @@ pub const Object = struct {
3011 llvm_fields_len += 1;3009 llvm_fields_len += 1;
3012 }3010 }
30133011
3014 const ty = try o.builder.opaqueType(try o.builder.string(t.containerTypeName(ip).toSlice(ip)));3012 const ty = try o.builder.opaqueType(try o.builder.string(t.containerTypeName(ip).fqn.toSlice(ip)));
3015 try o.type_map.put(o.gpa, t.toIntern(), ty);3013 try o.type_map.put(o.gpa, t.toIntern(), ty);
30163014
3017 o.builder.namedTypeSetBody(3015 o.builder.namedTypeSetBody(
...@@ -4026,7 +4024,7 @@ pub const Object = struct {...@@ -4026,7 +4024,7 @@ pub const Object = struct {
4026 // Dummy function type; `updateEnumTagNameFunction` will replace it with the correct type.4024 // Dummy function type; `updateEnumTagNameFunction` will replace it with the correct type.
4027 // TODO: change the builder API so we don't need to do this.4025 // TODO: change the builder API so we don't need to do this.
4028 try o.builder.fnType(.void, &.{}, .normal),4026 try o.builder.fnType(.void, &.{}, .normal),
4029 try o.builder.strtabStringFmt("__zig_tag_name_{f}", .{enum_ty.containerTypeName(ip).fmt(ip)}),4027 try o.builder.strtabStringFmt("__zig_tag_name_{f}", .{enum_ty.containerTypeName(ip).fqn.fmt(ip)}),
4030 toLlvmAddressSpace(.generic, zcu.getTarget()),4028 toLlvmAddressSpace(.generic, zcu.getTarget()),
4031 );4029 );
4032 gop.value_ptr.* = llvm_function;4030 gop.value_ptr.* = llvm_function;
...@@ -4108,7 +4106,7 @@ pub const Object = struct {...@@ -4108,7 +4106,7 @@ pub const Object = struct {
4108 }4106 }
41094107
4110 pub fn lazyAbiAlignment(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Alignment.Lazy {4108 pub fn lazyAbiAlignment(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Alignment.Lazy {
4111 const index = try o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern());4109 const index = o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern()) catch |err| return @errorCast(err);
4112 return o.lazy_abi_aligns.items[@backingInt(index)];4110 return o.lazy_abi_aligns.items[@backingInt(index)];
4113 }4111 }
41144112
...@@ -4123,7 +4121,7 @@ pub const Object = struct {...@@ -4123,7 +4121,7 @@ pub const Object = struct {
4123 // Dummy function type; `updateIsNamedEnumValue` will replace it with the correct type.4121 // Dummy function type; `updateIsNamedEnumValue` will replace it with the correct type.
4124 // TODO: change the builder API so we don't need to do this.4122 // TODO: change the builder API so we don't need to do this.
4125 try o.builder.fnType(.void, &.{}, .normal),4123 try o.builder.fnType(.void, &.{}, .normal),
4126 try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_ty.containerTypeName(ip).fmt(ip)}),4124 try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_ty.containerTypeName(ip).fqn.fmt(ip)}),
4127 toLlvmAddressSpace(.generic, zcu.getTarget()),4125 toLlvmAddressSpace(.generic, zcu.getTarget()),
4128 );4126 );
4129 gop.value_ptr.* = llvm_function;4127 gop.value_ptr.* = llvm_function;
src/codegen/loongarch/Select.zig+8-8
...@@ -1020,7 +1020,7 @@ pub const Value = struct {...@@ -1020,7 +1020,7 @@ pub const Value = struct {
1020 /// Defines a value with a location.1020 /// Defines a value with a location.
1021 /// Returned location must be free-ed by caller.1021 /// Returned location must be free-ed by caller.
1022 /// Extension unchanged.1022 /// Extension unchanged.
1023 fn def(vi: Value.Index, isel: *Select) error{ AlreadyReported, OutOfMemory }!?Location {1023 fn def(vi: Value.Index, isel: *Select) codegen.Error!?Location {
1024 try vi.collectDefs(isel);1024 try vi.collectDefs(isel);
1025 return vi.takeLocationMarkWritten(isel);1025 return vi.takeLocationMarkWritten(isel);
1026 }1026 }
...@@ -2046,7 +2046,7 @@ pub const Value = struct {...@@ -2046,7 +2046,7 @@ pub const Value = struct {
2046 if (!std.debug.runtime_safety) assert(@sizeOf(Mat) <= 32);2046 if (!std.debug.runtime_safety) assert(@sizeOf(Mat) <= 32);
2047 }2047 }
20482048
2049 const Error = error{ OutOfMemory, AlreadyReported };2049 const Error = codegen.Error;
20502050
2051 pub fn ra(mat: Value.Mat) Register.Alias {2051 pub fn ra(mat: Value.Mat) Register.Alias {
2052 return mat.location.register;2052 return mat.location.register;
...@@ -2296,13 +2296,13 @@ pub const Value = struct {...@@ -2296,13 +2296,13 @@ pub const Value = struct {
2296 };2296 };
2297};2297};
22982298
2299fn fail(isel: *Select, comptime format: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } {2299fn fail(isel: *Select, comptime format: []const u8, args: anytype) codegen.Error {
2300 @branchHint(.cold);2300 @branchHint(.cold);
2301 wip_mir_log.debug("codegen error: " ++ format, args);2301 wip_mir_log.debug("codegen error: " ++ format, args);
2302 return isel.pt.zcu.codegenFail(isel.nav_index, format, args);2302 return isel.pt.zcu.codegenFail(isel.nav_index, format, args);
2303}2303}
23042304
2305fn failUnimplemented(isel: *Select, comptime format: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported }!void {2305fn failUnimplemented(isel: *Select, comptime format: []const u8, args: anytype) codegen.Error!void {
2306 @branchHint(.cold);2306 @branchHint(.cold);
2307 if (debug_trap_unimplemented_code) {2307 if (debug_trap_unimplemented_code) {
2308 const gpa = isel.pt.zcu.gpa;2308 const gpa = isel.pt.zcu.gpa;
...@@ -2963,7 +2963,7 @@ pub fn verify(isel: *Select, check_values: bool) void {...@@ -2963,7 +2963,7 @@ pub fn verify(isel: *Select, check_values: bool) void {
2963 }2963 }
2964}2964}
29652965
2966pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, AlreadyReported }!void {2966pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void {
2967 const zcu = isel.pt.zcu;2967 const zcu = isel.pt.zcu;
2968 const ip = &zcu.intern_pool;2968 const ip = &zcu.intern_pool;
2969 const gpa = zcu.gpa;2969 const gpa = zcu.gpa;
...@@ -5341,7 +5341,7 @@ fn forgetReg(isel: *Select, dst_reg: Register) error{ OutOfMemory, AlreadyReport...@@ -5341,7 +5341,7 @@ fn forgetReg(isel: *Select, dst_reg: Register) error{ OutOfMemory, AlreadyReport
53415341
5342/// Frees a register by moving it to another place.5342/// Frees a register by moving it to another place.
5343/// Returns true on success, false on failure (i.e. dst_reg is locked/allocated or unallocatable).5343/// Returns true on success, false on failure (i.e. dst_reg is locked/allocated or unallocatable).
5344fn fillReg(isel: *Select, dst_reg: Register) error{ OutOfMemory, AlreadyReported }!bool {5344fn fillReg(isel: *Select, dst_reg: Register) codegen.Error!bool {
5345 if (!isRegisterAllocatable(dst_reg)) return false;5345 if (!isRegisterAllocatable(dst_reg)) return false;
5346 const dst_live_vi = isel.live_registers.getPtr(dst_reg);5346 const dst_live_vi = isel.live_registers.getPtr(dst_reg);
5347 const dst_vi = switch (dst_live_vi.*) {5347 const dst_vi = switch (dst_live_vi.*) {
...@@ -5377,7 +5377,7 @@ fn fillReg(isel: *Select, dst_reg: Register) error{ OutOfMemory, AlreadyReported...@@ -5377,7 +5377,7 @@ fn fillReg(isel: *Select, dst_reg: Register) error{ OutOfMemory, AlreadyReported
5377/// Frees a set of register. If locked is true, these registers are then locked.5377/// Frees a set of register. If locked is true, these registers are then locked.
5378/// Requires all registers to be unlocked.5378/// Requires all registers to be unlocked.
5379/// Returns true on success.5379/// Returns true on success.
5380fn fillRegsBatch(isel: *Select, regs: RegisterSet, locking: bool) error{ OutOfMemory, AlreadyReported }!void {5380fn fillRegsBatch(isel: *Select, regs: RegisterSet, locking: bool) codegen.Error!void {
5381 tracking_log.debug("batch fill: {f}", .{fmtRegisterSet(regs)});5381 tracking_log.debug("batch fill: {f}", .{fmtRegisterSet(regs)});
5382 // lock free registers5382 // lock free registers
5383 var regs_it = regs.iterator();5383 var regs_it = regs.iterator();
...@@ -5419,7 +5419,7 @@ fn fillRegsBatch(isel: *Select, regs: RegisterSet, locking: bool) error{ OutOfMe...@@ -5419,7 +5419,7 @@ fn fillRegsBatch(isel: *Select, regs: RegisterSet, locking: bool) error{ OutOfMe
54195419
5420/// Frees a register by moving it to stack.5420/// Frees a register by moving it to stack.
5421/// Returns true on success, false on failure (i.e. dst_reg is locked/allocated or unallocatable).5421/// Returns true on success, false on failure (i.e. dst_reg is locked/allocated or unallocatable).
5422fn fillRegToMemory(isel: *Select, dst_reg: Register) error{ OutOfMemory, AlreadyReported }!bool {5422fn fillRegToMemory(isel: *Select, dst_reg: Register) codegen.Error!bool {
5423 if (!isRegisterAllocatable(dst_reg)) return false;5423 if (!isRegisterAllocatable(dst_reg)) return false;
5424 const dst_live_vi = isel.live_registers.getPtr(dst_reg);5424 const dst_live_vi = isel.live_registers.getPtr(dst_reg);
5425 const dst_vi = switch (dst_live_vi.*) {5425 const dst_vi = switch (dst_live_vi.*) {
src/codegen/riscv64/CodeGen.zig+3-3
...@@ -856,7 +856,7 @@ pub fn generateLazy(...@@ -856,7 +856,7 @@ pub fn generateLazy(
856 atom_index: link.File.AtomId,856 atom_index: link.File.AtomId,
857 w: *std.Io.Writer,857 w: *std.Io.Writer,
858 debug_output: link.File.DebugInfoOutput,858 debug_output: link.File.DebugInfoOutput,
859) (codegen.Error || std.Io.Writer.Error)!void {859) link.EmitError!void {
860 _ = atom_index;860 _ = atom_index;
861 const comp = bin_file.comp;861 const comp = bin_file.comp;
862 const gpa = comp.gpa;862 const gpa = comp.gpa;
...@@ -8349,7 +8349,7 @@ fn wantSafety(func: *Func) bool {...@@ -8349,7 +8349,7 @@ fn wantSafety(func: *Func) bool {
8349 };8349 };
8350}8350}
83518351
8352fn fail(func: *const Func, comptime format: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } {8352fn fail(func: *const Func, comptime format: []const u8, args: anytype) codegen.Error {
8353 @branchHint(.cold);8353 @branchHint(.cold);
8354 const zcu = func.pt.zcu;8354 const zcu = func.pt.zcu;
8355 switch (func.owner) {8355 switch (func.owner) {
...@@ -8359,7 +8359,7 @@ fn fail(func: *const Func, comptime format: []const u8, args: anytype) error{ Ou...@@ -8359,7 +8359,7 @@ fn fail(func: *const Func, comptime format: []const u8, args: anytype) error{ Ou
8359 return error.AlreadyReported;8359 return error.AlreadyReported;
8360}8360}
83618361
8362fn failMsg(func: *const Func, msg: *ErrorMsg) error{ OutOfMemory, AlreadyReported } {8362fn failMsg(func: *const Func, msg: *ErrorMsg) codegen.Error {
8363 @branchHint(.cold);8363 @branchHint(.cold);
8364 const zcu = func.pt.zcu;8364 const zcu = func.pt.zcu;
8365 switch (func.owner) {8365 switch (func.owner) {
src/codegen/riscv64/Emit.zig+9-9
...@@ -13,7 +13,7 @@ prev_di_pc: usize,...@@ -13,7 +13,7 @@ prev_di_pc: usize,
13code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,13code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,
14relocs: std.ArrayList(Reloc) = .empty,14relocs: std.ArrayList(Reloc) = .empty,
1515
16pub const Error = Lower.Error || std.Io.Writer.Error || error{16pub const Error = Lower.Error || link.EmitError || error{
17 EmitFail,17 EmitFail,
18};18};
1919
...@@ -118,14 +118,14 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -118,14 +118,14 @@ pub fn emitMir(emit: *Emit) Error!void {
118 else => unreachable,118 else => unreachable,
119 .pseudo_dbg_prologue_end => {119 .pseudo_dbg_prologue_end => {
120 switch (emit.debug_output) {120 switch (emit.debug_output) {
121 .dwarf => |dw| {121 inline .dwarf, .dwarf2 => |dw| {
122 try dw.setPrologueEnd();122 try dw.setPrologueEnd();
123 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{123 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
124 emit.prev_di_line, emit.prev_di_column,124 emit.prev_di_line, emit.prev_di_column,
125 });125 });
126 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);126 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
127 },127 },
128 .none => {},128 .eh_frame, .none => {},
129 }129 }
130 },130 },
131 .pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine(131 .pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine(
...@@ -134,14 +134,14 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -134,14 +134,14 @@ pub fn emitMir(emit: *Emit) Error!void {
134 ),134 ),
135 .pseudo_dbg_epilogue_begin => {135 .pseudo_dbg_epilogue_begin => {
136 switch (emit.debug_output) {136 switch (emit.debug_output) {
137 .dwarf => |dw| {137 inline .dwarf, .dwarf2 => |dw| {
138 try dw.setEpilogueBegin();138 try dw.setEpilogueBegin();
139 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{139 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
140 emit.prev_di_line, emit.prev_di_column,140 emit.prev_di_line, emit.prev_di_column,
141 });141 });
142 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);142 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
143 },143 },
144 .none => {},144 .eh_frame, .none => {},
145 }145 }
146 },146 },
147 .pseudo_dead => {},147 .pseudo_dead => {},
...@@ -190,15 +190,14 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {...@@ -190,15 +190,14 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
190 const delta_pc: usize = emit.w.end - emit.prev_di_pc;190 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
191 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });191 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });
192 switch (emit.debug_output) {192 switch (emit.debug_output) {
193 .dwarf => |dw| {193 inline .dwarf, .dwarf2 => |dw| {
194 if (column != emit.prev_di_column) try dw.setColumn(column);194 if (column != emit.prev_di_column) try dw.setColumn(column);
195 if (delta_line == 0) return; // TODO: fix these edge cases.195 try dw.advanceLineAndPc(delta_line, delta_pc, false);
196 try dw.advancePCAndLine(delta_line, delta_pc);
197 emit.prev_di_line = line;196 emit.prev_di_line = line;
198 emit.prev_di_column = column;197 emit.prev_di_column = column;
199 emit.prev_di_pc = emit.w.end;198 emit.prev_di_pc = emit.w.end;
200 },199 },
201 .none => {},200 .eh_frame, .none => {},
202 }201 }
203}202}
204203
...@@ -209,6 +208,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {...@@ -209,6 +208,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {
209 };208 };
210}209}
211210
211const codegen = @import("../../codegen.zig");
212const link = @import("../../link.zig");212const link = @import("../../link.zig");
213const log = std.log.scoped(.emit);213const log = std.log.scoped(.emit);
214const mem = std.mem;214const mem = std.mem;
src/codegen/riscv64/Mir.zig+1-1
...@@ -111,7 +111,7 @@ pub fn emit(...@@ -111,7 +111,7 @@ pub fn emit(
111 atom_index: link.File.AtomId,111 atom_index: link.File.AtomId,
112 w: *std.Io.Writer,112 w: *std.Io.Writer,
113 debug_output: link.File.DebugInfoOutput,113 debug_output: link.File.DebugInfoOutput,
114) (codegen.Error || std.Io.Writer.Error)!void {114) link.EmitError!void {
115 _ = atom_index;115 _ = atom_index;
116 const zcu = pt.zcu;116 const zcu = pt.zcu;
117 const comp = zcu.comp;117 const comp = zcu.comp;
src/codegen/sparc64/CodeGen.zig+2-2
...@@ -3450,7 +3450,7 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)...@@ -3450,7 +3450,7 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
3450 }3450 }
3451}3451}
34523452
3453fn fail(self: *Self, comptime format: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } {3453fn fail(self: *Self, comptime format: []const u8, args: anytype) codegen.Error {
3454 @branchHint(.cold);3454 @branchHint(.cold);
3455 const zcu = self.pt.zcu;3455 const zcu = self.pt.zcu;
3456 const func = zcu.funcInfo(self.func_index);3456 const func = zcu.funcInfo(self.func_index);
...@@ -3458,7 +3458,7 @@ fn fail(self: *Self, comptime format: []const u8, args: anytype) error{ OutOfMem...@@ -3458,7 +3458,7 @@ fn fail(self: *Self, comptime format: []const u8, args: anytype) error{ OutOfMem
3458 return zcu.codegenFailMsg(func.owner_nav, msg);3458 return zcu.codegenFailMsg(func.owner_nav, msg);
3459}3459}
34603460
3461fn failMsg(self: *Self, msg: *ErrorMsg) error{ OutOfMemory, AlreadyReported } {3461fn failMsg(self: *Self, msg: *ErrorMsg) codegen.Error {
3462 @branchHint(.cold);3462 @branchHint(.cold);
3463 const zcu = self.pt.zcu;3463 const zcu = self.pt.zcu;
3464 const func = zcu.funcInfo(self.func_index);3464 const func = zcu.funcInfo(self.func_index);
src/codegen/sparc64/Emit.zig+9-9
...@@ -4,6 +4,7 @@...@@ -4,6 +4,7 @@
4const std = @import("std");4const std = @import("std");
5const Endian = std.lang.Endian;5const Endian = std.lang.Endian;
6const assert = std.debug.assert;6const assert = std.debug.assert;
7const codegen = @import("../../codegen.zig");
7const link = @import("../../link.zig");8const link = @import("../../link.zig");
8const Zcu = @import("../../Zcu.zig");9const Zcu = @import("../../Zcu.zig");
9const ErrorMsg = Zcu.ErrorMsg;10const ErrorMsg = Zcu.ErrorMsg;
...@@ -40,8 +41,7 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayList(M...@@ -40,8 +41,7 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayList(M
40/// instruction41/// instruction
41code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,42code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,
4243
43const InnerError = std.Io.Writer.Error || error{44const InnerError = link.EmitError || error{
44 OutOfMemory,
45 EmitFail,45 EmitFail,
46};46};
4747
...@@ -175,21 +175,21 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -175,21 +175,21 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
175175
176fn mirDebugPrologueEnd(emit: *Emit) !void {176fn mirDebugPrologueEnd(emit: *Emit) !void {
177 switch (emit.debug_output) {177 switch (emit.debug_output) {
178 .dwarf => |dbg_out| {178 inline .dwarf, .dwarf2 => |dbg_out| {
179 try dbg_out.setPrologueEnd();179 try dbg_out.setPrologueEnd();
180 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);180 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
181 },181 },
182 .none => {},182 .eh_frame, .none => {},
183 }183 }
184}184}
185185
186fn mirDebugEpilogueBegin(emit: *Emit) !void {186fn mirDebugEpilogueBegin(emit: *Emit) !void {
187 switch (emit.debug_output) {187 switch (emit.debug_output) {
188 .dwarf => |dbg_out| {188 inline .dwarf, .dwarf2 => |dbg_out| {
189 try dbg_out.setEpilogueBegin();189 try dbg_out.setEpilogueBegin();
190 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);190 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
191 },191 },
192 .none => {},192 .eh_frame, .none => {},
193 }193 }
194}194}
195195
...@@ -496,13 +496,13 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {...@@ -496,13 +496,13 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {
496 const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));496 const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));
497 const delta_pc: usize = emit.w.end - emit.prev_di_pc;497 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
498 switch (emit.debug_output) {498 switch (emit.debug_output) {
499 .dwarf => |dbg_out| {499 inline .dwarf, .dwarf2 => |dbg_out| {
500 try dbg_out.advancePCAndLine(delta_line, delta_pc);500 try dbg_out.advanceLineAndPc(delta_line, delta_pc, false);
501 emit.prev_di_line = line;501 emit.prev_di_line = line;
502 emit.prev_di_column = column;502 emit.prev_di_column = column;
503 emit.prev_di_pc = emit.w.end;503 emit.prev_di_pc = emit.w.end;
504 },504 },
505 else => {},505 .eh_frame, .none => {},
506 }506 }
507}507}
508508
src/codegen/sparc64/Mir.zig+1-1
...@@ -382,7 +382,7 @@ pub fn emit(...@@ -382,7 +382,7 @@ pub fn emit(
382 atom_index: link.File.AtomId,382 atom_index: link.File.AtomId,
383 w: *std.Io.Writer,383 w: *std.Io.Writer,
384 debug_output: link.File.DebugInfoOutput,384 debug_output: link.File.DebugInfoOutput,
385) (codegen.Error || std.Io.Writer.Error)!void {385) link.EmitError!void {
386 _ = atom_index;386 _ = atom_index;
387 const zcu = pt.zcu;387 const zcu = pt.zcu;
388 const func = zcu.funcInfo(func_index);388 const func = zcu.funcInfo(func_index);
src/codegen/spirv/CodeGen.zig+3-9
...@@ -240,10 +240,7 @@ pub fn generate(...@@ -240,10 +240,7 @@ pub fn generate(
240 };240 };
241 defer cg.deinit();241 defer cg.deinit();
242242
243 cg.genNav(true) catch |err| switch (err) {243 try cg.genNav(true);
244 error.AlreadyReported => return error.AlreadyReported,
245 error.OutOfMemory => return error.OutOfMemory,
246 };
247244
248 return cg.serializeToMir(gpa);245 return cg.serializeToMir(gpa);
249}246}
...@@ -270,10 +267,7 @@ pub fn generateNav(...@@ -270,10 +267,7 @@ pub fn generateNav(
270 };267 };
271 defer cg.deinit();268 defer cg.deinit();
272269
273 cg.genNav(false) catch |err| switch (err) {270 try cg.genNav(false);
274 error.AlreadyReported => return error.AlreadyReported,
275 error.OutOfMemory => return error.OutOfMemory,
276 };
277271
278 return cg.serializeToMir(gpa);272 return cg.serializeToMir(gpa);
279}273}
...@@ -854,7 +848,7 @@ pub fn storageClass(cg: *const CodeGen, as: std.lang.AddressSpace) spec.StorageC...@@ -854,7 +848,7 @@ pub fn storageClass(cg: *const CodeGen, as: std.lang.AddressSpace) spec.StorageC
854 };848 };
855}849}
856850
857const Error = error{ AlreadyReported, OutOfMemory };851const Error = codegen.Error;
858852
859pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {853pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
860 const gpa = cg.gpa;854 const gpa = cg.gpa;
src/codegen/spork8/CodeGen.zig+15-27
...@@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator;...@@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator;
4const assert = std.debug.assert;4const assert = std.debug.assert;
55
6const CodeGen = @This();6const CodeGen = @This();
7const codegen = @import("../../codegen.zig");
7const link = @import("../../link.zig");8const link = @import("../../link.zig");
8const Spork8 = link.File.Spork8;9const Spork8 = link.File.Spork8;
9const Zcu = @import("../../Zcu.zig");10const Zcu = @import("../../Zcu.zig");
...@@ -133,37 +134,20 @@ pub fn generate(...@@ -133,37 +134,20 @@ pub fn generate(
133 _ = bin_file;134 _ = bin_file;
134 const zcu = pt.zcu;135 const zcu = pt.zcu;
135 const gpa = zcu.gpa;136 const gpa = zcu.gpa;
136 const cg = zcu.funcInfo(func_index);137 const func = zcu.funcInfo(func_index);
137138
138 var code_gen: CodeGen = .{139 var cg: CodeGen = .{
139 .gpa = gpa,140 .gpa = gpa,
140 .pt = pt,141 .pt = pt,
141 .air = air.*,142 .air = air.*,
142 .liveness = liveness.*.?,143 .liveness = liveness.*.?,
143 .owner_nav = cg.owner_nav,144 .owner_nav = func.owner_nav,
144 .func_index = func_index,145 .func_index = func_index,
145 .mir_instructions = .empty,146 .mir_instructions = .empty,
146 .mir_extra = .empty,147 .mir_extra = .empty,
147 };148 };
148 defer code_gen.deinit();149 defer cg.deinit();
149150
150 return generateInner(&code_gen) catch |err| switch (err) {
151 error.AlreadyReported,
152 error.OutOfMemory,
153 => |e| return e,
154 };
155}
156
157pub fn deinit(cg: *CodeGen) void {
158 cg.* = undefined;
159}
160
161const InnerError = error{
162 AlreadyReported,
163 OutOfMemory,
164};
165
166fn generateInner(cg: *CodeGen) InnerError!Mir {
167 // Generate MIR for function body151 // Generate MIR for function body
168 try cg.genBody(cg.air.getMainBody());152 try cg.genBody(cg.air.getMainBody());
169153
...@@ -175,7 +159,11 @@ fn generateInner(cg: *CodeGen) InnerError!Mir {...@@ -175,7 +159,11 @@ fn generateInner(cg: *CodeGen) InnerError!Mir {
175 };159 };
176}160}
177161
178fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {162pub fn deinit(cg: *CodeGen) void {
163 cg.* = undefined;
164}
165
166fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) codegen.Error!void {
179 const zcu = cg.pt.zcu;167 const zcu = cg.pt.zcu;
180 const ip = &zcu.intern_pool;168 const ip = &zcu.intern_pool;
181169
...@@ -185,7 +173,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -185,7 +173,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
185 }173 }
186}174}
187175
188fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {176fn genInst(cg: *CodeGen, inst: Air.Inst.Index) codegen.Error!void {
189 const air_tags = cg.air.instructions.items(.tag);177 const air_tags = cg.air.instructions.items(.tag);
190 return switch (air_tags[@backingInt(inst)]) {178 return switch (air_tags[@backingInt(inst)]) {
191 .inferred_alloc, .inferred_alloc_comptime => unreachable,179 .inferred_alloc, .inferred_alloc_comptime => unreachable,
...@@ -444,17 +432,17 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -444,17 +432,17 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
444 };432 };
445}433}
446434
447fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {435fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) codegen.Error!void {
448 _ = cg;436 _ = cg;
449 _ = inst;437 _ = inst;
450}438}
451439
452fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {440fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) codegen.Error!void {
453 _ = inst;441 _ = inst;
454 try cg.addTag(.halt);442 try cg.addTag(.halt);
455}443}
456444
457fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {445fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) codegen.Error!void {
458 const unwrapped_asm = cg.air.unwrapAsm(inst);446 const unwrapped_asm = cg.air.unwrapAsm(inst);
459 const outputs = unwrapped_asm.outputs;447 const outputs = unwrapped_asm.outputs;
460 // const inputs = unwrapped_asm.inputs;448 // const inputs = unwrapped_asm.inputs;
...@@ -538,7 +526,7 @@ pub fn addTagImm8(cg: *CodeGen, tag: Mir.Inst.Tag, imm8: u8) error{OutOfMemory}!...@@ -538,7 +526,7 @@ pub fn addTagImm8(cg: *CodeGen, tag: Mir.Inst.Tag, imm8: u8) error{OutOfMemory}!
538 try cg.addInst(.{ .tag = tag, .data = .{ .imm8 = imm8 } });526 try cg.addInst(.{ .tag = tag, .data = .{ .imm8 = imm8 } });
539}527}
540528
541fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } {529fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) codegen.Error {
542 const zcu = cg.pt.zcu;530 const zcu = cg.pt.zcu;
543 const func = zcu.funcInfo(cg.func_index);531 const func = zcu.funcInfo(cg.func_index);
544 return zcu.codegenFail(func.owner_nav, fmt, args);532 return zcu.codegenFail(func.owner_nav, fmt, args);
src/codegen/wasm/CodeGen.zig+3-8
...@@ -332,8 +332,7 @@ const ValueTable = std.array_hash_map.Auto(Air.Inst.Ref, WValue);...@@ -332,8 +332,7 @@ const ValueTable = std.array_hash_map.Auto(Air.Inst.Ref, WValue);
332332
333const bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};333const bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
334334
335const InnerError = error{335const InnerError = Error || error{
336 OutOfMemory,
337 /// An error occurred when trying to lower AIR to MIR.336 /// An error occurred when trying to lower AIR to MIR.
338 AlreadyReported,337 AlreadyReported,
339 /// Compiler implementation could not handle a large integer.338 /// Compiler implementation could not handle a large integer.
...@@ -361,7 +360,7 @@ pub fn deinit(cg: *CodeGen) void {...@@ -361,7 +360,7 @@ pub fn deinit(cg: *CodeGen) void {
361 cg.* = undefined;360 cg.* = undefined;
362}361}
363362
364pub fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } {363pub fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) Error {
365 const zcu = cg.pt.zcu;364 const zcu = cg.pt.zcu;
366 const func = zcu.funcInfo(cg.func_index);365 const func = zcu.funcInfo(cg.func_index);
367 return zcu.codegenFail(func.owner_nav, fmt, args);366 return zcu.codegenFail(func.owner_nav, fmt, args);
...@@ -760,11 +759,7 @@ fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {...@@ -760,11 +759,7 @@ fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
760 return .{ .local = .{ .value = initial_index, .references = 1 } };759 return .{ .local = .{ .value = initial_index, .references = 1 } };
761}760}
762761
763pub const Error = error{762pub const Error = codegen.Error;
764 OutOfMemory,
765 /// Indicates the error is already stored in Zcu `failed_codegen`.
766 AlreadyReported,
767};
768763
769pub fn generate(764pub fn generate(
770 bin_file: *link.File,765 bin_file: *link.File,
src/codegen/x86_64/CodeGen.zig+20-25
...@@ -1072,20 +1072,12 @@ pub fn generate(...@@ -1072,20 +1072,12 @@ pub fn generate(
1072 );1072 );
1073 }1073 }
10741074
1075 function.gen(&file.zir.?, func_zir.inst, func.comptime_args, call_info.air_arg_count) catch |err| switch (err) {1075 function.gen(&file.zir.?, func_zir.inst, &func, call_info.air_arg_count) catch |err| switch (err) {
1076 error.OutOfRegisters => return function.fail("ran out of registers (Zig compiler bug)", .{}),1076 error.OutOfRegisters => return function.fail("ran out of registers (Zig compiler bug)", .{}),
1077 else => |e| return e,1077 else => |e| return e,
1078 };1078 };
10791079
1080 // Drop them off at the rbrace.1080 if (!mod.strip) _ = try function.asmPseudo(.pseudo_dbg_end_none);
1081 if (!mod.strip) _ = try function.addInst(.{
1082 .tag = .pseudo,
1083 .ops = .pseudo_dbg_line_line_column,
1084 .data = .{ .line_column = .{
1085 .line = func.rbrace_line,
1086 .column = func.rbrace_column,
1087 } },
1088 });
10891081
1090 try function.mir_extra.shrinkToLen(gpa);1082 try function.mir_extra.shrinkToLen(gpa);
1091 try function.mir_string_bytes.shrinkToLen(gpa);1083 try function.mir_string_bytes.shrinkToLen(gpa);
...@@ -1120,7 +1112,7 @@ pub fn generateLazy(...@@ -1120,7 +1112,7 @@ pub fn generateLazy(
1120 atom_id: link.File.AtomId,1112 atom_id: link.File.AtomId,
1121 w: *std.Io.Writer,1113 w: *std.Io.Writer,
1122 debug_output: link.File.DebugInfoOutput,1114 debug_output: link.File.DebugInfoOutput,
1123) codegen.Error!void {1115) link.EmitError!void {
1124 const gpa = pt.zcu.gpa;1116 const gpa = pt.zcu.gpa;
1125 // This function is for generating global code, so we use the root module.1117 // This function is for generating global code, so we use the root module.
1126 const mod = pt.zcu.comp.root_mod;1118 const mod = pt.zcu.comp.root_mod;
...@@ -1228,18 +1220,18 @@ fn formatWipMir(data: FormatWipMirData, w: *Writer) Writer.Error!void {...@@ -1228,18 +1220,18 @@ fn formatWipMir(data: FormatWipMirData, w: *Writer) Writer.Error!void {
1228 switch (mir_inst.ops) {1220 switch (mir_inst.ops) {
1229 else => unreachable,1221 else => unreachable,
1230 .pseudo_dbg_prologue_end_none,1222 .pseudo_dbg_prologue_end_none,
1231 .pseudo_dbg_epilogue_begin_none,
1232 .pseudo_dbg_enter_block_none,1223 .pseudo_dbg_enter_block_none,
1233 .pseudo_dbg_leave_block_none,1224 .pseudo_dbg_leave_block_none,
1225 .pseudo_dbg_end_none,
1234 .pseudo_dbg_arg_none,1226 .pseudo_dbg_arg_none,
1235 .pseudo_dbg_var_args_none,1227 .pseudo_dbg_var_args_none,
1236 .pseudo_dbg_var_none,1228 .pseudo_dbg_var_none,
1237 .pseudo_dead_none,1229 .pseudo_dead_none,
1238 => {},1230 => {},
1239 .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column => try w.print(1231 .pseudo_dbg_line_stmt_line_column,
1240 " {[line]d}, {[column]d}",1232 .pseudo_dbg_line_line_column,
1241 mir_inst.data.line_column,1233 .pseudo_dbg_epilogue_begin_line_column,
1242 ),1234 => try w.print(" {[line]d}, {[column]d}", mir_inst.data.line_column),
1243 .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try w.print(" {f}", .{1235 .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try w.print(" {f}", .{
1244 ip.getNav(ip.indexToKey(mir_inst.data.ip_index).func.owner_nav).name.fmt(ip),1236 ip.getNav(ip.indexToKey(mir_inst.data.ip_index).func.owner_nav).name.fmt(ip),
1245 }),1237 }),
...@@ -2069,7 +2061,7 @@ fn gen(...@@ -2069,7 +2061,7 @@ fn gen(
2069 self: *CodeGen,2061 self: *CodeGen,
2070 zir: *const std.zig.Zir,2062 zir: *const std.zig.Zir,
2071 func_zir_inst: std.zig.Zir.Inst.Index,2063 func_zir_inst: std.zig.Zir.Inst.Index,
2072 comptime_args: InternPool.Index.Slice,2064 func: *const InternPool.Key.Func,
2073 air_arg_count: u32,2065 air_arg_count: u32,
2074) InnerError!void {2066) InnerError!void {
2075 const pt = self.pt;2067 const pt = self.pt;
...@@ -2150,7 +2142,7 @@ fn gen(...@@ -2150,7 +2142,7 @@ fn gen(
21502142
2151 if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_prologue_end_none);2143 if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_prologue_end_none);
21522144
2153 try self.genMainBody(zir, func_zir_inst, comptime_args, air_arg_count);2145 try self.genMainBody(zir, func_zir_inst, func.comptime_args, air_arg_count);
21542146
2155 const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: {2147 const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: {
2156 var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1);2148 var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1);
...@@ -2165,7 +2157,14 @@ fn gen(...@@ -2165,7 +2157,14 @@ fn gen(
2165 }2157 }
2166 for (self.epilogue_relocs.items) |epilogue_reloc| self.performReloc(epilogue_reloc);2158 for (self.epilogue_relocs.items) |epilogue_reloc| self.performReloc(epilogue_reloc);
21672159
2168 if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);2160 if (!self.mod.strip) _ = try self.addInst(.{
2161 .tag = .pseudo,
2162 .ops = .pseudo_dbg_epilogue_begin_line_column,
2163 .data = .{ .line_column = .{
2164 .line = func.rbrace_line,
2165 .column = func.rbrace_column,
2166 } },
2167 });
2169 const backpatch_stack_dealloc = try self.asmPlaceholder();2168 const backpatch_stack_dealloc = try self.asmPlaceholder();
2170 const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();2169 const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();
2171 try self.asmRegister(.{ ._, .pop }, .rbp);2170 try self.asmRegister(.{ ._, .pop }, .rbp);
...@@ -2283,11 +2282,7 @@ fn gen(...@@ -2283,11 +2282,7 @@ fn gen(
2283 .data = .{ .reg_list = frame_layout.save_reg_list },2282 .data = .{ .reg_list = frame_layout.save_reg_list },
2284 });2283 });
2285 }2284 }
2286 } else {2285 } else try self.genMainBody(zir, func_zir_inst, func.comptime_args, air_arg_count);
2287 if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_prologue_end_none);
2288 try self.genMainBody(zir, func_zir_inst, comptime_args, air_arg_count);
2289 if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);
2290 }
2291}2286}
22922287
2293fn genMainBody(2288fn genMainBody(
...@@ -182177,7 +182172,7 @@ fn resolveCallingConventionValues(...@@ -182177,7 +182172,7 @@ fn resolveCallingConventionValues(
182177 return result;182172 return result;
182178}182173}
182179182174
182180fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } {182175fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) codegen.Error {
182181 @branchHint(.cold);182176 @branchHint(.cold);
182182 const zcu = cg.pt.zcu;182177 const zcu = cg.pt.zcu;
182183 return switch (cg.owner) {182178 return switch (cg.owner) {
src/codegen/x86_64/Emit.zig+209-192
...@@ -16,10 +16,8 @@ code_offset_mapping: std.ArrayList(u32),...@@ -16,10 +16,8 @@ code_offset_mapping: std.ArrayList(u32),
16relocs: std.ArrayList(Reloc),16relocs: std.ArrayList(Reloc),
17table_relocs: std.ArrayList(TableReloc),17table_relocs: std.ArrayList(TableReloc),
1818
19pub const Error = Lower.Error || error{19pub const Error = Lower.Error || codegen.Error || std.Io.Writer.Error || error{
20 AlreadyReported,
21 EmitFail,20 EmitFail,
22 NotFile,
23} || std.posix.MMapError || std.posix.MRemapError || link.File.UpdateDebugInfoError;21} || std.posix.MMapError || std.posix.MRemapError || link.File.UpdateDebugInfoError;
2422
25pub fn emitMir(emit: *Emit) Error!void {23pub fn emitMir(emit: *Emit) Error!void {
...@@ -38,7 +36,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -38,7 +36,7 @@ pub fn emitMir(emit: *Emit) Error!void {
38 if (lowered_inst.prefix == .directive) {36 if (lowered_inst.prefix == .directive) {
39 const start_offset: u32 = @intCast(emit.w.end);37 const start_offset: u32 = @intCast(emit.w.end);
40 switch (emit.debug_output) {38 switch (emit.debug_output) {
41 .dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) {39 inline .dwarf, .dwarf2, .eh_frame => |dwarf| switch (lowered_inst.encoding.mnemonic) {
42 .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{40 .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{
43 .reg = lowered_inst.ops[0].reg.dwarfNum(),41 .reg = lowered_inst.ops[0].reg.dwarfNum(),
44 .off = lowered_inst.ops[1].imm.signed,42 .off = lowered_inst.ops[1].imm.signed,
...@@ -460,204 +458,222 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -460,204 +458,222 @@ pub fn emitMir(emit: *Emit) Error!void {
460458
461 if (lowered.insts.len == 0) {459 if (lowered.insts.len == 0) {
462 const mir_inst = emit.lower.mir.instructions.get(mir_index);460 const mir_inst = emit.lower.mir.instructions.get(mir_index);
463 switch (mir_inst.tag) {461 assert(mir_inst.tag == .pseudo);
462 switch (mir_inst.ops) {
464 else => unreachable,463 else => unreachable,
465 .pseudo => switch (mir_inst.ops) {464 .pseudo_dbg_prologue_end_none => switch (emit.debug_output) {
466 else => unreachable,465 inline .dwarf, .dwarf2 => |dwarf| {
467 .pseudo_dbg_prologue_end_none => switch (emit.debug_output) {466 try dwarf.setPrologueEnd();
468 .dwarf => |dwarf| try dwarf.setPrologueEnd(),467 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
469 .none => {},468 emit.prev_di_loc.line, emit.prev_di_loc.column,
469 });
470 },470 },
471 .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePCAndLine(.{471 .eh_frame, .none => {},
472 .line = mir_inst.data.line_column.line,472 },
473 .column = mir_inst.data.line_column.column,473 .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvanceLineAndPc(.{
474 .is_stmt = true,474 .line = mir_inst.data.line_column.line,
475 }),475 .column = mir_inst.data.line_column.column,
476 .pseudo_dbg_line_line_column => try emit.dbgAdvancePCAndLine(.{476 .is_stmt = true,
477 .line = mir_inst.data.line_column.line,477 }),
478 .column = mir_inst.data.line_column.column,478 .pseudo_dbg_line_line_column => try emit.dbgAdvanceLineAndPc(.{
479 .is_stmt = false,479 .line = mir_inst.data.line_column.line,
480 }),480 .column = mir_inst.data.line_column.column,
481 .pseudo_dbg_epilogue_begin_none => switch (emit.debug_output) {481 .is_stmt = false,
482 .dwarf => |dwarf| {482 }),
483 .pseudo_dbg_epilogue_begin_line_column => {
484 switch (emit.debug_output) {
485 inline .dwarf, .dwarf2 => |dwarf| {
483 try dwarf.setEpilogueBegin();486 try dwarf.setEpilogueBegin();
484 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{487 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
485 emit.prev_di_loc.line, emit.prev_di_loc.column,488 emit.prev_di_loc.line, emit.prev_di_loc.column,
486 });489 });
487 try emit.dbgAdvancePCAndLine(emit.prev_di_loc);
488 },490 },
489 .none => {},491 .eh_frame, .none => {},
490 },492 }
491 .pseudo_dbg_enter_block_none => switch (emit.debug_output) {493 try emit.dbgAdvanceLineAndPc(.{
492 .dwarf => |dwarf| {494 .line = mir_inst.data.line_column.line,
493 log.debug("mirDbgEnterBlock (line={d}, col={d})", .{495 .column = mir_inst.data.line_column.column,
494 emit.prev_di_loc.line, emit.prev_di_loc.column,496 });
495 });497 },
496 try dwarf.enterBlock(emit.w.end);498 .pseudo_dbg_enter_block_none => switch (emit.debug_output) {
497 },499 inline .dwarf, .dwarf2 => |dwarf| {
498 .none => {},500 log.debug("mirDbgEnterBlock (line={d}, col={d})", .{
501 emit.prev_di_loc.line, emit.prev_di_loc.column,
502 });
503 try dwarf.enterBlock(emit.w.end);
499 },504 },
500 .pseudo_dbg_leave_block_none => switch (emit.debug_output) {505 .eh_frame, .none => {},
501 .dwarf => |dwarf| {506 },
502 log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{507 .pseudo_dbg_leave_block_none => switch (emit.debug_output) {
503 emit.prev_di_loc.line, emit.prev_di_loc.column,508 inline .dwarf, .dwarf2 => |dwarf| {
504 });509 log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{
505 try dwarf.leaveBlock(emit.w.end);510 emit.prev_di_loc.line, emit.prev_di_loc.column,
506 },511 });
507 .none => {},512 try dwarf.leaveBlock(emit.w.end);
508 },513 },
509 .pseudo_dbg_enter_inline_func => switch (emit.debug_output) {514 .eh_frame, .none => {},
510 .dwarf => |dwarf| {515 },
511 log.debug("mirDbgEnterInline (line={d}, col={d})", .{516 .pseudo_dbg_enter_inline_func => switch (emit.debug_output) {
512 emit.prev_di_loc.line, emit.prev_di_loc.column,517 inline .dwarf, .dwarf2 => |dwarf| {
513 });518 log.debug("mirDbgEnterInline (line={d}, col={d})", .{
514 try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column);519 emit.prev_di_loc.line, emit.prev_di_loc.column,
515 },520 });
516 .none => {},521 try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column);
517 },522 },
518 .pseudo_dbg_leave_inline_func => switch (emit.debug_output) {523 .eh_frame, .none => {},
519 .dwarf => |dwarf| {524 },
520 log.debug("mirDbgLeaveInline (line={d}, col={d})", .{525 .pseudo_dbg_leave_inline_func => switch (emit.debug_output) {
521 emit.prev_di_loc.line, emit.prev_di_loc.column,526 inline .dwarf, .dwarf2 => |dwarf| {
522 });527 log.debug("mirDbgLeaveInline (line={d}, col={d})", .{
523 try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end);528 emit.prev_di_loc.line, emit.prev_di_loc.column,
524 },529 });
525 .none => {},530 try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end);
526 },531 },
527 .pseudo_dbg_arg_none,532 .eh_frame, .none => {},
528 .pseudo_dbg_arg_i_s,533 },
529 .pseudo_dbg_arg_i_u,534 .pseudo_dbg_end_none => try emit.dbgAdvanceLineAndPc(.{
530 .pseudo_dbg_arg_i_64,535 .line = emit.prev_di_loc.line,
531 .pseudo_dbg_arg_ro,536 .column = emit.prev_di_loc.column,
532 .pseudo_dbg_arg_fa,537 .end = true,
533 .pseudo_dbg_arg_m,538 }),
534 .pseudo_dbg_var_none,539 .pseudo_dbg_arg_none,
535 .pseudo_dbg_var_i_s,540 .pseudo_dbg_arg_i_s,
536 .pseudo_dbg_var_i_u,541 .pseudo_dbg_arg_i_u,
537 .pseudo_dbg_var_i_64,542 .pseudo_dbg_arg_i_64,
538 .pseudo_dbg_var_ro,543 .pseudo_dbg_arg_ro,
539 .pseudo_dbg_var_fa,544 .pseudo_dbg_arg_fa,
540 .pseudo_dbg_var_m,545 .pseudo_dbg_arg_m,
541 => switch (emit.debug_output) {546 .pseudo_dbg_var_none,
542 .dwarf => |dwarf| {547 .pseudo_dbg_var_i_s,
543 var loc_buf: [2]link.File.Dwarf.Loc = undefined;548 .pseudo_dbg_var_i_u,
544 const loc: link.File.Dwarf.Loc = loc: switch (mir_inst.ops) {549 .pseudo_dbg_var_i_64,
550 .pseudo_dbg_var_ro,
551 .pseudo_dbg_var_fa,
552 .pseudo_dbg_var_m,
553 => switch (emit.debug_output) {
554 inline .dwarf, .dwarf2 => |dwarf, tag| {
555 const DwarfLoc = switch (tag) {
556 .dwarf => link.File.Dwarf.Loc,
557 .dwarf2 => link.File.Dwarf2.Loc,
558 .eh_frame, .none => comptime unreachable,
559 };
560 var loc_buf: [2]DwarfLoc = undefined;
561 const loc: DwarfLoc = loc: switch (mir_inst.ops) {
562 else => unreachable,
563 .pseudo_dbg_arg_none, .pseudo_dbg_var_none => .empty,
564 .pseudo_dbg_arg_i_s,
565 .pseudo_dbg_arg_i_u,
566 .pseudo_dbg_var_i_s,
567 .pseudo_dbg_var_i_u,
568 => .{ .stack_value = stack_value: {
569 loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.i.i)) {
570 .signed => |s| .{ .consts = s },
571 .unsigned => |u| .{ .constu = u },
572 };
573 break :stack_value &loc_buf[0];
574 } },
575 .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => .{ .stack_value = stack_value: {
576 loc_buf[0] = .{ .constu = mir_inst.data.i64 };
577 break :stack_value &loc_buf[0];
578 } },
579 .pseudo_dbg_arg_fa, .pseudo_dbg_var_fa => {
580 const reg_off = emit.lower.mir.resolveFrameAddr(mir_inst.data.fa);
581 break :loc .{ .plus = .{
582 reg: {
583 loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() };
584 break :reg &loc_buf[0];
585 },
586 off: {
587 loc_buf[1] = .{ .consts = reg_off.off };
588 break :off &loc_buf[1];
589 },
590 } };
591 },
592 .pseudo_dbg_arg_m, .pseudo_dbg_var_m => {
593 const mem = emit.lower.mir.resolveMemoryExtra(mir_inst.data.x.payload).decode();
594 break :loc .{ .plus = .{
595 base: {
596 loc_buf[0] = switch (mem.base()) {
597 .none => .{ .constu = 0 },
598 .reg => |reg| .{ .breg = reg.dwarfNum() },
599 .frame, .table, .rip_inst => unreachable,
600 .nav => |nav| .{ .addr_reloc = try codegen.genNavRef(
601 emit.bin_file,
602 emit.pt,
603 nav,
604 ) },
605 .uav => |uav| .{ .addr_reloc = try emit.bin_file.lowerUav(
606 emit.pt,
607 uav.val,
608 Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu),
609 ) },
610 .lazy_sym, .extern_func => unreachable,
611 };
612 break :base &loc_buf[0];
613 },
614 disp: {
615 loc_buf[1] = switch (mem.disp()) {
616 .signed => |s| .{ .consts = s },
617 .unsigned => |u| .{ .constu = u },
618 };
619 break :disp &loc_buf[1];
620 },
621 } };
622 },
623 };
624
625 const local = &emit.lower.mir.locals[local_index];
626 local_index += 1;
627 try dwarf.genLocalVarDebugInfo(
628 switch (mir_inst.ops) {
545 else => unreachable,629 else => unreachable,
546 .pseudo_dbg_arg_none, .pseudo_dbg_var_none => .empty,630 .pseudo_dbg_arg_none,
547 .pseudo_dbg_arg_i_s,631 .pseudo_dbg_arg_i_s,
548 .pseudo_dbg_arg_i_u,632 .pseudo_dbg_arg_i_u,
633 .pseudo_dbg_arg_i_64,
634 .pseudo_dbg_arg_ro,
635 .pseudo_dbg_arg_fa,
636 .pseudo_dbg_arg_m,
637 .pseudo_dbg_arg_val,
638 => .arg,
639 .pseudo_dbg_var_none,
549 .pseudo_dbg_var_i_s,640 .pseudo_dbg_var_i_s,
550 .pseudo_dbg_var_i_u,641 .pseudo_dbg_var_i_u,
551 => .{ .stack_value = stack_value: {642 .pseudo_dbg_var_i_64,
552 loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.i.i)) {643 .pseudo_dbg_var_ro,
553 .signed => |s| .{ .consts = s },644 .pseudo_dbg_var_fa,
554 .unsigned => |u| .{ .constu = u },645 .pseudo_dbg_var_m,
555 };646 .pseudo_dbg_var_val,
556 break :stack_value &loc_buf[0];647 => .local_var,
557 } },648 },
558 .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => .{ .stack_value = stack_value: {649 local.name.toSlice(&emit.lower.mir),
559 loc_buf[0] = .{ .constu = mir_inst.data.i64 };650 .fromInterned(local.type),
560 break :stack_value &loc_buf[0];651 loc,
561 } },652 );
562 .pseudo_dbg_arg_fa, .pseudo_dbg_var_fa => {
563 const reg_off = emit.lower.mir.resolveFrameAddr(mir_inst.data.fa);
564 break :loc .{ .plus = .{
565 reg: {
566 loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() };
567 break :reg &loc_buf[0];
568 },
569 off: {
570 loc_buf[1] = .{ .consts = reg_off.off };
571 break :off &loc_buf[1];
572 },
573 } };
574 },
575 .pseudo_dbg_arg_m, .pseudo_dbg_var_m => {
576 const mem = emit.lower.mir.resolveMemoryExtra(mir_inst.data.x.payload).decode();
577 break :loc .{ .plus = .{
578 base: {
579 loc_buf[0] = switch (mem.base()) {
580 .none => .{ .constu = 0 },
581 .reg => |reg| .{ .breg = reg.dwarfNum() },
582 .frame, .table, .rip_inst => unreachable,
583 .nav => |nav| .{ .addr_reloc = try codegen.genNavRef(
584 emit.bin_file,
585 emit.pt,
586 nav,
587 ) },
588 .uav => |uav| .{ .addr_reloc = try emit.bin_file.lowerUav(
589 emit.pt,
590 uav.val,
591 Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu),
592 ) },
593 .lazy_sym, .extern_func => unreachable,
594 };
595 break :base &loc_buf[0];
596 },
597 disp: {
598 loc_buf[1] = switch (mem.disp()) {
599 .signed => |s| .{ .consts = s },
600 .unsigned => |u| .{ .constu = u },
601 };
602 break :disp &loc_buf[1];
603 },
604 } };
605 },
606 };
607
608 const local = &emit.lower.mir.locals[local_index];
609 local_index += 1;
610 try dwarf.genLocalVarDebugInfo(
611 switch (mir_inst.ops) {
612 else => unreachable,
613 .pseudo_dbg_arg_none,
614 .pseudo_dbg_arg_i_s,
615 .pseudo_dbg_arg_i_u,
616 .pseudo_dbg_arg_i_64,
617 .pseudo_dbg_arg_ro,
618 .pseudo_dbg_arg_fa,
619 .pseudo_dbg_arg_m,
620 .pseudo_dbg_arg_val,
621 => .arg,
622 .pseudo_dbg_var_none,
623 .pseudo_dbg_var_i_s,
624 .pseudo_dbg_var_i_u,
625 .pseudo_dbg_var_i_64,
626 .pseudo_dbg_var_ro,
627 .pseudo_dbg_var_fa,
628 .pseudo_dbg_var_m,
629 .pseudo_dbg_var_val,
630 => .local_var,
631 },
632 local.name.toSlice(&emit.lower.mir),
633 .fromInterned(local.type),
634 loc,
635 );
636 },
637 .none => local_index += 1,
638 },
639 .pseudo_dbg_arg_val, .pseudo_dbg_var_val => switch (emit.debug_output) {
640 .dwarf => |dwarf| {
641 const local = &emit.lower.mir.locals[local_index];
642 local_index += 1;
643 try dwarf.genLocalConstDebugInfo(
644 switch (mir_inst.ops) {
645 else => unreachable,
646 .pseudo_dbg_arg_val => .comptime_arg,
647 .pseudo_dbg_var_val => .local_const,
648 },
649 local.name.toSlice(&emit.lower.mir),
650 .fromInterned(mir_inst.data.ip_index),
651 );
652 },
653 .none => local_index += 1,
654 },653 },
655 .pseudo_dbg_var_args_none => switch (emit.debug_output) {654 .eh_frame, .none => local_index += 1,
656 .dwarf => |dwarf| try dwarf.genVarArgsDebugInfo(),655 },
657 .none => {},656 .pseudo_dbg_arg_val, .pseudo_dbg_var_val => switch (emit.debug_output) {
657 inline .dwarf, .dwarf2 => |dwarf| {
658 const local = &emit.lower.mir.locals[local_index];
659 local_index += 1;
660 try dwarf.genLocalConstDebugInfo(
661 switch (mir_inst.ops) {
662 else => unreachable,
663 .pseudo_dbg_arg_val => .comptime_arg,
664 .pseudo_dbg_var_val => .local_const,
665 },
666 local.name.toSlice(&emit.lower.mir),
667 .fromInterned(mir_inst.data.ip_index),
668 );
658 },669 },
659 .pseudo_dead_none => {},670 .eh_frame, .none => local_index += 1,
671 },
672 .pseudo_dbg_var_args_none => switch (emit.debug_output) {
673 inline .dwarf, .dwarf2 => |dwarf| try dwarf.genVarArgsDebugInfo(),
674 .eh_frame, .none => {},
660 },675 },
676 .pseudo_dead_none => {},
661 }677 }
662 }678 }
663 }679 }
...@@ -971,22 +987,23 @@ const TableReloc = struct {...@@ -971,22 +987,23 @@ const TableReloc = struct {
971const Loc = struct {987const Loc = struct {
972 line: u32,988 line: u32,
973 column: u32,989 column: u32,
974 is_stmt: bool,990 is_stmt: ?bool = null,
991 end: bool = false,
975};992};
976993
977fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void {994fn dbgAdvanceLineAndPc(emit: *Emit, loc: Loc) Error!void {
978 const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line);
979 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
980 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });
981 switch (emit.debug_output) {995 switch (emit.debug_output) {
982 .dwarf => |dwarf| {996 inline .dwarf, .dwarf2 => |dwarf| {
983 if (loc.is_stmt != emit.prev_di_loc.is_stmt) try dwarf.negateStmt();997 const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line);
998 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
999 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });
1000 if (loc.is_stmt) |is_stmt| if (is_stmt != emit.prev_di_loc.is_stmt) try dwarf.negateStmt();
984 if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column);1001 if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column);
985 try dwarf.advancePCAndLine(delta_line, delta_pc);1002 try dwarf.advanceLineAndPc(delta_line, delta_pc, loc.end);
986 emit.prev_di_loc = loc;1003 emit.prev_di_loc = loc;
987 emit.prev_di_pc = emit.w.end;1004 emit.prev_di_pc = emit.w.end;
988 },1005 },
989 .none => {},1006 .eh_frame, .none => {},
990 }1007 }
991}1008}
9921009
src/codegen/x86_64/Lower.zig+2-1
...@@ -314,11 +314,12 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -314,11 +314,12 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
314 .pseudo_dbg_prologue_end_none,314 .pseudo_dbg_prologue_end_none,
315 .pseudo_dbg_line_stmt_line_column,315 .pseudo_dbg_line_stmt_line_column,
316 .pseudo_dbg_line_line_column,316 .pseudo_dbg_line_line_column,
317 .pseudo_dbg_epilogue_begin_none,317 .pseudo_dbg_epilogue_begin_line_column,
318 .pseudo_dbg_enter_block_none,318 .pseudo_dbg_enter_block_none,
319 .pseudo_dbg_leave_block_none,319 .pseudo_dbg_leave_block_none,
320 .pseudo_dbg_enter_inline_func,320 .pseudo_dbg_enter_inline_func,
321 .pseudo_dbg_leave_inline_func,321 .pseudo_dbg_leave_inline_func,
322 .pseudo_dbg_end_none,
322 .pseudo_dbg_arg_none,323 .pseudo_dbg_arg_none,
323 .pseudo_dbg_arg_i_s,324 .pseudo_dbg_arg_i_s,
324 .pseudo_dbg_arg_i_u,325 .pseudo_dbg_arg_i_u,
src/codegen/x86_64/Mir.zig+27-21
...@@ -1519,30 +1519,33 @@ pub const Inst = struct {...@@ -1519,30 +1519,33 @@ pub const Inst = struct {
1519 /// Uses `bytes` payload.1519 /// Uses `bytes` payload.
1520 pseudo_cfi_escape_bytes,1520 pseudo_cfi_escape_bytes,
15211521
1522 /// End of prologue1522 /// End of prologue.
1523 /// Uses `none` payload.1523 /// Uses `none` payload.
1524 pseudo_dbg_prologue_end_none,1524 pseudo_dbg_prologue_end_none,
1525 /// Update debug line with is_stmt register set1525 /// Update debug line with is_stmt register set.
1526 /// Uses `line_column` payload.1526 /// Uses `line_column` payload.
1527 pseudo_dbg_line_stmt_line_column,1527 pseudo_dbg_line_stmt_line_column,
1528 /// Update debug line with is_stmt register clear1528 /// Update debug line with is_stmt register clear.
1529 /// Uses `line_column` payload.1529 /// Uses `line_column` payload.
1530 pseudo_dbg_line_line_column,1530 pseudo_dbg_line_line_column,
1531 /// Start of epilogue1531 /// Start of epilogue.
1532 /// Uses `none` payload.1532 /// Uses `line_column` payload.
1533 pseudo_dbg_epilogue_begin_none,1533 pseudo_dbg_epilogue_begin_line_column,
1534 /// Start of lexical block1534 /// Start of lexical block.
1535 /// Uses `none` payload.1535 /// Uses `none` payload.
1536 pseudo_dbg_enter_block_none,1536 pseudo_dbg_enter_block_none,
1537 /// End of lexical block1537 /// End of lexical block.
1538 /// Uses `none` payload.1538 /// Uses `none` payload.
1539 pseudo_dbg_leave_block_none,1539 pseudo_dbg_leave_block_none,
1540 /// Start of inline function1540 /// Start of inline function.
1541 /// Uses `ip_index` payload.1541 /// Uses `ip_index` payload.
1542 pseudo_dbg_enter_inline_func,1542 pseudo_dbg_enter_inline_func,
1543 /// End of inline function1543 /// End of inline function.
1544 /// Uses `ip_index` payload.1544 /// Uses `ip_index` payload.
1545 pseudo_dbg_leave_inline_func,1545 pseudo_dbg_leave_inline_func,
1546 /// End of function.
1547 /// Uses `none` payload.
1548 pseudo_dbg_end_none,
1546 /// Local argument.1549 /// Local argument.
1547 /// Uses `none` payload.1550 /// Uses `none` payload.
1548 pseudo_dbg_arg_none,1551 pseudo_dbg_arg_none,
...@@ -1978,7 +1981,7 @@ pub fn emit(...@@ -1978,7 +1981,7 @@ pub fn emit(
1978 atom_id: link.File.AtomId,1981 atom_id: link.File.AtomId,
1979 w: *std.Io.Writer,1982 w: *std.Io.Writer,
1980 debug_output: link.File.DebugInfoOutput,1983 debug_output: link.File.DebugInfoOutput,
1981) codegen.Error!void {1984) link.EmitError!void {
1982 const zcu = pt.zcu;1985 const zcu = pt.zcu;
1983 const comp = zcu.comp;1986 const comp = zcu.comp;
1984 const gpa = comp.gpa;1987 const gpa = comp.gpa;
...@@ -1986,7 +1989,7 @@ pub fn emit(...@@ -1986,7 +1989,7 @@ pub fn emit(
1986 const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?;1989 const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?;
1987 const nav = func.owner_nav;1990 const nav = func.owner_nav;
1988 const mod = zcu.navFileScope(nav).mod.?;1991 const mod = zcu.navFileScope(nav).mod.?;
1989 var e: Emit = .{1992 var em: Emit = .{
1990 .lower = .{1993 .lower = .{
1991 .target = &mod.resolved_target.result,1994 .target = &mod.resolved_target.result,
1992 .allocator = gpa,1995 .allocator = gpa,
...@@ -2006,7 +2009,8 @@ pub fn emit(...@@ -2006,7 +2009,8 @@ pub fn emit(
2006 .column = func.lbrace_column,2009 .column = func.lbrace_column,
2007 .is_stmt = switch (debug_output) {2010 .is_stmt = switch (debug_output) {
2008 .dwarf => |dwarf| dwarf.dwarf.debug_line.header.default_is_stmt,2011 .dwarf => |dwarf| dwarf.dwarf.debug_line.header.default_is_stmt,
2009 .none => undefined,2012 .dwarf2 => |dwarf| dwarf.wip_nav.dwarf.debug_line.header.default_is_stmt,
2013 .eh_frame, .none => undefined,
2010 },2014 },
2011 },2015 },
2012 .prev_di_pc = 0,2016 .prev_di_pc = 0,
...@@ -2015,11 +2019,12 @@ pub fn emit(...@@ -2015,11 +2019,12 @@ pub fn emit(
2015 .relocs = .empty,2019 .relocs = .empty,
2016 .table_relocs = .empty,2020 .table_relocs = .empty,
2017 };2021 };
2018 defer e.deinit();2022 defer em.deinit();
2019 e.emitMir() catch |err| switch (err) {2023 em.emitMir() catch |err| switch (err) {
2020 error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, e.lower.err_msg.?),2024 error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, em.lower.err_msg.?),
2021 error.InvalidInstruction, error.CannotEncode => return zcu.codegenFail(nav, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),2025 error.InvalidInstruction, error.CannotEncode => return zcu.codegenFail(nav, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),
2022 else => return zcu.codegenFail(nav, "emit MIR failed: {s}", .{@errorName(err)}),2026 else => return zcu.codegenFail(nav, "emit MIR failed: {s}", .{@errorName(err)}),
2027 error.AlreadyReported, error.Canceled, error.WriteFailed => |e| return e,
2023 };2028 };
2024}2029}
20252030
...@@ -2031,12 +2036,12 @@ pub fn emitLazy(...@@ -2031,12 +2036,12 @@ pub fn emitLazy(
2031 atom_id: link.File.AtomId,2036 atom_id: link.File.AtomId,
2032 w: *std.Io.Writer,2037 w: *std.Io.Writer,
2033 debug_output: link.File.DebugInfoOutput,2038 debug_output: link.File.DebugInfoOutput,
2034) codegen.Error!void {2039) link.EmitError!void {
2035 const zcu = pt.zcu;2040 const zcu = pt.zcu;
2036 const comp = zcu.comp;2041 const comp = zcu.comp;
2037 const gpa = comp.gpa;2042 const gpa = comp.gpa;
2038 const mod = comp.root_mod;2043 const mod = comp.root_mod;
2039 var e: Emit = .{2044 var em: Emit = .{
2040 .lower = .{2045 .lower = .{
2041 .target = &mod.resolved_target.result,2046 .target = &mod.resolved_target.result,
2042 .allocator = gpa,2047 .allocator = gpa,
...@@ -2058,11 +2063,12 @@ pub fn emitLazy(...@@ -2058,11 +2063,12 @@ pub fn emitLazy(
2058 .relocs = .empty,2063 .relocs = .empty,
2059 .table_relocs = .empty,2064 .table_relocs = .empty,
2060 };2065 };
2061 defer e.deinit();2066 defer em.deinit();
2062 e.emitMir() catch |err| switch (err) {2067 em.emitMir() catch |err| switch (err) {
2063 error.LowerFail, error.EmitFail => return zcu.codegenFailTypeMsg(lazy_sym.ty, e.lower.err_msg.?),2068 error.LowerFail, error.EmitFail => return zcu.codegenFailTypeMsg(lazy_sym.ty, em.lower.err_msg.?),
2064 error.InvalidInstruction, error.CannotEncode => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),2069 error.InvalidInstruction, error.CannotEncode => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),
2065 else => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s}", .{@errorName(err)}),2070 else => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s}", .{@errorName(err)}),
2071 error.AlreadyReported, error.Canceled, error.WriteFailed => |e| return e,
2066 };2072 };
2067}2073}
20682074
src/crash_report.zig-1
...@@ -215,7 +215,6 @@ const Sema = @import("Sema.zig");...@@ -215,7 +215,6 @@ const Sema = @import("Sema.zig");
215const Zcu = @import("Zcu.zig");215const Zcu = @import("Zcu.zig");
216const link = @import("link.zig");216const link = @import("link.zig");
217const InternPool = @import("InternPool.zig");217const InternPool = @import("InternPool.zig");
218const dev = @import("dev.zig");
219const print_zir = @import("print_zir.zig");218const print_zir = @import("print_zir.zig");
220219
221const build_options = @import("build_options");220const build_options = @import("build_options");
src/dev.zig-1
...@@ -227,7 +227,6 @@ pub const Env = enum {...@@ -227,7 +227,6 @@ pub const Env = enum {
227 else => Env.sema.supports(feature),227 else => Env.sema.supports(feature),
228 },228 },
229 .@"x86_64-windows" => switch (feature) {229 .@"x86_64-windows" => switch (feature) {
230 .build_command,
231 .stdio_listen,230 .stdio_listen,
232 .incremental,231 .incremental,
233 .legalize,232 .legalize,
src/link.zig+109-48
...@@ -26,9 +26,10 @@ const target_util = @import("target.zig");...@@ -26,9 +26,10 @@ const target_util = @import("target.zig");
26const codegen = @import("codegen.zig");26const codegen = @import("codegen.zig");
27const crash_report = @import("crash_report.zig");27const crash_report = @import("crash_report.zig");
2828
29pub const ConstPool = @import("link/ConstPool.zig");
29pub const LdScript = @import("link/LdScript.zig");30pub const LdScript = @import("link/LdScript.zig");
31pub const MappedFile = @import("link/MappedFile.zig");
30pub const Queue = @import("link/Queue.zig");32pub const Queue = @import("link/Queue.zig");
31pub const ConstPool = @import("link/ConstPool.zig");
3233
33pub const aarch64 = @import("link/aarch64.zig");34pub const aarch64 = @import("link/aarch64.zig");
34pub const loongarch = @import("link/loongarch.zig");35pub const loongarch = @import("link/loongarch.zig");
...@@ -38,6 +39,7 @@ pub const Error = Allocator.Error || Io.Cancelable || error{...@@ -38,6 +39,7 @@ pub const Error = Allocator.Error || Io.Cancelable || error{
38 /// instance in `Compilation.link_diags`.39 /// instance in `Compilation.link_diags`.
39 AlreadyReported,40 AlreadyReported,
40};41};
42pub const EmitError = Error || Io.Writer.Error;
4143
42pub const Diags = struct {44pub const Diags = struct {
43 /// Stored here so that function definitions can distinguish between45 /// Stored here so that function definitions can distinguish between
...@@ -95,7 +97,6 @@ pub const Diags = struct {...@@ -95,7 +97,6 @@ pub const Diags = struct {
95 return switch (msg.source_location) {97 return switch (msg.source_location) {
96 .none => try bundle.addString(msg.msg),98 .none => try bundle.addString(msg.msg),
97 .wasm => |sl| {99 .wasm => |sl| {
98 dev.check(.wasm_linker);
99 const wasm = base.?.cast(.wasm).?;100 const wasm = base.?.cast(.wasm).?;
100 return sl.string(msg.msg, bundle, wasm);101 return sl.string(msg.msg, bundle, wasm);
101 },102 },
...@@ -394,8 +395,6 @@ pub const Diags = struct {...@@ -394,8 +395,6 @@ pub const Diags = struct {
394 }395 }
395};396};
396397
397pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version;
398
399pub const File = struct {398pub const File = struct {
400 tag: Tag,399 tag: Tag,
401400
...@@ -653,7 +652,6 @@ pub const File = struct {...@@ -653,7 +652,6 @@ pub const File = struct {
653 base.file = try emit.root_dir.handle.openFile(io, emit.sub_path, .{ .mode = .read_write });652 base.file = try emit.root_dir.handle.openFile(io, emit.sub_path, .{ .mode = .read_write });
654 },653 },
655 .elf2, .coff2 => if (base.file == null) {654 .elf2, .coff2 => if (base.file == null) {
656 dev.checkAny(&.{ .elf2_linker, .coff2_linker });
657 const mf = if (base.cast(.elf2)) |elf|655 const mf = if (base.cast(.elf2)) |elf|
658 &elf.mf656 &elf.mf
659 else if (base.cast(.coff2)) |coff|657 else if (base.cast(.coff2)) |coff|
...@@ -757,6 +755,8 @@ pub const File = struct {...@@ -757,6 +755,8 @@ pub const File = struct {
757755
758 pub const DebugInfoOutput = union(enum) {756 pub const DebugInfoOutput = union(enum) {
759 dwarf: *Dwarf.WipNav,757 dwarf: *Dwarf.WipNav,
758 eh_frame: *Dwarf2.WipNav,
759 dwarf2: *Dwarf2.WipNav.Debug,
760 none,760 none,
761 };761 };
762 pub const UpdateDebugInfoError = Dwarf.UpdateError;762 pub const UpdateDebugInfoError = Dwarf.UpdateError;
...@@ -791,9 +791,31 @@ pub const File = struct {...@@ -791,9 +791,31 @@ pub const File = struct {
791 }791 }
792 }792 }
793793
794 /// When there is a ZCU, this is called exactly once per update, to indicate that all per-file
795 /// state (e.g. `Zcu.alive_files`) has been populated by the frontend, so can now be safely
796 /// accessed by the linker.
797 ///
798 /// This call occurs before any call to any of these functions:
799 /// * `updateNav`
800 /// * `updateFunc`
801 /// * `updateContainerType`
802 /// * `updateLineNumber`
803 ///
804 /// Asserts that the ZCU is not using the LLVM backend.
805 fn zcuFilesReady(base: *File, zcu: *Zcu) Error!void {
806 assert(zcu.llvm_object == null);
807 switch (base.tag) {
808 else => {},
809 inline .elf2 => |tag| {
810 dev.check(tag.devFeature());
811 return @as(*tag.Type(), @fieldParentPtr("base", base)).zcuFilesReady(zcu);
812 },
813 }
814 }
815
794 /// Asserts that the ZCU is not using the LLVM backend.816 /// Asserts that the ZCU is not using the LLVM backend.
795 fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) Error!void {817 fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) Error!void {
796 assert(base.comp.zcu.?.llvm_object == null);818 assert(pt.zcu.llvm_object == null);
797 const nav = pt.zcu.intern_pool.getNav(nav_index);819 const nav = pt.zcu.intern_pool.getNav(nav_index);
798 assert(nav.resolved.?.value != .none);820 assert(nav.resolved.?.value != .none);
799821
...@@ -809,30 +831,17 @@ pub const File = struct {...@@ -809,30 +831,17 @@ pub const File = struct {
809831
810 /// Never called when LLVM is codegenning the ZCU.832 /// Never called when LLVM is codegenning the ZCU.
811 fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Error!void {833 fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Error!void {
812 assert(base.comp.zcu.?.llvm_object == null);834 assert(pt.zcu.llvm_object == null);
813 switch (base.tag) {835 switch (base.tag) {
814 .lld => unreachable,836 .lld => unreachable,
815 else => {},837 else => {},
816 inline .elf, .c => |tag| {838 inline .elf, .elf2, .c, .coff2 => |tag| {
817 dev.check(tag.devFeature());839 dev.check(tag.devFeature());
818 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateContainerType(pt, ty, success);840 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateContainerType(pt, ty, success);
819 },841 },
820 }842 }
821 }843 }
822844
823 /// Never called when LLVM is codegenning the ZCU.
824 fn clearContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) Error!void {
825 assert(base.comp.zcu.?.llvm_object == null);
826 switch (base.tag) {
827 .lld => unreachable,
828 else => {},
829 inline .elf => |tag| {
830 dev.check(tag.devFeature());
831 return @as(*tag.Type(), @fieldParentPtr("base", base)).clearContainerType(pt, ty);
832 },
833 }
834 }
835
836 /// The active tag of `mir` is determined by the backend used for the module this function is in.845 /// The active tag of `mir` is determined by the backend used for the module this function is in.
837 /// Never called when LLVM is codegenning the ZCU.846 /// Never called when LLVM is codegenning the ZCU.
838 fn updateFunc(847 fn updateFunc(
...@@ -844,7 +853,7 @@ pub const File = struct {...@@ -844,7 +853,7 @@ pub const File = struct {
844 /// take ownership of an embedded slice and replace it with `&.{}` in `mir`.853 /// take ownership of an embedded slice and replace it with `&.{}` in `mir`.
845 mir: *codegen.AnyMir,854 mir: *codegen.AnyMir,
846 ) Error!void {855 ) Error!void {
847 assert(base.comp.zcu.?.llvm_object == null);856 assert(pt.zcu.llvm_object == null);
848 switch (base.tag) {857 switch (base.tag) {
849 .lld => unreachable,858 .lld => unreachable,
850 .plan9 => unreachable,859 .plan9 => unreachable,
...@@ -858,23 +867,49 @@ pub const File = struct {...@@ -858,23 +867,49 @@ pub const File = struct {
858 /// On an incremental update, fixup the line number of all `Nav`s at the given `TrackedInst`, because867 /// On an incremental update, fixup the line number of all `Nav`s at the given `TrackedInst`, because
859 /// its line number has changed. The ZIR instruction `ti_id` has tag `.declaration`.868 /// its line number has changed. The ZIR instruction `ti_id` has tag `.declaration`.
860 /// Never called when LLVM is codegenning the ZCU.869 /// Never called when LLVM is codegenning the ZCU.
861 fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) Error!void {870 fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index, line: u32) Error!void {
862 assert(base.comp.zcu.?.llvm_object == null);871 assert(pt.zcu.llvm_object == null);
863 {872 {
864 const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?;873 const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?;
865 const file = pt.zcu.fileByIndex(ti.file);874 const file = pt.zcu.fileByIndex(ti.file);
866 const inst = file.zir.?.instructions.get(@backingInt(ti.inst));875 const inst = file.zir.?.instructions.get(@backingInt(ti.inst));
867 assert(inst.tag == .declaration);876 switch (inst.tag) {
877 .declaration => {},
878 .extended => switch (inst.data.extended.opcode) {
879 .struct_decl,
880 .union_decl,
881 .enum_decl,
882 .opaque_decl,
883 .reify_enum,
884 .reify_struct,
885 .reify_union,
886 => {},
887 else => unreachable,
888 },
889 else => unreachable,
890 }
868 }891 }
869
870 switch (base.tag) {892 switch (base.tag) {
871 .lld => unreachable,893 .lld => unreachable,
872 .spirv => {},
873 .plan9 => unreachable,894 .plan9 => unreachable,
874 .elf2, .coff2 => {},895 .spirv => {},
896 .coff2 => {},
875 inline else => |tag| {897 inline else => |tag| {
876 dev.check(tag.devFeature());898 dev.check(tag.devFeature());
877 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id);899 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id, line);
900 },
901 }
902 }
903
904 fn lostTracking(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) Error!void {
905 assert(base.comp.zcu.?.llvm_object == null);
906 switch (base.tag) {
907 .lld => unreachable,
908 .plan9 => unreachable,
909 else => {},
910 inline .elf2 => |tag| {
911 dev.check(tag.devFeature());
912 return @as(*tag.Type(), @fieldParentPtr("base", base)).lostTracking(pt, ti_id);
878 },913 },
879 }914 }
880 }915 }
...@@ -984,7 +1019,7 @@ pub const File = struct {...@@ -984,7 +1019,7 @@ pub const File = struct {
984 pt: Zcu.PerThread,1019 pt: Zcu.PerThread,
985 export_indices: []const Zcu.Export.Index,1020 export_indices: []const Zcu.Export.Index,
986 ) Error!void {1021 ) Error!void {
987 assert(base.comp.zcu.?.llvm_object == null);1022 assert(pt.zcu.llvm_object == null);
9881023
989 crash_report.LinkerOp.start(base, pt.tid);1024 crash_report.LinkerOp.start(base, pt.tid);
990 defer crash_report.LinkerOp.stop(base, pt.tid);1025 defer crash_report.LinkerOp.stop(base, pt.tid);
...@@ -1019,7 +1054,7 @@ pub const File = struct {...@@ -1019,7 +1054,7 @@ pub const File = struct {
1019 /// the block/atom.1054 /// the block/atom.
1020 /// Never called when LLVM is codegenning the ZCU.1055 /// Never called when LLVM is codegenning the ZCU.
1021 pub fn getNavVAddr(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: RelocInfo) Error!u64 {1056 pub fn getNavVAddr(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: RelocInfo) Error!u64 {
1022 assert(base.comp.zcu.?.llvm_object == null);1057 assert(pt.zcu.llvm_object == null);
10231058
1024 switch (base.tag) {1059 switch (base.tag) {
1025 .lld => unreachable,1060 .lld => unreachable,
...@@ -1042,7 +1077,7 @@ pub const File = struct {...@@ -1042,7 +1077,7 @@ pub const File = struct {
1042 decl_val: InternPool.Index,1077 decl_val: InternPool.Index,
1043 decl_align: InternPool.Alignment,1078 decl_align: InternPool.Alignment,
1044 ) Error!SymbolId {1079 ) Error!SymbolId {
1045 assert(base.comp.zcu.?.llvm_object == null);1080 assert(pt.zcu.llvm_object == null);
10461081
1047 switch (base.tag) {1082 switch (base.tag) {
1048 .lld => unreachable,1083 .lld => unreachable,
...@@ -1308,7 +1343,7 @@ pub const File = struct {...@@ -1308,7 +1343,7 @@ pub const File = struct {
1308 };1343 };
1309 }1344 }
13101345
1311 pub fn devFeature(tag: Tag) dev.Feature {1346 fn devFeature(tag: Tag) dev.Feature {
1312 return @field(dev.Feature, @tagName(tag) ++ "_linker");1347 return @field(dev.Feature, @tagName(tag) ++ "_linker");
1313 }1348 }
1314 };1349 };
...@@ -1391,6 +1426,7 @@ pub const File = struct {...@@ -1391,6 +1426,7 @@ pub const File = struct {
1391 pub const SpirV = @import("link/SpirV.zig");1426 pub const SpirV = @import("link/SpirV.zig");
1392 pub const Wasm = @import("link/Wasm.zig");1427 pub const Wasm = @import("link/Wasm.zig");
1393 pub const Dwarf = @import("link/Dwarf.zig");1428 pub const Dwarf = @import("link/Dwarf.zig");
1429 pub const Dwarf2 = @import("link/Dwarf2.zig");
1394};1430};
13951431
1396pub const PrelinkTask = union(enum) {1432pub const PrelinkTask = union(enum) {
...@@ -1413,6 +1449,9 @@ pub const PrelinkTask = union(enum) {...@@ -1413,6 +1449,9 @@ pub const PrelinkTask = union(enum) {
1413 load_dso: Path,1449 load_dso: Path,
1414};1450};
1415pub const ZcuTask = union(enum) {1451pub const ZcuTask = union(enum) {
1452 /// Sent once per update, as the very first `ZcuTask` in the update. Indicates that all per-file
1453 /// state (e.g. `Zcu.alive_files`) is populated so can now be safely accessed by the linker.
1454 files_ready,
1416 /// Write the constant value for a Decl to the output file.1455 /// Write the constant value for a Decl to the output file.
1417 link_nav: InternPool.Nav.Index,1456 link_nav: InternPool.Nav.Index,
1418 /// Write the machine code for a function to the output file.1457 /// Write the machine code for a function to the output file.
...@@ -1424,7 +1463,11 @@ pub const ZcuTask = union(enum) {...@@ -1424,7 +1463,11 @@ pub const ZcuTask = union(enum) {
1424 ty: InternPool.Index,1463 ty: InternPool.Index,
1425 success: bool,1464 success: bool,
1426 },1465 },
1427 debug_update_line_number: InternPool.TrackedInst.Index,1466 debug_update_line_number: struct {
1467 inst: InternPool.TrackedInst.Index,
1468 line: u32,
1469 },
1470 lost_tracking: InternPool.TrackedInst.Index,
1428};1471};
14291472
1430pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {1473pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
...@@ -1616,6 +1659,16 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void...@@ -1616,6 +1659,16 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void
1616 var timer = comp.startTimer();1659 var timer = comp.startTimer();
16171660
1618 const maybe_nav: ?InternPool.Nav.Index = switch (task) {1661 const maybe_nav: ?InternPool.Nav.Index = switch (task) {
1662 .files_ready => {
1663 if (zcu.llvm_object != null) return;
1664 const lf = comp.bin_file orelse return;
1665 lf.zcuFilesReady(zcu) catch |err| switch (err) {
1666 error.Canceled => io.recancel(),
1667 error.AlreadyReported => return,
1668 error.OutOfMemory => return diags.setAllocFailure(),
1669 };
1670 return;
1671 },
1619 .link_nav => |nav_index| nav: {1672 .link_nav => |nav_index| nav: {
1620 const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);1673 const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
1621 const nav_prog_node = comp.link_prog_node.start(fqn_slice, 0);1674 const nav_prog_node = comp.link_prog_node.start(fqn_slice, 0);
...@@ -1661,32 +1714,40 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void...@@ -1661,32 +1714,40 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void
1661 break :nav ip.indexToKey(func).func.owner_nav;1714 break :nav ip.indexToKey(func).func.owner_nav;
1662 },1715 },
1663 .debug_update_container_type => |container_update| nav: {1716 .debug_update_container_type => |container_update| nav: {
1664 const name = Type.fromInterned(container_update.ty).containerTypeName(ip).toSlice(ip);1717 const fqn = Type.fromInterned(container_update.ty).containerTypeName(ip).fqn.toSlice(ip);
1665 const ty_prog_node = comp.link_prog_node.start(name, 0);1718 const ty_prog_node = comp.link_prog_node.start(fqn, 0);
1666 defer ty_prog_node.end();1719 defer ty_prog_node.end();
1667 if (zcu.llvm_object) |llvm_object| {1720 (if (zcu.llvm_object) |llvm_object|
1668 llvm_object.updateContainerType(pt, container_update.ty, container_update.success) catch |err| switch (err) {1721 llvm_object.updateContainerType(pt, container_update.ty, container_update.success)
1669 error.OutOfMemory => diags.setAllocFailure(),1722 else if (comp.bin_file) |lf|
1670 };1723 lf.updateContainerType(pt, container_update.ty, container_update.success)) catch |err| switch (err) {
1671 } else {1724 error.OutOfMemory => diags.setAllocFailure(),
1725 error.Canceled => io.recancel(),
1726 error.AlreadyReported => {},
1727 };
1728 break :nav null;
1729 },
1730 .debug_update_line_number => |line_update| nav: {
1731 const nav_prog_node = comp.link_prog_node.start("Update line number", 0);
1732 defer nav_prog_node.end();
1733 if (pt.zcu.llvm_object == null) {
1672 if (comp.bin_file) |lf| {1734 if (comp.bin_file) |lf| {
1673 lf.updateContainerType(pt, container_update.ty, container_update.success) catch |err| switch (err) {1735 lf.updateLineNumber(pt, line_update.inst, line_update.line) catch |err| switch (err) {
1674 error.OutOfMemory => diags.setAllocFailure(),1736 error.OutOfMemory => diags.setAllocFailure(),
1675 error.Canceled => io.recancel(),1737 else => |e| log.err("update line number failed: {s}", .{@errorName(e)}),
1676 error.AlreadyReported => {},
1677 };1738 };
1678 }1739 }
1679 }1740 }
1680 break :nav null;1741 break :nav null;
1681 },1742 },
1682 .debug_update_line_number => |ti| nav: {1743 .lost_tracking => |ti| nav: {
1683 const nav_prog_node = comp.link_prog_node.start("Update line number", 0);1744 const nav_prog_node = comp.link_prog_node.start("Lost tracking", 0);
1684 defer nav_prog_node.end();1745 defer nav_prog_node.end();
1685 if (pt.zcu.llvm_object == null) {1746 if (pt.zcu.llvm_object == null) {
1686 if (comp.bin_file) |lf| {1747 if (comp.bin_file) |lf| {
1687 lf.updateLineNumber(pt, ti) catch |err| switch (err) {1748 lf.lostTracking(pt, ti) catch |err| switch (err) {
1688 error.OutOfMemory => diags.setAllocFailure(),1749 error.OutOfMemory => diags.setAllocFailure(),
1689 else => |e| log.err("update line number failed: {s}", .{@errorName(e)}),1750 else => |e| log.err("lost tracking failed: {s}", .{@errorName(e)}),
1690 };1751 };
1691 }1752 }
1692 }1753 }
src/link/C.zig+19-18
...@@ -209,7 +209,7 @@ pub fn addConst(...@@ -209,7 +209,7 @@ pub fn addConst(
209 pt: Zcu.PerThread,209 pt: Zcu.PerThread,
210 pool_index: link.ConstPool.Index,210 pool_index: link.ConstPool.Index,
211 val: InternPool.Index,211 val: InternPool.Index,
212) Allocator.Error!void {212) link.Error!void {
213 const zcu = pt.zcu;213 const zcu = pt.zcu;
214 const gpa = zcu.comp.gpa;214 const gpa = zcu.comp.gpa;
215 assert(zcu.intern_pool.typeOf(val) == .type_type);215 assert(zcu.intern_pool.typeOf(val) == .type_type);
...@@ -310,7 +310,7 @@ pub fn updateConst(...@@ -310,7 +310,7 @@ pub fn updateConst(
310 pt: Zcu.PerThread,310 pt: Zcu.PerThread,
311 index: link.ConstPool.Index,311 index: link.ConstPool.Index,
312 val: InternPool.Index,312 val: InternPool.Index,
313) Allocator.Error!void {313) link.Error!void {
314 const zcu = pt.zcu;314 const zcu = pt.zcu;
315 const gpa = zcu.comp.gpa;315 const gpa = zcu.comp.gpa;
316316
...@@ -498,7 +498,7 @@ pub fn updateFunc(...@@ -498,7 +498,7 @@ pub fn updateFunc(
498 pt: Zcu.PerThread,498 pt: Zcu.PerThread,
499 func_index: InternPool.Index,499 func_index: InternPool.Index,
500 mir: *AnyMir,500 mir: *AnyMir,
501) Allocator.Error!void {501) link.Error!void {
502 const zcu = pt.zcu;502 const zcu = pt.zcu;
503 const gpa = zcu.gpa;503 const gpa = zcu.gpa;
504 const nav = zcu.funcInfo(func_index).owner_nav;504 const nav = zcu.funcInfo(func_index).owner_nav;
...@@ -536,11 +536,7 @@ pub fn updateFunc(...@@ -536,11 +536,7 @@ pub fn updateFunc(
536 try c.type_pool.flushPending(pt, .{ .c = c });536 try c.type_pool.flushPending(pt, .{ .c = c });
537}537}
538538
539pub fn updateNav(539pub fn updateNav(c: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void {
540 c: *C,
541 pt: Zcu.PerThread,
542 nav_index: InternPool.Nav.Index,
543) Allocator.Error!void {
544 const tracy = trace(@src());540 const tracy = trace(@src());
545 defer tracy.end();541 defer tracy.end();
546542
...@@ -603,7 +599,8 @@ pub fn updateNav(...@@ -603,7 +599,8 @@ pub fn updateNav(
603 const start = aw.written().len;599 const start = aw.written().len;
604 codegen.genDeclFwd(&dg, &aw.writer) catch |err| switch (err) {600 codegen.genDeclFwd(&dg, &aw.writer) catch |err| switch (err) {
605 error.AlreadyReported => return,601 error.AlreadyReported => return,
606 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,602 error.WriteFailed => return error.OutOfMemory,
603 error.Canceled, error.OutOfMemory => |e| return e,
607 };604 };
608 break :fwd_decl .{605 break :fwd_decl .{
609 .start = @intCast(start),606 .start = @intCast(start),
...@@ -617,7 +614,8 @@ pub fn updateNav(...@@ -617,7 +614,8 @@ pub fn updateNav(
617 const start = aw.written().len;614 const start = aw.written().len;
618 codegen.genDecl(&dg, &aw.writer) catch |err| switch (err) {615 codegen.genDecl(&dg, &aw.writer) catch |err| switch (err) {
619 error.AlreadyReported => return,616 error.AlreadyReported => return,
620 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,617 error.WriteFailed => return error.OutOfMemory,
618 error.Canceled, error.OutOfMemory => |e| return e,
621 };619 };
622 break :code .{620 break :code .{
623 .start = @intCast(start),621 .start = @intCast(start),
...@@ -655,7 +653,7 @@ fn updateUav(...@@ -655,7 +653,7 @@ fn updateUav(
655 pt: Zcu.PerThread,653 pt: Zcu.PerThread,
656 val: Value,654 val: Value,
657 rendered_decl: *RenderedDecl,655 rendered_decl: *RenderedDecl,
658) Allocator.Error!void {656) link.Error!void {
659 const tracy = trace(@src());657 const tracy = trace(@src());
660 defer tracy.end();658 defer tracy.end();
661659
...@@ -691,7 +689,8 @@ fn updateUav(...@@ -691,7 +689,8 @@ fn updateUav(
691 .init_val = val,689 .init_val = val,
692 }) catch |err| switch (err) {690 }) catch |err| switch (err) {
693 error.AlreadyReported => return,691 error.AlreadyReported => return,
694 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,692 error.WriteFailed => return error.OutOfMemory,
693 error.Canceled, error.OutOfMemory => |e| return e,
695 };694 };
696 break :fwd_decl .{695 break :fwd_decl .{
697 .start = @intCast(start),696 .start = @intCast(start),
...@@ -710,7 +709,8 @@ fn updateUav(...@@ -710,7 +709,8 @@ fn updateUav(
710 .init_val = val,709 .init_val = val,
711 }) catch |err| switch (err) {710 }) catch |err| switch (err) {
712 error.AlreadyReported => return,711 error.AlreadyReported => return,
713 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,712 error.WriteFailed => return error.OutOfMemory,
713 error.Canceled, error.OutOfMemory => |e| return e,
714 };714 };
715 break :code .{715 break :code .{
716 .start = @intCast(start),716 .start = @intCast(start),
...@@ -721,12 +721,13 @@ fn updateUav(...@@ -721,12 +721,13 @@ fn updateUav(
721 rendered_decl.ctype_deps = try c.addCTypeDependencies(pt, &dg.ctype_deps);721 rendered_decl.ctype_deps = try c.addCTypeDependencies(pt, &dg.ctype_deps);
722}722}
723723
724pub fn updateLineNumber(c: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) error{}!void {724pub fn updateLineNumber(c: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index, line: u32) error{}!void {
725 // The C backend does not currently emit "#line" directives. Even if it did, it would not be725 // The C backend does not currently emit "#line" directives. Even if it did, it would not be
726 // capable of updating those line numbers without re-generating the entire declaration.726 // capable of updating those line numbers without re-generating the entire declaration.
727 _ = c;727 _ = c;
728 _ = pt;728 _ = pt;
729 _ = ti_id;729 _ = ti_id;
730 _ = line;
730}731}
731732
732pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.Error!void {733pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.Error!void {
...@@ -1144,14 +1145,14 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog...@@ -1144,14 +1145,14 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog
1144 for (need_never_tail_funcs.keys()) |fn_nav| {1145 for (need_never_tail_funcs.keys()) |fn_nav| {
1145 codegen.genLazyCallModifierFn(&lazy_dg, fn_nav, .never_tail, &lazy_decls_aw.writer) catch |err| switch (err) {1146 codegen.genLazyCallModifierFn(&lazy_dg, fn_nav, .never_tail, &lazy_decls_aw.writer) catch |err| switch (err) {
1146 error.WriteFailed => return error.OutOfMemory,1147 error.WriteFailed => return error.OutOfMemory,
1147 error.OutOfMemory => |e| return e,1148 error.Canceled, error.OutOfMemory => |e| return e,
1148 error.AlreadyReported => unreachable,1149 error.AlreadyReported => unreachable,
1149 };1150 };
1150 }1151 }
1151 for (need_never_inline_funcs.keys()) |fn_nav| {1152 for (need_never_inline_funcs.keys()) |fn_nav| {
1152 codegen.genLazyCallModifierFn(&lazy_dg, fn_nav, .never_inline, &lazy_decls_aw.writer) catch |err| switch (err) {1153 codegen.genLazyCallModifierFn(&lazy_dg, fn_nav, .never_inline, &lazy_decls_aw.writer) catch |err| switch (err) {
1153 error.WriteFailed => return error.OutOfMemory,1154 error.WriteFailed => return error.OutOfMemory,
1154 error.OutOfMemory => |e| return e,1155 error.Canceled, error.OutOfMemory => |e| return e,
1155 error.AlreadyReported => unreachable,1156 error.AlreadyReported => unreachable,
1156 };1157 };
1157 }1158 }
...@@ -1343,7 +1344,7 @@ fn addCTypeDependencies(...@@ -1343,7 +1344,7 @@ fn addCTypeDependencies(
1343 c: *C,1344 c: *C,
1344 pt: Zcu.PerThread,1345 pt: Zcu.PerThread,
1345 deps: *const codegen.CType.Dependencies,1346 deps: *const codegen.CType.Dependencies,
1346) Allocator.Error!CTypeDependencies {1347) link.Error!CTypeDependencies {
1347 const gpa = pt.zcu.comp.gpa;1348 const gpa = pt.zcu.comp.gpa;
13481349
1349 try c.bigint_types.ensureUnusedCapacity(gpa, deps.bigint.count());1350 try c.bigint_types.ensureUnusedCapacity(gpa, deps.bigint.count());
...@@ -1399,7 +1400,7 @@ fn addCTypeDependencies(...@@ -1399,7 +1400,7 @@ fn addCTypeDependencies(
1399 };1400 };
1400}1401}
14011402
1402fn updateNewUavs(c: *C, pt: Zcu.PerThread, old_uavs_len: usize) Allocator.Error!void {1403fn updateNewUavs(c: *C, pt: Zcu.PerThread, old_uavs_len: usize) link.Error!void {
1403 const gpa = pt.zcu.comp.gpa;1404 const gpa = pt.zcu.comp.gpa;
1404 var index = old_uavs_len;1405 var index = old_uavs_len;
1405 while (index < c.uavs.count()) : (index += 1) {1406 while (index < c.uavs.count()) : (index += 1) {
src/link/Coff.zig+190-155
...@@ -13,7 +13,7 @@ const codegen = @import("../codegen.zig");...@@ -13,7 +13,7 @@ const codegen = @import("../codegen.zig");
13const Compilation = @import("../Compilation.zig");13const Compilation = @import("../Compilation.zig");
14const InternPool = @import("../InternPool.zig");14const InternPool = @import("../InternPool.zig");
15const link = @import("../link.zig");15const link = @import("../link.zig");
16const MappedFile = @import("MappedFile.zig");16const MappedFile = link.MappedFile;
17const target_util = @import("../target.zig");17const target_util = @import("../target.zig");
18const Type = @import("../Type.zig");18const Type = @import("../Type.zig");
19const Value = @import("../Value.zig");19const Value = @import("../Value.zig");
...@@ -536,7 +536,7 @@ pub const Member = struct {...@@ -536,7 +536,7 @@ pub const Member = struct {
536 const new_size = Alignment.@"4".forward(old_size + name.len + 1);536 const new_size = Alignment.@"4".forward(old_size + name.len + 1);
537 assert(new_size < comptime try std.math.powi(u64, 10, max_name_len - 1));537 assert(new_size < comptime try std.math.powi(u64, 10, max_name_len - 1));
538538
539 try Node.known.longnames_member.resizeLeaf(&coff.mf, gpa, new_size);539 try Node.known.longnames_member.resizeLeaf(gpa, &coff.mf, new_size);
540 const name_table_slice = Node.known.longnames_member.slice(&coff.mf);540 const name_table_slice = Node.known.longnames_member.slice(&coff.mf);
541 const name_slice = name_table_slice[@intCast(old_size)..][0 .. name.len + 1];541 const name_slice = name_table_slice[@intCast(old_size)..][0 .. name.len + 1];
542 @memcpy(name_slice[0..name.len], name);542 @memcpy(name_slice[0..name.len], name);
...@@ -1666,7 +1666,7 @@ fn create(...@@ -1666,7 +1666,7 @@ fn create(
1666 .global_pending_index = 0,1666 .global_pending_index = 0,
1667 .navs = .empty,1667 .navs = .empty,
1668 .uavs = .empty,1668 .uavs = .empty,
1669 .lazy = .initFill(.{1669 .lazy = comptime .initFill(.{
1670 .map = .empty,1670 .map = .empty,
1671 .pending_index = 0,1671 .pending_index = 0,
1672 }),1672 }),
...@@ -1840,13 +1840,13 @@ fn initHeaders(...@@ -1840,13 +1840,13 @@ fn initHeaders(
1840 coff.nodes.appendAssumeCapacity(.file);1840 coff.nodes.appendAssumeCapacity(.file);
18411841
1842 const header_ni = Node.known.header;1842 const header_ni = Node.known.header;
1843 assert(header_ni == try Node.known.file.addOnlyHeaderChild(&coff.mf, gpa, .{1843 assert(header_ni == try Node.known.file.addOnlyHeaderChild(gpa, &coff.mf, .{
1844 .alignment = coff.mf.flags.block_size,1844 .alignment = coff.mf.flags.block_size,
1845 }));1845 }));
1846 coff.nodes.appendAssumeCapacity(.header);1846 coff.nodes.appendAssumeCapacity(.header);
18471847
1848 const coff_parent_ni: MappedFile.Node.Index = if (is_archive) parent: {1848 const coff_parent_ni: MappedFile.Node.Index = if (is_archive) parent: {
1849 assert(try Node.known.file.addHeaderChildAfter(&coff.mf, gpa, .wrap(header_ni), .{1849 assert(try Node.known.file.addHeaderChildAfter(gpa, &coff.mf, .wrap(header_ni), .{
1850 .size = std.coff.archive_signature.len,1850 .size = std.coff.archive_signature.len,
1851 .alignment = .@"4",1851 .alignment = .@"4",
1852 }) == Node.known.signature);1852 }) == Node.known.signature);
...@@ -1879,7 +1879,7 @@ fn initHeaders(...@@ -1879,7 +1879,7 @@ fn initHeaders(
1879 const zcu_member = zcu_mi.get(coff);1879 const zcu_member = zcu_mi.get(coff);
1880 try zcu_member.initHeader(coff, zcu.main_mod.fully_qualified_name, timestamp);1880 try zcu_member.initHeader(coff, zcu.main_mod.fully_qualified_name, timestamp);
18811881
1882 assert(try zcu_member.content_ni.addOnlyHeaderChild(&coff.mf, gpa, .{1882 assert(try zcu_member.content_ni.addOnlyHeaderChild(gpa, &coff.mf, .{
1883 .size = @sizeOf(std.coff.Header),1883 .size = @sizeOf(std.coff.Header),
1884 .alignment = .@"4",1884 .alignment = .@"4",
1885 }) == Node.known.coff_header);1885 }) == Node.known.coff_header);
...@@ -1894,13 +1894,13 @@ fn initHeaders(...@@ -1894,13 +1894,13 @@ fn initHeaders(
1894 // no other members then the last linker member (longnames) needs to expand1894 // no other members then the last linker member (longnames) needs to expand
1895 // to fill the padding at the end of the file.1895 // to fill the padding at the end of the file.
1896 while (coff.nodes.len < Node.known_count) {1896 while (coff.nodes.len < Node.known_count) {
1897 _ = try Node.known.header.addHeaderChildAfter(&coff.mf, gpa, .none, .{});1897 _ = try Node.known.header.addHeaderChildAfter(gpa, &coff.mf, .none, .{});
1898 coff.nodes.appendAssumeCapacity(.placeholder);1898 coff.nodes.appendAssumeCapacity(.placeholder);
1899 }1899 }
19001900
1901 return;1901 return;
1902 } else parent: {1902 } else parent: {
1903 assert(try header_ni.addOnlyHeaderChild(&coff.mf, gpa, .{1903 assert(try header_ni.addOnlyHeaderChild(gpa, &coff.mf, .{
1904 .size = if (is_image) msdos_stub.len + std.coff.pe_signature.len else 0,1904 .size = if (is_image) msdos_stub.len + std.coff.pe_signature.len else 0,
1905 .alignment = .@"4",1905 .alignment = .@"4",
1906 }) == Node.known.signature);1906 }) == Node.known.signature);
...@@ -1913,12 +1913,12 @@ fn initHeaders(...@@ -1913,12 +1913,12 @@ fn initHeaders(
19131913
1914 // TODO: Not ideal to have this many placeholder nodes - use two distinct `Node.known` types?1914 // TODO: Not ideal to have this many placeholder nodes - use two distinct `Node.known` types?
1915 while (true) {1915 while (true) {
1916 const placeholder_ni = try Node.known.file.addHeaderChildAfter(&coff.mf, gpa, .none, .{});1916 const placeholder_ni = try Node.known.file.addHeaderChildAfter(gpa, &coff.mf, .none, .{});
1917 coff.nodes.appendAssumeCapacity(.placeholder);1917 coff.nodes.appendAssumeCapacity(.placeholder);
1918 if (placeholder_ni == Node.known.zcu_member) break;1918 if (placeholder_ni == Node.known.zcu_member) break;
1919 }1919 }
19201920
1921 assert(try header_ni.addHeaderChildAfter(&coff.mf, gpa, .wrap(Node.known.signature), .{1921 assert(try header_ni.addHeaderChildAfter(gpa, &coff.mf, .wrap(Node.known.signature), .{
1922 .size = @sizeOf(std.coff.Header),1922 .size = @sizeOf(std.coff.Header),
1923 .alignment = .@"4",1923 .alignment = .@"4",
1924 }) == Node.known.coff_header);1924 }) == Node.known.coff_header);
...@@ -1949,7 +1949,7 @@ fn initHeaders(...@@ -1949,7 +1949,7 @@ fn initHeaders(
1949 }1949 }
19501950
1951 const optional_header_ni = Node.known.optional_header;1951 const optional_header_ni = Node.known.optional_header;
1952 assert(optional_header_ni == try coff_parent_ni.addHeaderChildAfter(&coff.mf, gpa, .wrap(Node.known.coff_header), .{1952 assert(optional_header_ni == try coff_parent_ni.addHeaderChildAfter(gpa, &coff.mf, .wrap(Node.known.coff_header), .{
1953 .size = optional_header_size,1953 .size = optional_header_size,
1954 .alignment = .@"4",1954 .alignment = .@"4",
1955 }));1955 }));
...@@ -2060,7 +2060,7 @@ fn initHeaders(...@@ -2060,7 +2060,7 @@ fn initHeaders(
2060 }2060 }
20612061
2062 const data_directories_ni = Node.known.data_directories;2062 const data_directories_ni = Node.known.data_directories;
2063 assert(data_directories_ni == try coff_parent_ni.addHeaderChildAfter(&coff.mf, gpa, .wrap(optional_header_ni), .{2063 assert(data_directories_ni == try coff_parent_ni.addHeaderChildAfter(gpa, &coff.mf, .wrap(optional_header_ni), .{
2064 .size = data_directories_size,2064 .size = data_directories_size,
2065 .alignment = .@"4",2065 .alignment = .@"4",
2066 }));2066 }));
...@@ -2075,7 +2075,7 @@ fn initHeaders(...@@ -2075,7 +2075,7 @@ fn initHeaders(
2075 }2075 }
20762076
2077 const section_table_ni = Node.known.section_table;2077 const section_table_ni = Node.known.section_table;
2078 assert(section_table_ni == try coff_parent_ni.addHeaderChildAfter(&coff.mf, gpa, .wrap(data_directories_ni), .{2078 assert(section_table_ni == try coff_parent_ni.addHeaderChildAfter(gpa, &coff.mf, .wrap(data_directories_ni), .{
2079 .alignment = .@"4",2079 .alignment = .@"4",
2080 }));2080 }));
2081 coff.nodes.appendAssumeCapacity(.section_table);2081 coff.nodes.appendAssumeCapacity(.section_table);
...@@ -2084,13 +2084,13 @@ fn initHeaders(...@@ -2084,13 +2084,13 @@ fn initHeaders(
20842084
2085 if (!is_image) {2085 if (!is_image) {
2086 // TODO: These two nodes could be inside one movable node?2086 // TODO: These two nodes could be inside one movable node?
2087 coff.symbol_table.ni = try coff_parent_ni.addHeaderChildAfter(&coff.mf, gpa, .wrap(section_table_ni), .{2087 coff.symbol_table.ni = try coff_parent_ni.addHeaderChildAfter(gpa, &coff.mf, .wrap(section_table_ni), .{
2088 .alignment = .@"2",2088 .alignment = .@"2",
2089 .moved = true,2089 .moved = true,
2090 });2090 });
2091 coff.nodes.appendAssumeCapacity(.symbol_table);2091 coff.nodes.appendAssumeCapacity(.symbol_table);
20922092
2093 coff.symbol_table.strings_ni = try coff_parent_ni.addHeaderChildAfter(&coff.mf, gpa, .wrap(coff.symbol_table.ni), .{2093 coff.symbol_table.strings_ni = try coff_parent_ni.addHeaderChildAfter(gpa, &coff.mf, .wrap(coff.symbol_table.ni), .{
2094 .size = @sizeOf(u32),2094 .size = @sizeOf(u32),
2095 .resized = true,2095 .resized = true,
2096 });2096 });
...@@ -2143,7 +2143,7 @@ fn initHeaders(...@@ -2143,7 +2143,7 @@ fn initHeaders(
2143 coff.mf.flags.block_size,2143 coff.mf.flags.block_size,
2144 .{ .read = true, .initialized = true },2144 .{ .read = true, .initialized = true },
2145 )).symbol(coff).node(coff);2145 )).symbol(coff).node(coff);
2146 coff.import_table.ni = try import_table_parent_ni.addFloatingChild(&coff.mf, gpa, .{2146 coff.import_table.ni = try import_table_parent_ni.addFloatingChild(gpa, &coff.mf, .{
2147 .alignment = .@"4",2147 .alignment = .@"4",
2148 });2148 });
2149 coff.nodes.appendAssumeCapacity(.import_directory_table);2149 coff.nodes.appendAssumeCapacity(.import_directory_table);
...@@ -2154,7 +2154,7 @@ fn initHeaders(...@@ -2154,7 +2154,7 @@ fn initHeaders(
2154 .{ .read = true, .initialized = true },2154 .{ .read = true, .initialized = true },
2155 )).symbol(coff).node(coff);2155 )).symbol(coff).node(coff);
21562156
2157 coff.export_table.export_directory_table_ni = try coff.export_table.ni.addHeaderChildAfter(&coff.mf, gpa, coff.export_table.ni.last(&coff.mf), .{2157 coff.export_table.export_directory_table_ni = try coff.export_table.ni.addHeaderChildAfter(gpa, &coff.mf, coff.export_table.ni.last(&coff.mf), .{
2158 .size = @sizeOf(std.coff.ExportDirectoryTable) + file_name.len + 1,2158 .size = @sizeOf(std.coff.ExportDirectoryTable) + file_name.len + 1,
2159 .moved = true,2159 .moved = true,
2160 });2160 });
...@@ -2165,7 +2165,7 @@ fn initHeaders(...@@ -2165,7 +2165,7 @@ fn initHeaders(
2165 @memcpy(table_slice[name_index..][0..file_name.len], file_name[0..file_name.len]);2165 @memcpy(table_slice[name_index..][0..file_name.len], file_name[0..file_name.len]);
2166 @memset(table_slice[name_index + file_name.len ..], 0);2166 @memset(table_slice[name_index + file_name.len ..], 0);
21672167
2168 const export_address_table_ni = try coff.export_table.ni.addFloatingChild(&coff.mf, gpa, .{2168 const export_address_table_ni = try coff.export_table.ni.addFloatingChild(gpa, &coff.mf, .{
2169 .alignment = .of(std.coff.ExportAddressTableEntry),2169 .alignment = .of(std.coff.ExportAddressTableEntry),
2170 .moved = true,2170 .moved = true,
2171 });2171 });
...@@ -2181,19 +2181,19 @@ fn initHeaders(...@@ -2181,19 +2181,19 @@ fn initHeaders(
2181 export_address_table_sym.section_number =2181 export_address_table_sym.section_number =
2182 coff.getNode(coff.export_table.ni).pseudo_section.symbol(coff).get(coff).section_number;2182 coff.getNode(coff.export_table.ni).pseudo_section.symbol(coff).get(coff).section_number;
21832183
2184 coff.export_table.name_pointer_table_ni = try coff.export_table.ni.addFloatingChild(&coff.mf, gpa, .{2184 coff.export_table.name_pointer_table_ni = try coff.export_table.ni.addFloatingChild(gpa, &coff.mf, .{
2185 .alignment = .of(std.coff.ExportNamePointerTableEntry),2185 .alignment = .of(std.coff.ExportNamePointerTableEntry),
2186 .moved = true,2186 .moved = true,
2187 });2187 });
2188 coff.nodes.appendAssumeCapacity(.export_name_pointer_table);2188 coff.nodes.appendAssumeCapacity(.export_name_pointer_table);
21892189
2190 coff.export_table.ordinal_table_ni = try coff.export_table.ni.addFloatingChild(&coff.mf, gpa, .{2190 coff.export_table.ordinal_table_ni = try coff.export_table.ni.addFloatingChild(gpa, &coff.mf, .{
2191 .alignment = .of(std.coff.ExportOrdinalTableEntry),2191 .alignment = .of(std.coff.ExportOrdinalTableEntry),
2192 .moved = true,2192 .moved = true,
2193 });2193 });
2194 coff.nodes.appendAssumeCapacity(.export_ordinal_table);2194 coff.nodes.appendAssumeCapacity(.export_ordinal_table);
21952195
2196 coff.export_table.name_table_ni = try coff.export_table.ni.addFloatingChild(&coff.mf, gpa, .{2196 coff.export_table.name_table_ni = try coff.export_table.ni.addFloatingChild(gpa, &coff.mf, .{
2197 .alignment = .of(u8),2197 .alignment = .of(u8),
2198 .moved = true,2198 .moved = true,
2199 });2199 });
...@@ -2286,7 +2286,7 @@ pub fn initBuiltins(coff: *Coff) !void {...@@ -2286,7 +2286,7 @@ pub fn initBuiltins(coff: *Coff) !void {
2286 const list_len_si = try coff.globalSymbol(.{ .name = list.global, .type = .data });2286 const list_len_si = try coff.globalSymbol(.{ .name = list.global, .type = .data });
2287 const list_len_sym = list_len_si.get(coff);2287 const list_len_sym = list_len_si.get(coff);
2288 list_len_sym.setExtra(.{ .size = addr_info.size });2288 list_len_sym.setExtra(.{ .size = addr_info.size });
2289 list_len_sym.ni = .wrap(try start_sym.ni.unwrap().?.addHeaderChildAfter(&coff.mf, gpa, .none, .{2289 list_len_sym.ni = .wrap(try start_sym.ni.unwrap().?.addHeaderChildAfter(gpa, &coff.mf, .none, .{
2290 .size = addr_info.size,2290 .size = addr_info.size,
2291 }));2291 }));
2292 coff.nodes.appendAssumeCapacity(.{ .builtin = list_len_si });2292 coff.nodes.appendAssumeCapacity(.{ .builtin = list_len_si });
...@@ -2307,7 +2307,7 @@ pub fn initBuiltins(coff: *Coff) !void {...@@ -2307,7 +2307,7 @@ pub fn initBuiltins(coff: *Coff) !void {
2307 const list_end_si = coff.addSymbolAssumeCapacity();2307 const list_end_si = coff.addSymbolAssumeCapacity();
2308 const list_end_sym = list_end_si.get(coff);2308 const list_end_sym = list_end_si.get(coff);
2309 list_end_sym.setExtra(.{ .size = addr_info.size });2309 list_end_sym.setExtra(.{ .size = addr_info.size });
2310 list_end_sym.ni = .wrap(try end_sym.ni.unwrap().?.addHeaderChildAfter(&coff.mf, gpa, .none, .{2310 list_end_sym.ni = .wrap(try end_sym.ni.unwrap().?.addHeaderChildAfter(gpa, &coff.mf, .none, .{
2311 .size = addr_info.size,2311 .size = addr_info.size,
2312 }));2312 }));
2313 coff.nodes.appendAssumeCapacity(.{ .builtin = list_end_si });2313 coff.nodes.appendAssumeCapacity(.{ .builtin = list_end_si });
...@@ -2723,7 +2723,7 @@ fn getOrPutSymbolName(coff: *Coff, name: []const u8, opt_string: ?String) !Symbo...@@ -2723,7 +2723,7 @@ fn getOrPutSymbolName(coff: *Coff, name: []const u8, opt_string: ?String) !Symbo
2723 const string_index = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf)[1];2723 const string_index = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf)[1];
2724 string_gop.value_ptr.* = @fromBackingInt(@intCast(string_index));2724 string_gop.value_ptr.* = @fromBackingInt(@intCast(string_index));
27252725
2726 try coff.symbol_table.strings_ni.resizeLeaf(&coff.mf, gpa, string_index + name.len + 1);2726 try coff.symbol_table.strings_ni.resizeLeaf(gpa, &coff.mf, string_index + name.len + 1);
2727 const slice = coff.symbol_table.strings_ni.slice(&coff.mf);2727 const slice = coff.symbol_table.strings_ni.slice(&coff.mf);
2728 @memcpy(slice[@intCast(string_index)..][0..name.len], name);2728 @memcpy(slice[@intCast(string_index)..][0..name.len], name);
2729 slice[@intCast(string_index + name.len)] = 0;2729 slice[@intCast(string_index + name.len)] = 0;
...@@ -2948,7 +2948,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind,...@@ -2948,7 +2948,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind,
2948 const comp = coff.base.comp;2948 const comp = coff.base.comp;
2949 const gpa = comp.gpa;2949 const gpa = comp.gpa;
29502950
2951 const header_ni = try Node.known.file.addHeaderChildAfter(&coff.mf, gpa, Node.known.file.last(&coff.mf), .{2951 const header_ni = try Node.known.file.addHeaderChildAfter(gpa, &coff.mf, Node.known.file.last(&coff.mf), .{
2952 .size = @sizeOf(std.coff.ArchiveMemberHeader),2952 .size = @sizeOf(std.coff.ArchiveMemberHeader),
2953 .alignment = .@"2",2953 .alignment = .@"2",
2954 .moved = true,2954 .moved = true,
...@@ -2960,7 +2960,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind,...@@ -2960,7 +2960,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind,
2960 .first_linker, .second_linker, .longnames, .coff => .@"4",2960 .first_linker, .second_linker, .longnames, .coff => .@"4",
2961 else => .@"2",2961 else => .@"2",
2962 };2962 };
2963 const content_ni = try Node.known.file.addHeaderChildAfter(&coff.mf, gpa, .wrap(header_ni), .{2963 const content_ni = try Node.known.file.addHeaderChildAfter(gpa, &coff.mf, .wrap(header_ni), .{
2964 .alignment = content_align,2964 .alignment = content_align,
2965 .size = content_align.forward(size),2965 .size = content_align.forward(size),
2966 .resized = size > 0,2966 .resized = size > 0,
...@@ -2989,7 +2989,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind,...@@ -2989,7 +2989,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind,
2989 const old_size = Node.known.second_linker_member.location(&coff.mf).resolve(&coff.mf)[1];2989 const old_size = Node.known.second_linker_member.location(&coff.mf).resolve(&coff.mf)[1];
2990 const old_header_size = new_num_members * @sizeOf(u32);2990 const old_header_size = new_num_members * @sizeOf(u32);
2991 const trailing_size: usize = @intCast(old_size - old_header_size);2991 const trailing_size: usize = @intCast(old_size - old_header_size);
2992 try Node.known.second_linker_member.resizeLeaf(&coff.mf, gpa, old_size + @sizeOf(u32));2992 try Node.known.second_linker_member.resizeLeaf(gpa, &coff.mf, old_size + @sizeOf(u32));
29932993
2994 const slice = Node.known.second_linker_member.slice(&coff.mf);2994 const slice = Node.known.second_linker_member.slice(&coff.mf);
2995 @memmove(2995 @memmove(
...@@ -3060,7 +3060,7 @@ fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void {...@@ -3060,7 +3060,7 @@ fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void {
3060 {3060 {
3061 const old_header_size: usize = @intCast(@sizeOf(u32) + @backingInt(mfli) * @sizeOf(u32));3061 const old_header_size: usize = @intCast(@sizeOf(u32) + @backingInt(mfli) * @sizeOf(u32));
3062 const new_header_size: usize = @intCast(old_header_size + @sizeOf(u32));3062 const new_header_size: usize = @intCast(old_header_size + @sizeOf(u32));
3063 try Node.known.first_linker_member.resizeLeaf(&coff.mf, gpa, Alignment.@"4".forward(new_header_size + new_string_table_size));3063 try Node.known.first_linker_member.resizeLeaf(gpa, &coff.mf, Alignment.@"4".forward(new_header_size + new_string_table_size));
30643064
3065 const slice = Node.known.first_linker_member.slice(&coff.mf);3065 const slice = Node.known.first_linker_member.slice(&coff.mf);
3066 @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]);3066 @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]);
...@@ -3074,7 +3074,7 @@ fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void {...@@ -3074,7 +3074,7 @@ fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void {
3074 const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr());3074 const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr());
3075 const old_header_size = 2 * @sizeOf(u32) + num_members * @sizeOf(u32) + @backingInt(mfli) * @sizeOf(u16);3075 const old_header_size = 2 * @sizeOf(u32) + num_members * @sizeOf(u32) + @backingInt(mfli) * @sizeOf(u16);
3076 const new_header_size = old_header_size + @sizeOf(u16);3076 const new_header_size = old_header_size + @sizeOf(u16);
3077 try Node.known.second_linker_member.resizeLeaf(&coff.mf, gpa, Alignment.@"4".forward(new_header_size + new_string_table_size));3077 try Node.known.second_linker_member.resizeLeaf(gpa, &coff.mf, Alignment.@"4".forward(new_header_size + new_string_table_size));
30783078
3079 const old_needs_sort = coff.pending_members.get(Member.Index.second) != null;3079 const old_needs_sort = coff.pending_members.get(Member.Index.second) != null;
3080 const needs_sort = old_needs_sort or (if (coff.lib_string_table.items.len > 0)3080 const needs_sort = old_needs_sort or (if (coff.lib_string_table.items.len > 0)
...@@ -3108,7 +3108,7 @@ fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void {...@@ -3108,7 +3108,7 @@ fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void {
3108 coff.member_prog_node.increaseEstimatedTotalItems(1);3108 coff.member_prog_node.increaseEstimatedTotalItems(1);
3109}3109}
31103110
3111fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {3111fn flushSymbolTableEntry(coff: *Coff, index: u32) !void {
3112 assert(!coff.isImage());3112 assert(!coff.isImage());
3113 const gpa = coff.base.comp.gpa;3113 const gpa = coff.base.comp.gpa;
31143114
...@@ -3119,7 +3119,6 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {...@@ -3119,7 +3119,6 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
3119 assert(sym.ni != .none or sym.gmi != .none);3119 assert(sym.ni != .none or sym.gmi != .none);
31203120
3121 const entry = coff.symbolTableEntryPtr(sti.*) orelse entry: {3121 const entry = coff.symbolTableEntryPtr(sti.*) orelse entry: {
3122 var buf: [15]u8 = undefined;
3123 const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType =3122 const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType =
3124 if (sym.gmi != .none) blk: {3123 if (sym.gmi != .none) blk: {
3125 const name = sym.gmi.name(coff);3124 const name = sym.gmi.name(coff);
...@@ -3148,21 +3147,22 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {...@@ -3148,21 +3147,22 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
3148 };3147 };
3149 },3148 },
3150 .uav => |umi| {3149 .uav => |umi| {
3151 var w = Io.Writer.fixed(&buf);3150 var name_buf: [std.fmt.count("__anon_{d}", .{std.math.maxInt(u32)})]u8 = undefined;
3152 w.print("__anon_{x}", .{umi.uavValue(coff)}) catch unreachable;3151 const name = std.mem.print(&name_buf, "__anon_{d}", .{umi}) catch unreachable;
3153 break :blk .{3152 break :blk .{
3154 try coff.getOrPutSymbolName(w.buffered(), null),3153 try coff.getOrPutSymbolName(name, null),
3155 0,3154 0,
3156 .NULL,3155 .NULL,
3157 };3156 };
3158 },3157 },
3159 inline .lazy_code, .lazy_const_data => |mi, tag| {3158 inline .lazy_code, .lazy_const_data => |mi, tag| {
3160 const lazy_sym = mi.lazySymbol(coff);3159 const lazy_sym = mi.lazySymbol(coff);
3161 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{3160 var name_buf: [
3162 @tagName(lazy_sym.kind),3161 std.fmt.count("__lazy_const_data_{d}", .{std.math.maxInt(u32)})
3163 Type.fromInterned(lazy_sym.ty).fmt(pt),3162 ]u8 = undefined;
3164 });3163 const name = std.mem.print(&name_buf, "__lazy_{t}_{d}", .{
3165 defer gpa.free(name);3164 lazy_sym.kind, mi,
3165 }) catch unreachable;
31663166
3167 const string = try coff.getOrPutString(name);3167 const string = try coff.getOrPutString(name);
3168 break :blk .{3168 break :blk .{
...@@ -3181,7 +3181,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {...@@ -3181,7 +3181,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
3181 const new_num_symbols = old_num_symbols + 1 + num_aux_symbols;3181 const new_num_symbols = old_num_symbols + 1 + num_aux_symbols;
3182 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);3182 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);
31833183
3184 try coff.symbol_table.ni.resizeLeaf(&coff.mf, gpa, new_num_symbols * std.coff.Symbol.sizeOf());3184 try coff.symbol_table.ni.resizeLeaf(gpa, &coff.mf, new_num_symbols * std.coff.Symbol.sizeOf());
31853185
3186 sti.* = .wrap(old_num_symbols);3186 sti.* = .wrap(old_num_symbols);
3187 si.flushSymbolTableIndex(coff);3187 si.flushSymbolTableIndex(coff);
...@@ -3317,7 +3317,7 @@ fn flushInputSection(coff: *Coff, isi: Node.InputSection.Index) !void {...@@ -3317,7 +3317,7 @@ fn flushInputSection(coff: *Coff, isi: Node.InputSection.Index) !void {
3317 try fr.seekTo(file_loc.offset);3317 try fr.seekTo(file_loc.offset);
3318 var nw: MappedFile.Node.Writer = undefined;3318 var nw: MappedFile.Node.Writer = undefined;
3319 const si = isi.symbol(coff);3319 const si = isi.symbol(coff);
3320 si.node(coff).writer(&coff.mf, gpa, &nw);3320 si.node(coff).writer(gpa, &coff.mf, &nw);
3321 defer nw.deinit();3321 defer nw.deinit();
3322 log.debug("flushInputSection({f}{f}, {s}, {d}, n{d})", .{3322 log.debug("flushInputSection({f}{f}, {s}, {d}, n{d})", .{
3323 path,3323 path,
...@@ -3345,12 +3345,12 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S...@@ -3345,12 +3345,12 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S
3345 const section_table_len = section_index + 1;3345 const section_table_len = section_index + 1;
3346 coff.targetStore(&coff_header.number_of_sections, section_table_len);3346 coff.targetStore(&coff_header.number_of_sections, section_table_len);
3347 try Node.known.section_table.resizeLeaf(3347 try Node.known.section_table.resizeLeaf(
3348 &coff.mf,
3349 gpa,3348 gpa,
3349 &coff.mf,
3350 @sizeOf(std.coff.SectionHeader) * section_table_len,3350 @sizeOf(std.coff.SectionHeader) * section_table_len,
3351 );3351 );
33523352
3353 const ni = try coff.sectionParent().addFloatingChild(&coff.mf, gpa, .{3353 const ni = try coff.sectionParent().addFloatingChild(gpa, &coff.mf, .{
3354 .alignment = coff.mf.flags.block_size,3354 .alignment = coff.mf.flags.block_size,
3355 .moved = true,3355 .moved = true,
3356 .bubbles_moved = false,3356 .bubbles_moved = false,
...@@ -3486,7 +3486,7 @@ fn pseudoSectionMapIndex(...@@ -3486,7 +3486,7 @@ fn pseudoSectionMapIndex(
34863486
3487 try coff.nodes.ensureUnusedCapacity(gpa, 1);3487 try coff.nodes.ensureUnusedCapacity(gpa, 1);
3488 try coff.symbols.ensureUnusedCapacity(gpa, 1);3488 try coff.symbols.ensureUnusedCapacity(gpa, 1);
3489 const ni = try parent.node(coff).addFloatingChild(&coff.mf, gpa, .{ .alignment = alignment });3489 const ni = try parent.node(coff).addFloatingChild(gpa, &coff.mf, .{ .alignment = alignment });
3490 const si = coff.addSymbolAssumeCapacity();3490 const si = coff.addSymbolAssumeCapacity();
3491 pseudo_section_gop.value_ptr.* = si;3491 pseudo_section_gop.value_ptr.* = si;
3492 const sym = si.get(coff);3492 const sym = si.get(coff);
...@@ -3560,7 +3560,7 @@ fn objectSectionMapIndex(...@@ -3560,7 +3560,7 @@ fn objectSectionMapIndex(
3560 }3560 }
3561 }3561 }
3562 }3562 }
3563 const ni = try parent_ni.addHeaderChildAfter(&coff.mf, gpa, prev_oni, .{3563 const ni = try parent_ni.addHeaderChildAfter(gpa, &coff.mf, prev_oni, .{
3564 .alignment = alignment,3564 .alignment = alignment,
3565 });3565 });
3566 const si = coff.addSymbolAssumeCapacity();3566 const si = coff.addSymbolAssumeCapacity();
...@@ -3579,13 +3579,13 @@ fn objectSectionMapIndex(...@@ -3579,13 +3579,13 @@ fn objectSectionMapIndex(
3579 const parent_alignment = parent_ni.alignment(&coff.mf);3579 const parent_alignment = parent_ni.alignment(&coff.mf);
3580 if (alignment.compare(.gt, parent_alignment)) {3580 if (alignment.compare(.gt, parent_alignment)) {
3581 log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment });3581 log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment });
3582 try parent_ni.realign(&coff.mf, gpa, alignment);3582 try parent_ni.realign(gpa, &coff.mf, alignment);
3583 }3583 }
35843584
3585 const old_alignment = sym.ni.unwrap().?.alignment(&coff.mf);3585 const old_alignment = sym.ni.unwrap().?.alignment(&coff.mf);
3586 if (alignment.compare(.gt, old_alignment)) {3586 if (alignment.compare(.gt, old_alignment)) {
3587 log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment });3587 log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment });
3588 try sym.ni.unwrap().?.realign(&coff.mf, gpa, alignment);3588 try sym.ni.unwrap().?.realign(gpa, &coff.mf, alignment);
3589 }3589 }
35903590
3591 try coff.verifyParentSectionAttributes(3591 try coff.verifyParentSectionAttributes(
...@@ -3742,9 +3742,9 @@ fn addRelocAssumeCapacity(...@@ -3742,9 +3742,9 @@ fn addRelocAssumeCapacity(
3742 coff.targetStore(&aux_ptr.number_of_relocations, new_num_relocations);3742 coff.targetStore(&aux_ptr.number_of_relocations, new_num_relocations);
37433743
3744 if (section.relocation_table_ni.unwrap()) |relocation_table_ni| {3744 if (section.relocation_table_ni.unwrap()) |relocation_table_ni| {
3745 try relocation_table_ni.resizeLeaf(&coff.mf, gpa, new_size);3745 try relocation_table_ni.resizeLeaf(gpa, &coff.mf, new_size);
3746 } else {3746 } else {
3747 section.relocation_table_ni = .wrap(try coff.sectionParent().addFloatingChild(&coff.mf, gpa, .{3747 section.relocation_table_ni = .wrap(try coff.sectionParent().addFloatingChild(gpa, &coff.mf, .{
3748 .size = new_size,3748 .size = new_size,
3749 .alignment = .@"2",3749 .alignment = .@"2",
3750 .moved = true,3750 .moved = true,
...@@ -4094,7 +4094,7 @@ fn loadObject(...@@ -4094,7 +4094,7 @@ fn loadObject(
4094 {4094 {
4095 // TODO: This should be deferred to an idle task (but resize it here!)4095 // TODO: This should be deferred to an idle task (but resize it here!)
4096 var nw: MappedFile.Node.Writer = undefined;4096 var nw: MappedFile.Node.Writer = undefined;
4097 member.content_ni.writer(&coff.mf, gpa, &nw);4097 member.content_ni.writer(gpa, &coff.mf, &nw);
4098 defer nw.deinit();4098 defer nw.deinit();
40994099
4100 try fr.seekTo(fl.offset);4100 try fr.seekTo(fl.offset);
...@@ -4653,7 +4653,7 @@ fn loadObject(...@@ -4653,7 +4653,7 @@ fn loadObject(
4653 if (section.parent_si == .null) continue;4653 if (section.parent_si == .null) continue;
46544654
4655 const alignment: Alignment = .fromByteUnits(section.header.flags.ALIGN.toByteUnits() orelse 1);4655 const alignment: Alignment = .fromByteUnits(section.header.flags.ALIGN.toByteUnits() orelse 1);
4656 const ni = try section.parent_si.node(coff).addFloatingChild(&coff.mf, gpa, .{4656 const ni = try section.parent_si.node(coff).addFloatingChild(gpa, &coff.mf, .{
4657 .size = alignment.forward(section.header.size_of_raw_data),4657 .size = alignment.forward(section.header.size_of_raw_data),
4658 .alignment = alignment,4658 .alignment = alignment,
4659 .moved = true,4659 .moved = true,
...@@ -5064,7 +5064,9 @@ fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) Loa...@@ -5064,7 +5064,9 @@ fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) Loa
5064 offset: u32,5064 offset: u32,
5065 iami: ?InputArchive.Member.Index,5065 iami: ?InputArchive.Member.Index,
5066 }) = .empty;5066 }) = .empty;
5067 defer members.deinit(gpa);
5067 var symbol_member_indices: std.ArrayList(u32) = .empty;5068 var symbol_member_indices: std.ArrayList(u32) = .empty;
5069 defer symbol_member_indices.deinit(gpa);
50685070
5069 const iai: InputArchive.Index = @fromBackingInt(@intCast(coff.input_archives.items.len));5071 const iai: InputArchive.Index = @fromBackingInt(@intCast(coff.input_archives.items.len));
5070 (try coff.input_archives.addOne(gpa)).* = .{5072 (try coff.input_archives.addOne(gpa)).* = .{
...@@ -5447,7 +5449,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -5447,7 +5449,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
5447 const sec_si = try coff.navSection(zcu, nav.resolved.?);5449 const sec_si = try coff.navSection(zcu, nav.resolved.?);
5448 try coff.nodes.ensureUnusedCapacity(gpa, 1);5450 try coff.nodes.ensureUnusedCapacity(gpa, 1);
5449 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);5451 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);
5450 const ni = try sec_si.node(coff).addFloatingChild(&coff.mf, gpa, .{5452 const ni = try sec_si.node(coff).addFloatingChild(gpa, &coff.mf, .{
5451 .alignment = .fromIp(zcu.navAlignment(nav_index)),5453 .alignment = .fromIp(zcu.navAlignment(nav_index)),
5452 .moved = true,5454 .moved = true,
5453 });5455 });
...@@ -5469,7 +5471,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -5469,7 +5471,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
54695471
5470 {5472 {
5471 var nw: MappedFile.Node.Writer = undefined;5473 var nw: MappedFile.Node.Writer = undefined;
5472 ni.writer(&coff.mf, gpa, &nw);5474 ni.writer(gpa, &coff.mf, &nw);
5473 defer nw.deinit();5475 defer nw.deinit();
5474 codegen.generateSymbol(5476 codegen.generateSymbol(
5475 &coff.base,5477 &coff.base,
...@@ -5486,8 +5488,26 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -5486,8 +5488,26 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
5486 }5488 }
54875489
5488 if (nav.resolved.?.@"linksection".unwrap()) |_| {5490 if (nav.resolved.?.@"linksection".unwrap()) |_| {
5489 try ni.resizeLeaf(&coff.mf, gpa, si.get(coff).extra.size);5491 try ni.resizeLeaf(gpa, &coff.mf, si.get(coff).extra.size);
5490 }5492 }
5493
5494 // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs.
5495 try coff.genPending(pt);
5496}
5497
5498pub fn updateContainerType(
5499 coff: *Coff,
5500 pt: Zcu.PerThread,
5501 ty: InternPool.Index,
5502 success: bool,
5503) link.Error!void {
5504 if (!success) return;
5505 var lazy_it = coff.lazy.iterator();
5506 while (lazy_it.next()) |lazy| if (lazy.value.map.getIndex(ty)) |lmi| {
5507 if (lazy.value.pending_index <= lmi) continue;
5508 // This type has changed on this incremental update, so update the lazy code/data.
5509 try coff.genLazy(pt, .{ .kind = lazy.key, .index = @intCast(lmi) });
5510 };
5491}5511}
54925512
5493pub fn lowerUav(5513pub fn lowerUav(
...@@ -5558,7 +5578,7 @@ fn updateFuncInner(...@@ -5558,7 +5578,7 @@ fn updateFuncInner(
5558 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);5578 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);
5559 const mod = zcu.navFileScope(func.owner_nav).mod.?;5579 const mod = zcu.navFileScope(func.owner_nav).mod.?;
5560 const target = &mod.resolved_target.result;5580 const target = &mod.resolved_target.result;
5561 const ni = try sec_si.node(coff).addFloatingChild(&coff.mf, gpa, .{5581 const ni = try sec_si.node(coff).addFloatingChild(gpa, &coff.mf, .{
5562 .alignment = switch (nav.resolved.?.@"align") {5582 .alignment = switch (nav.resolved.?.@"align") {
5563 .none => switch (mod.optimize_mode) {5583 .none => switch (mod.optimize_mode) {
5564 .debug,5584 .debug,
...@@ -5587,7 +5607,7 @@ fn updateFuncInner(...@@ -5587,7 +5607,7 @@ fn updateFuncInner(
5587 };5607 };
55885608
5589 var nw: MappedFile.Node.Writer = undefined;5609 var nw: MappedFile.Node.Writer = undefined;
5590 ni.writer(&coff.mf, gpa, &nw);5610 ni.writer(gpa, &coff.mf, &nw);
5591 defer nw.deinit();5611 defer nw.deinit();
5592 codegen.emitFunction(5612 codegen.emitFunction(
5593 &coff.base,5613 &coff.base,
...@@ -5603,10 +5623,13 @@ fn updateFuncInner(...@@ -5603,10 +5623,13 @@ fn updateFuncInner(
5603 };5623 };
5604 si.get(coff).extra.size = @intCast(nw.interface.end);5624 si.get(coff).extra.size = @intCast(nw.interface.end);
5605 try si.applyLocationRelocs(coff);5625 try si.applyLocationRelocs(coff);
5626
5627 // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs.
5628 try coff.genPending(pt);
5606}5629}
56075630
5608pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void {5631pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void {
5609 coff.flushLazy(pt, .{5632 coff.genLazyInner(pt, .{
5610 .kind = .const_data,5633 .kind = .const_data,
5611 .index = @intCast(coff.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return),5634 .index = @intCast(coff.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return),
5612 }) catch |err| switch (err) {5635 }) catch |err| switch (err) {
...@@ -5863,8 +5886,8 @@ pub fn flush(...@@ -5863,8 +5886,8 @@ pub fn flush(
58635886
5864 const number_of_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);5887 const number_of_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);
5865 coff.symbol_table.ni.resizeLeaf(5888 coff.symbol_table.ni.resizeLeaf(
5866 &coff.mf,
5867 comp.gpa,5889 comp.gpa,
5890 &coff.mf,
5868 number_of_symbols * std.coff.Symbol.sizeOf(),5891 number_of_symbols * std.coff.Symbol.sizeOf(),
5869 ) catch |err| switch (err) {5892 ) catch |err| switch (err) {
5870 else => |e| return e,5893 else => |e| return e,
...@@ -5919,22 +5942,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -5919,22 +5942,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
5919 };5942 };
5920 break :task;5943 break :task;
5921 }5944 }
5922 while (coff.pending_uavs.pop()) |pending_uav| {
5923 const sub_prog_node = coff.idleProgNode(tid, coff.const_prog_node, .{ .uav = pending_uav.key });
5924 defer sub_prog_node.end();
5925 coff.flushUav(
5926 .{ .zcu = comp.zcu.?, .tid = tid },
5927 pending_uav.key,
5928 pending_uav.value.alignment,
5929 ) catch |err| switch (err) {
5930 else => |e| return e,
5931 error.MappedFileIo => return comp.link_diags.fail(
5932 "linker failed to lower constant: {t}",
5933 .{coff.mf.io_err.?},
5934 ),
5935 };
5936 break :task;
5937 }
5938 if (coff.pending_input) |pending_iami| {5945 if (coff.pending_input) |pending_iami| {
5939 const name_slice = pending_iami.member(coff).name.toSlice(coff);5946 const name_slice = pending_iami.member(coff).name.toSlice(coff);
5940 const sub_prog_node = coff.input_prog_node.start(5947 const sub_prog_node = coff.input_prog_node.start(
...@@ -5983,33 +5990,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -5983,33 +5990,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
5983 };5990 };
5984 break :task;5991 break :task;
5985 }5992 }
5986 var lazy_it = coff.lazy.iterator();
5987 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {
5988 const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid };
5989 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };
5990 lazy.value.pending_index += 1;
5991 const kind = switch (lmr.kind) {
5992 .code => "code",
5993 .const_data => "data",
5994 };
5995 var name: [std.Progress.Node.max_name_len]u8 = undefined;
5996 const sub_prog_node = coff.synth_prog_node.start(
5997 std.mem.print(&name, "lazy {s} for {f}", .{
5998 kind,
5999 Type.fromInterned(lmr.lazySymbol(coff).ty).fmt(pt),
6000 }) catch &name,
6001 0,
6002 );
6003 defer sub_prog_node.end();
6004 coff.flushLazy(pt, lmr) catch |err| switch (err) {
6005 else => |e| return e,
6006 error.MappedFileIo => return comp.link_diags.fail(
6007 "linker failed to lower lazy {s}: {t}",
6008 .{ kind, coff.mf.io_err.? },
6009 ),
6010 };
6011 break :task;
6012 };
6013 if (coff.symbol_table.pending_symbol_index < coff.symbol_table.symbols.count()) {5993 if (coff.symbol_table.pending_symbol_index < coff.symbol_table.symbols.count()) {
6014 defer coff.symbol_table.pending_symbol_index += 1;5994 defer coff.symbol_table.pending_symbol_index += 1;
6015 const si = coff.symbol_table.symbols.keys()[coff.symbol_table.pending_symbol_index];5995 const si = coff.symbol_table.symbols.keys()[coff.symbol_table.pending_symbol_index];
...@@ -6025,7 +6005,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -6025,7 +6005,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
6025 defer sub_prog_node.end();6005 defer sub_prog_node.end();
6026 coff.flushSymbolTableEntry(6006 coff.flushSymbolTableEntry(
6027 coff.symbol_table.pending_symbol_index,6007 coff.symbol_table.pending_symbol_index,
6028 .{ .zcu = comp.zcu.?, .tid = tid },
6029 ) catch |err| switch (err) {6008 ) catch |err| switch (err) {
6030 error.OutOfMemory => return error.OutOfMemory,6009 error.OutOfMemory => return error.OutOfMemory,
6031 else => |e| return comp.link_diags.fail(6010 else => |e| return comp.link_diags.fail(
...@@ -6038,12 +6017,10 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -6038,12 +6017,10 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
6038 }6017 }
60396018
6040 if (coff.section_merge_pending_index < coff.section_merges.count()) return true;6019 if (coff.section_merge_pending_index < coff.section_merges.count()) return true;
6041 if (coff.pending_uavs.count() > 0) return true;
6042 if (coff.pending_input != null) return true;6020 if (coff.pending_input != null) return true;
6043 if (coff.exports_complete and coff.globals.count() > coff.global_pending_index) return true;6021 if (coff.exports_complete and coff.globals.count() > coff.global_pending_index) return true;
6044 assert(!coff.exports_complete or coff.inputs_complete);6022 assert(!coff.exports_complete or coff.inputs_complete);
6045 if (coff.exports_complete and coff.pending_special_symbol != .none) return true;6023 if (coff.exports_complete and coff.pending_special_symbol != .none) return true;
6046 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
6047 if (coff.symbol_table.pending_symbol_index < coff.symbol_table.symbols.count()) return true;6024 if (coff.symbol_table.pending_symbol_index < coff.symbol_table.symbols.count()) return true;
6048 return false;6025 return false;
6049}6026}
...@@ -6077,17 +6054,18 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -6077,17 +6054,18 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
6077 };6054 };
6078 break :task;6055 break :task;
6079 }6056 }
6080 while (coff.mf.updates.pop()) |ni| {6057 while (coff.mf.updates.pop()) |ni| : (coff.mf.update_prog_node.completeOne()) {
6058 if (ni.pendingDelete(&coff.mf)) continue;
6081 const clean_moved = ni.cleanMoved(&coff.mf);6059 const clean_moved = ni.cleanMoved(&coff.mf);
6082 const clean_resized = ni.cleanResized(&coff.mf);6060 const clean_resized = ni.cleanResized(&coff.mf);
6083 if (clean_moved or clean_resized) {6061 const clean_next_moved = ni.cleanNextMoved(&coff.mf);
6084 const sub_prog_node =6062 if (!clean_moved and !clean_resized and !clean_next_moved) continue;
6085 coff.idleProgNode(tid, coff.mf.update_prog_node, coff.getNode(ni));6063 const sub_prog_node =
6086 defer sub_prog_node.end();6064 coff.idleProgNode(tid, coff.mf.update_prog_node, coff.getNode(ni));
6087 if (clean_moved) try coff.flushMoved(ni);6065 defer sub_prog_node.end();
6088 if (clean_resized) try coff.flushResized(ni);6066 if (clean_moved) try coff.flushMoved(ni);
6089 break :task;6067 if (clean_resized) try coff.flushResized(ni);
6090 } else coff.mf.update_prog_node.completeOne();6068 break :task;
6091 }6069 }
6092 while (coff.pending_members.pop()) |pending_mi| {6070 while (coff.pending_members.pop()) |pending_mi| {
6093 const sub_prog_node = coff.idleProgNode(6071 const sub_prog_node = coff.idleProgNode(
...@@ -6153,7 +6131,27 @@ fn idleProgNode(...@@ -6153,7 +6131,27 @@ fn idleProgNode(
6153 }, 0);6131 }, 0);
6154}6132}
61556133
6156fn flushUav(6134fn genPending(coff: *Coff, pt: Zcu.PerThread) Error!void {
6135 const comp = pt.zcu.comp;
6136 while (coff.pending_uavs.pop()) |pending_uav| {
6137 const sub_prog_node = coff.idleProgNode(pt.tid, coff.const_prog_node, .{ .uav = pending_uav.key });
6138 defer sub_prog_node.end();
6139 coff.genUav(pt, pending_uav.key, pending_uav.value.alignment) catch |err| switch (err) {
6140 else => |e| return e,
6141 error.MappedFileIo => return comp.link_diags.fail(
6142 "linker failed to lower constant: {t}",
6143 .{coff.mf.io_err.?},
6144 ),
6145 };
6146 }
6147 var lazy_it = coff.lazy.iterator();
6148 while (lazy_it.next()) |lazy| while (lazy.value.pending_index < lazy.value.map.count()) {
6149 try coff.genLazy(pt, .{ .kind = lazy.key, .index = lazy.value.pending_index });
6150 lazy.value.pending_index += 1;
6151 };
6152}
6153
6154fn genUav(
6157 coff: *Coff,6155 coff: *Coff,
6158 pt: Zcu.PerThread,6156 pt: Zcu.PerThread,
6159 umi: Node.UavMapIndex,6157 umi: Node.UavMapIndex,
...@@ -6175,7 +6173,7 @@ fn flushUav(...@@ -6175,7 +6173,7 @@ fn flushUav(
6175 try coff.nodes.ensureUnusedCapacity(gpa, 1);6173 try coff.nodes.ensureUnusedCapacity(gpa, 1);
6176 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);6174 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);
6177 const sym = si.get(coff);6175 const sym = si.get(coff);
6178 const ni = try sec_si.node(coff).addFloatingChild(&coff.mf, gpa, .{6176 const ni = try sec_si.node(coff).addFloatingChild(gpa, &coff.mf, .{
6179 .alignment = .fromIp(uav_align),6177 .alignment = .fromIp(uav_align),
6180 .moved = true,6178 .moved = true,
6181 });6179 });
...@@ -6204,7 +6202,7 @@ fn flushUav(...@@ -6204,7 +6202,7 @@ fn flushUav(
6204 };6202 };
62056203
6206 var nw: MappedFile.Node.Writer = undefined;6204 var nw: MappedFile.Node.Writer = undefined;
6207 ni.writer(&coff.mf, gpa, &nw);6205 ni.writer(gpa, &coff.mf, &nw);
6208 defer nw.deinit();6206 defer nw.deinit();
6209 codegen.generateSymbol(6207 codegen.generateSymbol(
6210 &coff.base,6208 &coff.base,
...@@ -6311,7 +6309,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6311,7 +6309,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6311 .{ name, imp_match }6309 .{ name, imp_match }
6312 else name: {6310 else name: {
6313 try coff.ensureUnusedStringCapacity(imp_prefix.len + name_slice.len);6311 try coff.ensureUnusedStringCapacity(imp_prefix.len + name_slice.len);
6314 const imp_name = try std.fmt.allocPrint(gpa, imp_prefix ++ "{s}", .{name_slice});6312 const imp_name = try gpa.print(imp_prefix ++ "{s}", .{name_slice});
6315 defer gpa.free(imp_name);6313 defer gpa.free(imp_name);
6316 break :name .{ coff.getOrPutStringAssumeCapacity(imp_name), true };6314 break :name .{ coff.getOrPutStringAssumeCapacity(imp_name), true };
6317 };6315 };
...@@ -6468,19 +6466,19 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6468,19 +6466,19 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6468 if (!gop.found_existing) {6466 if (!gop.found_existing) {
6469 errdefer _ = coff.import_table.entries.pop();6467 errdefer _ = coff.import_table.entries.pop();
6470 try coff.import_table.ni.resizeLeaf(6468 try coff.import_table.ni.resizeLeaf(
6471 &coff.mf,
6472 gpa,6469 gpa,
6470 &coff.mf,
6473 @sizeOf(std.coff.ImportDirectoryEntry) * (gop.index + 2),6471 @sizeOf(std.coff.ImportDirectoryEntry) * (gop.index + 2),
6474 );6472 );
6475 const import_hint_name_table_len =6473 const import_hint_name_table_len =
6476 import_hint_name_align.forward(lib_name.len + ".dll".len + 1);6474 import_hint_name_align.forward(lib_name.len + ".dll".len + 1);
6477 const idata_section_ni = coff.import_table.ni.parent(&coff.mf).unwrap().?;6475 const idata_section_ni = coff.import_table.ni.parent(&coff.mf).unwrap().?;
6478 const import_lookup_table_ni = try idata_section_ni.addFloatingChild(&coff.mf, gpa, .{6476 const import_lookup_table_ni = try idata_section_ni.addFloatingChild(gpa, &coff.mf, .{
6479 .size = addr_info.size * 2,6477 .size = addr_info.size * 2,
6480 .alignment = addr_info.alignment,6478 .alignment = addr_info.alignment,
6481 .moved = true,6479 .moved = true,
6482 });6480 });
6483 const import_address_table_ni = try idata_section_ni.addFloatingChild(&coff.mf, gpa, .{6481 const import_address_table_ni = try idata_section_ni.addFloatingChild(gpa, &coff.mf, .{
6484 .size = addr_info.size * 2,6482 .size = addr_info.size * 2,
6485 .alignment = addr_info.alignment,6483 .alignment = addr_info.alignment,
6486 .moved = true,6484 .moved = true,
...@@ -6494,7 +6492,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6494,7 +6492,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6494 import_address_table_sym.section_number =6492 import_address_table_sym.section_number =
6495 coff.getNode(idata_section_ni).object_section.symbol(coff).get(coff).section_number;6493 coff.getNode(idata_section_ni).object_section.symbol(coff).get(coff).section_number;
6496 }6494 }
6497 const import_hint_name_table_ni = try idata_section_ni.addFloatingChild(&coff.mf, gpa, .{6495 const import_hint_name_table_ni = try idata_section_ni.addFloatingChild(gpa, &coff.mf, .{
6498 .size = import_hint_name_table_len,6496 .size = import_hint_name_table_len,
6499 .alignment = import_hint_name_align,6497 .alignment = import_hint_name_align,
6500 .moved = true,6498 .moved = true,
...@@ -6550,9 +6548,9 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6550,9 +6548,9 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6550 gop.value_ptr.len = import_symbol_index + 1;6548 gop.value_ptr.len = import_symbol_index + 1;
6551 const new_symbol_table_size = addr_info.size * (import_symbol_index + 2);6549 const new_symbol_table_size = addr_info.size * (import_symbol_index + 2);
65526550
6553 try gop.value_ptr.import_lookup_table_ni.resizeLeaf(&coff.mf, gpa, new_symbol_table_size);6551 try gop.value_ptr.import_lookup_table_ni.resizeLeaf(gpa, &coff.mf, new_symbol_table_size);
6554 const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff);6552 const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff);
6555 try import_address_table_ni.resizeLeaf(&coff.mf, gpa, new_symbol_table_size);6553 try import_address_table_ni.resizeLeaf(gpa, &coff.mf, new_symbol_table_size);
65566554
6557 const opt_imp_name = import.name.toSlice(coff);6555 const opt_imp_name = import.name.toSlice(coff);
6558 const opt_import_hint_name_index = if (opt_imp_name) |imp_name| blk: {6556 const opt_import_hint_name_index = if (opt_imp_name) |imp_name| blk: {
...@@ -6560,7 +6558,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6560,7 +6558,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6560 gop.value_ptr.hint_name_len = @intCast(6558 gop.value_ptr.hint_name_len = @intCast(
6561 import_hint_name_align.forward(import_hint_name_index + 2 + imp_name.len + 1),6559 import_hint_name_align.forward(import_hint_name_index + 2 + imp_name.len + 1),
6562 );6560 );
6563 try gop.value_ptr.import_hint_name_table_ni.resizeLeaf(&coff.mf, gpa, gop.value_ptr.hint_name_len);6561 try gop.value_ptr.import_hint_name_table_ni.resizeLeaf(gpa, &coff.mf, gop.value_ptr.hint_name_len);
6564 break :blk import_hint_name_index;6562 break :blk import_hint_name_index;
6565 } else null;6563 } else null;
65666564
...@@ -6635,7 +6633,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6635,7 +6633,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6635 else => |tag| @panic(@tagName(tag)),6633 else => |tag| @panic(@tagName(tag)),
6636 .AMD64 => {6634 .AMD64 => {
6637 const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 };6635 const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 };
6638 const ni = try parent_sym.ni.unwrap().?.addFloatingChild(&coff.mf, gpa, .{6636 const ni = try parent_sym.ni.unwrap().?.addFloatingChild(gpa, &coff.mf, .{
6639 .alignment = alignment,6637 .alignment = alignment,
6640 .size = alignment.forward(init.len),6638 .size = alignment.forward(init.len),
6641 });6639 });
...@@ -6773,7 +6771,31 @@ fn flushSpecialSymbol(coff: *Coff, pending: SpecialSymbol) !SpecialSymbol {...@@ -6773,7 +6771,31 @@ fn flushSpecialSymbol(coff: *Coff, pending: SpecialSymbol) !SpecialSymbol {
6773 };6771 };
6774}6772}
67756773
6776fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {6774fn genLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
6775 const lazy = lmr.lazySymbol(coff);
6776 if (lazy.ty == .anyerror_type) return;
6777 const kind = switch (lmr.kind) {
6778 .code => "code",
6779 .const_data => "data",
6780 };
6781 var name: [std.Progress.Node.max_name_len]u8 = undefined;
6782 const sub_prog_node = coff.synth_prog_node.start(
6783 std.mem.print(&name, "lazy {s} for {f}", .{
6784 kind,
6785 Type.fromInterned(lazy.ty).fmt(pt),
6786 }) catch &name,
6787 0,
6788 );
6789 defer sub_prog_node.end();
6790 coff.genLazyInner(pt, lmr) catch |err| switch (err) {
6791 else => |e| return e,
6792 error.MappedFileIo => return coff.base.comp.link_diags.fail(
6793 "linker failed to lower lazy {s}: {t}",
6794 .{ kind, coff.mf.io_err.? },
6795 ),
6796 };
6797}
6798fn genLazyInner(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
6777 const zcu = pt.zcu;6799 const zcu = pt.zcu;
6778 const gpa = zcu.gpa;6800 const gpa = zcu.gpa;
67796801
...@@ -6788,7 +6810,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -6788,7 +6810,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
6788 .code => .text,6810 .code => .text,
6789 .const_data => .rdata,6811 .const_data => .rdata,
6790 };6812 };
6791 const ni = try sec_si.node(coff).addFloatingChild(&coff.mf, gpa, .{ .moved = true });6813 const ni = try sec_si.node(coff).addFloatingChild(gpa, &coff.mf, .{ .moved = true });
6792 coff.nodes.appendAssumeCapacity(switch (lazy.kind) {6814 coff.nodes.appendAssumeCapacity(switch (lazy.kind) {
6793 .code => .{ .lazy_code = @fromBackingInt(@intCast(lmr.index)) },6815 .code => .{ .lazy_code = @fromBackingInt(@intCast(lmr.index)) },
6794 .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(lmr.index)) },6816 .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(lmr.index)) },
...@@ -6808,7 +6830,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -6808,7 +6830,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
68086830
6809 var required_alignment: InternPool.Alignment = .none;6831 var required_alignment: InternPool.Alignment = .none;
6810 var nw: MappedFile.Node.Writer = undefined;6832 var nw: MappedFile.Node.Writer = undefined;
6811 ni.writer(&coff.mf, gpa, &nw);6833 ni.writer(gpa, &coff.mf, &nw);
6812 defer nw.deinit();6834 defer nw.deinit();
6813 codegen.generateLazySymbol(6835 codegen.generateLazySymbol(
6814 &coff.base,6836 &coff.base,
...@@ -7356,7 +7378,7 @@ fn updateExportInner(...@@ -7356,7 +7378,7 @@ fn updateExportInner(
7356 pt: Zcu.PerThread,7378 pt: Zcu.PerThread,
7357 export_index: Zcu.Export.Index,7379 export_index: Zcu.Export.Index,
7358 alias_syms: *std.array_hash_map.Auto(Symbol.Index, Symbol.Index),7380 alias_syms: *std.array_hash_map.Auto(Symbol.Index, Symbol.Index),
7359) !void {7381) Error!void {
7360 const zcu = pt.zcu;7382 const zcu = pt.zcu;
7361 const gpa = zcu.gpa;7383 const gpa = zcu.gpa;
7362 const ip = &zcu.intern_pool;7384 const ip = &zcu.intern_pool;
...@@ -7380,6 +7402,8 @@ fn updateExportInner(...@@ -7380,6 +7402,8 @@ fn updateExportInner(
7380 exported_si,7402 exported_si,
7381 }),7403 }),
7382 }7404 }
7405
7406 try coff.genPending(pt);
7383 while (try coff.resolve(pt.tid)) {}7407 while (try coff.resolve(pt.tid)) {}
7384 while (try coff.idle(pt.tid)) {}7408 while (try coff.idle(pt.tid)) {}
73857409
...@@ -7444,7 +7468,7 @@ fn updateExportInner(...@@ -7444,7 +7468,7 @@ fn updateExportInner(
7444 if (new_name_table_size > std.math.maxInt(@FieldType(ExportTable.Entry, "name_index")))7468 if (new_name_table_size > std.math.maxInt(@FieldType(ExportTable.Entry, "name_index")))
7445 return coff.base.comp.link_diags.fail("exports name table limit reached", .{});7469 return coff.base.comp.link_diags.fail("exports name table limit reached", .{});
74467470
7447 try coff.export_table.name_table_ni.resizeLeaf(&coff.mf, gpa, new_name_table_size);7471 try coff.export_table.name_table_ni.resizeLeaf(gpa, &coff.mf, new_name_table_size);
74487472
7449 const name_table_slice = coff.export_table.name_table_ni.slice(&coff.mf);7473 const name_table_slice = coff.export_table.name_table_ni.slice(&coff.mf);
7450 @memcpy(name_table_slice[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]);7474 @memcpy(name_table_slice[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]);
...@@ -7468,20 +7492,20 @@ fn updateExportInner(...@@ -7468,20 +7492,20 @@ fn updateExportInner(
7468 // TODO: These should all be resized ahead of time to fit all exports7492 // TODO: These should all be resized ahead of time to fit all exports
7469 // after https://github.com/ziglang/zig/issues/236167493 // after https://github.com/ziglang/zig/issues/23616
7470 try coff.export_table.export_address_table_si.node(coff).resizeLeaf(7494 try coff.export_table.export_address_table_si.node(coff).resizeLeaf(
7471 &coff.mf,
7472 gpa,7495 gpa,
7496 &coff.mf,
7473 export_count * @sizeOf(std.coff.ExportAddressTableEntry),7497 export_count * @sizeOf(std.coff.ExportAddressTableEntry),
7474 );7498 );
74757499
7476 try coff.export_table.name_pointer_table_ni.resizeLeaf(7500 try coff.export_table.name_pointer_table_ni.resizeLeaf(
7477 &coff.mf,
7478 gpa,7501 gpa,
7502 &coff.mf,
7479 export_count * @sizeOf(std.coff.ExportNamePointerTableEntry),7503 export_count * @sizeOf(std.coff.ExportNamePointerTableEntry),
7480 );7504 );
74817505
7482 try coff.export_table.ordinal_table_ni.resizeLeaf(7506 try coff.export_table.ordinal_table_ni.resizeLeaf(
7483 &coff.mf,
7484 gpa,7507 gpa,
7508 &coff.mf,
7485 export_count * @sizeOf(std.coff.ExportOrdinalTableEntry),7509 export_count * @sizeOf(std.coff.ExportOrdinalTableEntry),
7486 );7510 );
74877511
...@@ -7519,17 +7543,19 @@ fn updateExportInner(...@@ -7519,17 +7543,19 @@ fn updateExportInner(
7519 }7543 }
7520}7544}
75217545
7522fn dumpStderr(coff: *Coff, tid: Zcu.PerThread.Id) !void {7546fn dumpStderr(coff: *Coff, tid: Zcu.PerThread.Id) Io.File.Writer.Error!void {
7523 const comp = coff.base.comp;7547 const comp = coff.base.comp;
7524 const io = comp.io;7548 const io = comp.io;
7525 var buffer: [512]u8 = undefined;7549 var buffer: [512]u8 = undefined;
7526 const stderr = try io.lockStderr(&buffer, null);7550 const stderr = try io.lockStderr(&buffer, null);
7527 defer io.unlockStderr();7551 defer io.unlockStderr();
7528 const w = &stderr.file_writer.interface;7552 const w = &stderr.file_writer.interface;
7529 _ = try coff.dump(w, tid);7553 _ = coff.dump(w, tid) catch |err| switch (err) {
7554 error.WriteFailed => return stderr.file_writer.err.?,
7555 };
7530}7556}
75317557
7532pub fn dump(coff: *Coff, w: *Io.Writer, tid: Zcu.PerThread.Id) !link.File.DumpResult {7558pub fn dump(coff: *Coff, w: *Io.Writer, tid: Zcu.PerThread.Id) Io.Writer.Error!link.File.DumpResult {
7533 if (coff.options.enable_link_snapshots) {7559 if (coff.options.enable_link_snapshots) {
7534 try coff.printNode(tid, w, .root, 0);7560 try coff.printNode(tid, w, .root, 0);
7535 try w.writeAll("Section table:\n");7561 try w.writeAll("Section table:\n");
...@@ -7544,7 +7570,7 @@ pub fn dump(coff: *Coff, w: *Io.Writer, tid: Zcu.PerThread.Id) !link.File.DumpRe...@@ -7544,7 +7570,7 @@ pub fn dump(coff: *Coff, w: *Io.Writer, tid: Zcu.PerThread.Id) !link.File.DumpRe
7544 return .disabled;7570 return .disabled;
7545}7571}
75467572
7547fn printSection(coff: *Coff, w: *Io.Writer, name: String, si: Symbol.Index) !void {7573fn printSection(coff: *Coff, w: *Io.Writer, name: String, si: Symbol.Index) Io.Writer.Error!void {
7548 const sym = si.get(coff);7574 const sym = si.get(coff);
7549 try w.print("{d:0>6}@{d:0>2} {x:08} n{d:0>8} | {s}\n", .{7575 try w.print("{d:0>6}@{d:0>2} {x:08} n{d:0>8} | {s}\n", .{
7550 si,7576 si,
...@@ -7560,7 +7586,7 @@ fn printSymbol(...@@ -7560,7 +7586,7 @@ fn printSymbol(
7560 w: *Io.Writer,7586 w: *Io.Writer,
7561 tid: Zcu.PerThread.Id,7587 tid: Zcu.PerThread.Id,
7562 si: Symbol.Index,7588 si: Symbol.Index,
7563) !void {7589) Io.Writer.Error!void {
7564 const sym = si.get(coff);7590 const sym = si.get(coff);
7565 try w.print("{d:0>6}@{d:0>2} {x:08} {s} {s} {s} n{d:0>8}+{x:08}:{s: <26} | {x:08} ", .{7591 try w.print("{d:0>6}@{d:0>2} {x:08} {s} {s} {s} n{d:0>8}+{x:08}:{s: <26} | {x:08} ", .{
7566 si,7592 si,
...@@ -7622,7 +7648,7 @@ fn printNodeName(...@@ -7622,7 +7648,7 @@ fn printNodeName(
7622 w: *std.Io.Writer,7648 w: *std.Io.Writer,
7623 tid: Zcu.PerThread.Id,7649 tid: Zcu.PerThread.Id,
7624 node: Node,7650 node: Node,
7625) !void {7651) Io.Writer.Error!void {
7626 switch (node) {7652 switch (node) {
7627 else => {},7653 else => {},
7628 .image_section => |si| try w.print("({s})", .{7654 .image_section => |si| try w.print("({s})", .{
...@@ -7702,7 +7728,7 @@ pub fn printNode(...@@ -7702,7 +7728,7 @@ pub fn printNode(
7702 w: *Io.Writer,7728 w: *Io.Writer,
7703 ni: MappedFile.Node.Index,7729 ni: MappedFile.Node.Index,
7704 indent: usize,7730 indent: usize,
7705) !void {7731) Io.Writer.Error!void {
7706 const node = coff.getNode(ni);7732 const node = coff.getNode(ni);
7707 try w.splatByteAll(' ', indent);7733 try w.splatByteAll(' ', indent);
7708 try w.writeAll(@tagName(node));7734 try w.writeAll(@tagName(node));
...@@ -7710,12 +7736,13 @@ pub fn printNode(...@@ -7710,12 +7736,13 @@ pub fn printNode(
7710 {7736 {
7711 const mf_node = &coff.mf.nodes.items[@backingInt(ni)];7737 const mf_node = &coff.mf.nodes.items[@backingInt(ni)];
7712 const off, const size = mf_node.location().resolve(&coff.mf);7738 const off, const size = mf_node.location().resolve(&coff.mf);
7713 try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x} {t}{s}{s}{s}\n", .{7739 try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x} {t}{s}{s}{s}{s}\n", .{
7714 @backingInt(ni),7740 @backingInt(ni),
7715 off,7741 off,
7716 size,7742 size,
7717 mf_node.flags.alignment.toByteUnits(),7743 mf_node.flags.alignment.toByteUnits(),
7718 mf_node.flags.position,7744 mf_node.flags.position,
7745 if (mf_node.flags.bubbles_moved) " bubbles_moved" else "",
7719 if (mf_node.flags.moved) " moved" else "",7746 if (mf_node.flags.moved) " moved" else "",
7720 if (mf_node.flags.resized) " resized" else "",7747 if (mf_node.flags.resized) " resized" else "",
7721 if (mf_node.flags.has_content) " has_content" else "",7748 if (mf_node.flags.has_content) " has_content" else "",
...@@ -7730,22 +7757,30 @@ pub fn printNode(...@@ -7730,22 +7757,30 @@ pub fn printNode(
7730 }7757 }
7731 return;7758 return;
7732 }7759 }
7733 const file_loc = ni.fileLocation(&coff.mf, false);7760 const start_address: usize, const end_address: usize = file_loc: {
7734 if (file_loc.size == 0) return;7761 const file_loc = ni.fileLocation(&coff.mf, false);
7735 var address = file_loc.offset;7762 break :file_loc .{ @intCast(file_loc.offset), @intCast(file_loc.offset + file_loc.size) };
7763 };
7764 var address = start_address;
7736 const line_len = 0x10;7765 const line_len = 0x10;
7737 var line_it = std.mem.window(7766 while (true) : (address = @min(std.mem.alignForward(usize, address + 1, line_len), end_address)) {
7738 u8,
7739 coff.mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
7740 line_len,
7741 line_len,
7742 );
7743 while (line_it.next()) |line_bytes| : (address += line_len) {
7744 try w.splatByteAll(' ', indent + 1);7767 try w.splatByteAll(' ', indent + 1);
7745 try w.print("{x:0>8} ", .{address});7768 try w.print("{x:0>8}", .{address});
7746 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});7769 if (address == end_address) break try w.writeByte('\n');
7747 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);7770 try w.splatByteAll(' ', 2);
7748 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');7771 const start_byte_address = std.mem.alignBackward(usize, address, line_len);
7772 const end_byte_address = start_byte_address + line_len;
7773 for (start_byte_address..end_byte_address) |byte_address|
7774 if (byte_address < start_address or byte_address >= end_address)
7775 try w.splatByteAll(' ', 3)
7776 else
7777 try w.print("{x:0>2} ", .{coff.mf.memory_map.memory[byte_address]});
7778 try w.writeByte(' ');
7779 for (start_byte_address..@min(end_address, end_byte_address)) |byte_address|
7780 try w.writeByte(if (byte_address < start_address or byte_address >= end_address) ' ' else char: {
7781 const byte = coff.mf.memory_map.memory[byte_address];
7782 break :char if (std.ascii.isPrint(byte)) byte else '.';
7783 });
7749 try w.writeByte('\n');7784 try w.writeByte('\n');
7750 }7785 }
7751}7786}
src/link/ConstPool.zig+38-12
...@@ -45,10 +45,22 @@ pub const Index = enum(u32) {...@@ -45,10 +45,22 @@ pub const Index = enum(u32) {
45};45};
4646
47pub const User = union(enum) {47pub const User = union(enum) {
48 dwarf: *@import("Dwarf.zig"),48 elf: *@import("Dwarf.zig"),
49 elf2: *@import("Elf2.zig"),
50 macho: *@import("Dwarf.zig"),
49 c: *@import("C.zig"),51 c: *@import("C.zig"),
50 llvm: @import("../codegen/llvm.zig").Object.Ptr,52 llvm: @import("../codegen/llvm.zig").Object.Ptr,
5153
54 fn devFeature(tag: @typeInfo(User).@"union".tag_type.?) dev.Feature {
55 return switch (tag) {
56 .elf => .elf_linker,
57 .elf2 => .elf2_linker,
58 .macho => .macho_linker,
59 .c => .c_linker,
60 .llvm => .llvm_backend,
61 };
62 }
63
52 /// Inform the debug info implementation that the new constant `val` was added to the pool at64 /// Inform the debug info implementation that the new constant `val` was added to the pool at
53 /// the given index (which equals the current pool length) due to a `get` call. It is guaranteed65 /// the given index (which equals the current pool length) due to a `get` call. It is guaranteed
54 /// that there will eventually be a call to either `updateConst` or `updateConstIncomplete`66 /// that there will eventually be a call to either `updateConst` or `updateConstIncomplete`
...@@ -58,9 +70,12 @@ pub const User = union(enum) {...@@ -58,9 +70,12 @@ pub const User = union(enum) {
58 pt: Zcu.PerThread,70 pt: Zcu.PerThread,
59 index: Index,71 index: Index,
60 val: InternPool.Index,72 val: InternPool.Index,
61 ) Allocator.Error!void {73 ) link.Error!void {
62 switch (user) {74 switch (user) {
63 inline else => |impl| return impl.addConst(pt, index, val),75 inline else => |impl, tag| {
76 dev.check(devFeature(tag));
77 return impl.addConst(pt, index, val);
78 },
64 }79 }
65 }80 }
6681
...@@ -73,9 +88,12 @@ pub const User = union(enum) {...@@ -73,9 +88,12 @@ pub const User = union(enum) {
73 pt: Zcu.PerThread,88 pt: Zcu.PerThread,
74 index: Index,89 index: Index,
75 val: InternPool.Index,90 val: InternPool.Index,
76 ) Allocator.Error!void {91 ) link.Error!void {
77 switch (user) {92 switch (user) {
78 inline else => |impl| return impl.updateConst(pt, index, val),93 inline else => |impl, tag| {
94 dev.check(devFeature(tag));
95 return impl.updateConst(pt, index, val);
96 },
79 }97 }
80 }98 }
8199
...@@ -89,9 +107,12 @@ pub const User = union(enum) {...@@ -89,9 +107,12 @@ pub const User = union(enum) {
89 pt: Zcu.PerThread,107 pt: Zcu.PerThread,
90 index: Index,108 index: Index,
91 val: InternPool.Index,109 val: InternPool.Index,
92 ) Allocator.Error!void {110 ) link.Error!void {
93 switch (user) {111 switch (user) {
94 inline else => |impl| return impl.updateConstIncomplete(pt, index, val),112 inline else => |impl, tag| {
113 dev.check(devFeature(tag));
114 return impl.updateConstIncomplete(pt, index, val);
115 },
95 }116 }
96 }117 }
97};118};
...@@ -128,12 +149,12 @@ pub fn updateContainerType(...@@ -128,12 +149,12 @@ pub fn updateContainerType(
128 user: User,149 user: User,
129 container_ty: InternPool.Index,150 container_ty: InternPool.Index,
130 success: bool,151 success: bool,
131) Allocator.Error!void {152) link.Error!void {
132 if (success) {153 if (success) {
133 const gpa = pt.zcu.comp.gpa;154 const gpa = pt.zcu.comp.gpa;
134 try pool.complete_containers.put(gpa, container_ty, {});155 try pool.complete_containers.put(gpa, container_ty, {});
135 } else {156 } else {
136 _ = pool.complete_containers.fetchSwapRemove(container_ty);157 _ = pool.complete_containers.swapRemove(container_ty);
137 }158 }
138 var opt_dep = pool.container_deps.get(container_ty);159 var opt_dep = pool.container_deps.get(container_ty);
139 while (opt_dep) |dep| : (opt_dep = dep.ptr(pool).next.unwrap()) {160 while (opt_dep) |dep| : (opt_dep = dep.ptr(pool).next.unwrap()) {
...@@ -143,7 +164,7 @@ pub fn updateContainerType(...@@ -143,7 +164,7 @@ pub fn updateContainerType(
143164
144/// After this is called, there may be a constant for which debug information (complete or not) has165/// After this is called, there may be a constant for which debug information (complete or not) has
145/// not yet been emitted, so the user must call `flushPending` at some point after this call.166/// not yet been emitted, so the user must call `flushPending` at some point after this call.
146pub fn get(pool: *ConstPool, pt: Zcu.PerThread, user: User, val: InternPool.Index) Allocator.Error!ConstPool.Index {167pub fn get(pool: *ConstPool, pt: Zcu.PerThread, user: User, val: InternPool.Index) link.Error!ConstPool.Index {
147 const zcu = pt.zcu;168 const zcu = pt.zcu;
148 const ip = &zcu.intern_pool;169 const ip = &zcu.intern_pool;
149 const gpa = zcu.comp.gpa;170 const gpa = zcu.comp.gpa;
...@@ -160,13 +181,16 @@ pub fn get(pool: *ConstPool, pt: Zcu.PerThread, user: User, val: InternPool.Inde...@@ -160,13 +181,16 @@ pub fn get(pool: *ConstPool, pt: Zcu.PerThread, user: User, val: InternPool.Inde
160 }181 }
161 return index;182 return index;
162}183}
163pub fn flushPending(pool: *ConstPool, pt: Zcu.PerThread, user: User) Allocator.Error!void {184pub fn getIfExists(pool: *ConstPool, val: InternPool.Index) ?ConstPool.Index {
185 return @fromBackingInt(@intCast(pool.values.getIndex(val) orelse return null));
186}
187pub fn flushPending(pool: *ConstPool, pt: Zcu.PerThread, user: User) link.Error!void {
164 while (pool.pending.pop()) |pending_ty| {188 while (pool.pending.pop()) |pending_ty| {
165 try pool.update(pt, user, pending_ty);189 try pool.update(pt, user, pending_ty);
166 }190 }
167}191}
168192
169fn update(pool: *ConstPool, pt: Zcu.PerThread, user: User, index: ConstPool.Index) Allocator.Error!void {193fn update(pool: *ConstPool, pt: Zcu.PerThread, user: User, index: ConstPool.Index) link.Error!void {
170 const zcu = pt.zcu;194 const zcu = pt.zcu;
171 const ip = &zcu.intern_pool;195 const ip = &zcu.intern_pool;
172 const val = index.val(pool);196 const val = index.val(pool);
...@@ -285,6 +309,8 @@ fn registerTypeDeps(pool: *ConstPool, root: Index, ty: Type, zcu: *const Zcu) Al...@@ -285,6 +309,8 @@ fn registerTypeDeps(pool: *ConstPool, root: Index, ty: Type, zcu: *const Zcu) Al
285const std = @import("std");309const std = @import("std");
286const Allocator = std.mem.Allocator;310const Allocator = std.mem.Allocator;
287311
312const dev = @import("../dev.zig");
288const InternPool = @import("../InternPool.zig");313const InternPool = @import("../InternPool.zig");
314const link = @import("../link.zig");
289const Type = @import("../Type.zig");315const Type = @import("../Type.zig");
290const Zcu = @import("../Zcu.zig");316const Zcu = @import("../Zcu.zig");
src/link/Dwarf.zig+135-121
...@@ -122,7 +122,7 @@ const DebugFrame = struct {...@@ -122,7 +122,7 @@ const DebugFrame = struct {
122 uleb128Bytes(1) + 1,122 uleb128Bytes(1) + 1,
123 } + switch (target.cpu.arch) {123 } + switch (target.cpu.arch) {
124 .x86_64 => len: {124 .x86_64 => len: {
125 dev.check(.x86_64_backend);125 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
126 const Register = @import("../codegen/x86_64/bits.zig").Register;126 const Register = @import("../codegen/x86_64/bits.zig").Register;
127 break :len uleb128Bytes(1) + sleb128Bytes(-8) + uleb128Bytes(Register.rip.dwarfNum()) +127 break :len uleb128Bytes(1) + sleb128Bytes(-8) + uleb128Bytes(Register.rip.dwarfNum()) +
128 1 + uleb128Bytes(Register.rsp.dwarfNum()) + sleb128Bytes(-1) +128 1 + uleb128Bytes(Register.rsp.dwarfNum()) + sleb128Bytes(-1) +
...@@ -1626,15 +1626,25 @@ pub const WipNav = struct {...@@ -1626,15 +1626,25 @@ pub const WipNav = struct {
1626 wip_nav.any_children = true;1626 wip_nav.any_children = true;
1627 }1627 }
16281628
1629 pub fn advancePCAndLine(wip_nav: *WipNav, delta_line: i33, delta_pc: u64) Allocator.Error!void {1629 pub fn advanceLineAndPc(
1630 return wip_nav.advancePCAndLineWriterError(delta_line, delta_pc) catch |err| switch (err) {1630 wip_nav: *WipNav,
1631 delta_line: i33,
1632 delta_pc: u64,
1633 end: bool,
1634 ) Allocator.Error!void {
1635 return wip_nav.advanceLineAndPcWriterError(
1636 delta_line,
1637 delta_pc,
1638 end,
1639 ) catch |err| switch (err) {
1631 error.WriteFailed => error.OutOfMemory,1640 error.WriteFailed => error.OutOfMemory,
1632 };1641 };
1633 }1642 }
1634 fn advancePCAndLineWriterError(1643 fn advanceLineAndPcWriterError(
1635 wip_nav: *WipNav,1644 wip_nav: *WipNav,
1636 delta_line: i33,1645 delta_line: i33,
1637 delta_pc: u64,1646 delta_pc: u64,
1647 end: bool,
1638 ) Writer.Error!void {1648 ) Writer.Error!void {
1639 const dlw = &wip_nav.debug_line.writer;1649 const dlw = &wip_nav.debug_line.writer;
16401650
...@@ -1654,20 +1664,30 @@ pub const WipNav = struct {...@@ -1654,20 +1664,30 @@ pub const WipNav = struct {
1654 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *1664 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
1655 header.maximum_operations_per_instruction + delta_op;1665 header.maximum_operations_per_instruction + delta_op;
1656 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;1666 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
1657 const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: {1667 const remaining_op_advance: u8 = @intCast(if (end or
1658 try dlw.writeByte(DW.LNS.advance_pc);1668 op_advance >= 2 * max_op_advance)
1659 try dlw.writeUleb128(op_advance);1669 remaining: {
1670 if (op_advance == max_op_advance) {
1671 try dlw.writeByte(DW.LNS.const_add_pc);
1672 } else if (op_advance != 0) {
1673 try dlw.writeByte(DW.LNS.advance_pc);
1674 try dlw.writeUleb128(op_advance);
1675 } else assert(end);
1660 break :remaining 0;1676 break :remaining 0;
1661 } else if (op_advance >= max_op_advance) remaining: {1677 } else if (op_advance >= max_op_advance) remaining: {
1662 try dlw.writeByte(DW.LNS.const_add_pc);1678 try dlw.writeByte(DW.LNS.const_add_pc);
1663 break :remaining op_advance - max_op_advance;1679 break :remaining op_advance - max_op_advance;
1664 } else op_advance);1680 } else op_advance);
16651681
1666 if (remaining_delta_line == 0 and remaining_op_advance == 0)1682 if (remaining_delta_line != 0 or remaining_op_advance != 0) {
1667 try dlw.writeByte(DW.LNS.copy)1683 assert(!end);
1668 else
1669 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +1684 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +
1670 (header.line_range * remaining_op_advance) + header.opcode_base));1685 (header.line_range * remaining_op_advance) + header.opcode_base));
1686 } else if (end) {
1687 try dlw.writeByte(DW.LNS.extended_op);
1688 try dlw.writeUleb128(1);
1689 try dlw.writeByte(DW.LNE.end_sequence);
1690 } else try dlw.writeByte(DW.LNS.copy);
1671 }1691 }
16721692
1673 pub fn setColumn(wip_nav: *WipNav, column: u32) Allocator.Error!void {1693 pub fn setColumn(wip_nav: *WipNav, column: u32) Allocator.Error!void {
...@@ -1990,7 +2010,7 @@ pub const WipNav = struct {...@@ -1990,7 +2010,7 @@ pub const WipNav = struct {
1990 try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);2010 try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
1991 }2011 }
1992 } = .{ .wip_nav = wip_nav };2012 } = .{ .wip_nav = wip_nav };
1993 try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end);2013 try adapter.writer().writeUleb128(counter.dw.fullCount());
1994 try loc.write(adapter);2014 try loc.write(adapter);
1995 }2015 }
19962016
...@@ -2032,7 +2052,7 @@ pub const WipNav = struct {...@@ -2032,7 +2052,7 @@ pub const WipNav = struct {
2032 try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0);2052 try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0);
2033 }2053 }
2034 } = .{ .wip_nav = wip_nav };2054 } = .{ .wip_nav = wip_nav };
2035 try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end);2055 try adapter.writer().writeUleb128(counter.dw.fullCount());
2036 try loc.write(adapter);2056 try loc.write(adapter);
2037 }2057 }
20382058
...@@ -2072,7 +2092,7 @@ pub const WipNav = struct {...@@ -2072,7 +2092,7 @@ pub const WipNav = struct {
2072 assert(value.typeOf(wip_nav.pt.zcu).comptimeOnly(wip_nav.pt.zcu));2092 assert(value.typeOf(wip_nav.pt.zcu).comptimeOnly(wip_nav.pt.zcu));
2073 }2093 }
2074 const dwarf = wip_nav.dwarf;2094 const dwarf = wip_nav.dwarf;
2075 const index = try dwarf.const_pool.get(wip_nav.pt, .{ .dwarf = dwarf }, value.toIntern());2095 const index = try dwarf.const_pool.get(wip_nav.pt, dwarf.constPoolUser(), value.toIntern());
2076 return dwarf.values.items[@backingInt(index)];2096 return dwarf.values.items[@backingInt(index)];
2077 }2097 }
20782098
...@@ -2105,20 +2125,20 @@ pub const WipNav = struct {...@@ -2105,20 +2125,20 @@ pub const WipNav = struct {
2105 const size = ty.abiSize(wip_nav.pt.zcu);2125 const size = ty.abiSize(wip_nav.pt.zcu);
2106 try diw.writeUleb128(size);2126 try diw.writeUleb128(size);
2107 if (size == 0) return;2127 if (size == 0) return;
2108 const old_end = wip_nav.debug_info.writer.end;2128 const old_end = diw.end;
2109 try codegen.generateSymbol(2129 try codegen.generateSymbol(
2110 wip_nav.dwarf.bin_file,2130 wip_nav.dwarf.bin_file,
2111 wip_nav.pt,2131 wip_nav.pt,
2112 val,2132 val,
2113 &wip_nav.debug_info.writer,2133 diw,
2114 .{ .debug_output = .{ .dwarf = wip_nav } },2134 .{ .debug_output = .{ .dwarf = wip_nav } },
2115 );2135 );
2116 if (old_end + size != wip_nav.debug_info.writer.end) {2136 if (old_end + size != diw.end) {
2117 std.debug.print("{f} [{}]: {} != {}\n", .{2137 std.debug.print("{f} [{}]: {} != {}\n", .{
2118 ty.fmt(wip_nav.pt),2138 ty.fmt(wip_nav.pt),
2119 ty.toIntern(),2139 ty.toIntern(),
2120 size,2140 size,
2121 wip_nav.debug_info.writer.end - old_end,2141 diw.end - old_end,
2122 });2142 });
2123 unreachable;2143 unreachable;
2124 }2144 }
...@@ -2182,7 +2202,7 @@ pub const WipNav = struct {...@@ -2182,7 +2202,7 @@ pub const WipNav = struct {
2182 wip_nav: *WipNav,2202 wip_nav: *WipNav,
2183 abbrev_code: struct {2203 abbrev_code: struct {
2184 decl: AbbrevCode,2204 decl: AbbrevCode,
2185 generic_decl: AbbrevCode,2205 decl_specification: AbbrevCode,
2186 decl_instance: AbbrevCode,2206 decl_instance: AbbrevCode,
2187 },2207 },
2188 nav: *const InternPool.Nav,2208 nav: *const InternPool.Nav,
...@@ -2196,11 +2216,11 @@ pub const WipNav = struct {...@@ -2196,11 +2216,11 @@ pub const WipNav = struct {
21962216
2197 const orig_entry = wip_nav.entry;2217 const orig_entry = wip_nav.entry;
2198 defer wip_nav.entry = orig_entry;2218 defer wip_nav.entry = orig_entry;
2199 const parent_type, const is_generic_decl = if (nav.analysis) |analysis| parent_info: {2219 const parent_type, const is_specification = if (nav.analysis) |analysis| parent_info: {
2200 const parent_type: Type = .fromInterned(zcu.namespacePtr(analysis.namespace).owner_type);2220 const parent_type: Type = .fromInterned(zcu.namespacePtr(analysis.namespace).owner_type);
2201 const decl_gop = try dwarf.decls.getOrPut(dwarf.gpa, analysis.zir_index);2221 const decl_gop = try dwarf.decls.getOrPut(dwarf.gpa, analysis.zir_index);
2202 errdefer _ = if (!decl_gop.found_existing) dwarf.decls.pop();2222 errdefer _ = if (!decl_gop.found_existing) dwarf.decls.pop();
2203 const was_generic_decl = decl_gop.found_existing and2223 const was_specification = decl_gop.found_existing and
2204 switch (try dwarf.debug_info.declAbbrevCode(wip_nav.unit, decl_gop.value_ptr.*)) {2224 switch (try dwarf.debug_info.declAbbrevCode(wip_nav.unit, decl_gop.value_ptr.*)) {
2205 .null,2225 .null,
2206 .decl_alias,2226 .decl_alias,
...@@ -2222,9 +2242,9 @@ pub const WipNav = struct {...@@ -2222,9 +2242,9 @@ pub const WipNav = struct {
2222 .decl_extern_nullary_func,2242 .decl_extern_nullary_func,
2223 .decl_extern_func,2243 .decl_extern_func,
2224 => false,2244 => false,
2225 .generic_decl_var,2245 .decl_specification_var,
2226 .generic_decl_const,2246 .decl_specification_const,
2227 .generic_decl_func,2247 .decl_specification_func,
2228 => true,2248 => true,
22292249
2230 // This comes from a decl which was previously generated as an incomplete value2250 // This comes from a decl which was previously generated as an incomplete value
...@@ -2235,11 +2255,11 @@ pub const WipNav = struct {...@@ -2235,11 +2255,11 @@ pub const WipNav = struct {
2235 else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}),2255 else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}),
2236 };2256 };
2237 if (parent_type.getCaptures(zcu).len == 0) {2257 if (parent_type.getCaptures(zcu).len == 0) {
2238 if (was_generic_decl) try dwarf.freeCommonEntry(wip_nav.unit, decl_gop.value_ptr.*);2258 if (was_specification) try dwarf.freeCommonEntry(wip_nav.unit, decl_gop.value_ptr.*);
2239 decl_gop.value_ptr.* = orig_entry;2259 decl_gop.value_ptr.* = orig_entry;
2240 break :parent_info .{ parent_type, false };2260 break :parent_info .{ parent_type, false };
2241 } else {2261 } else {
2242 if (was_generic_decl)2262 if (was_specification)
2243 dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(decl_gop.value_ptr.*).clear()2263 dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(decl_gop.value_ptr.*).clear()
2244 else2264 else
2245 decl_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);2265 decl_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
...@@ -2248,8 +2268,8 @@ pub const WipNav = struct {...@@ -2248,8 +2268,8 @@ pub const WipNav = struct {
2248 }2268 }
2249 } else .{ null, false };2269 } else .{ null, false };
22502270
2251 try wip_nav.abbrevCode(if (is_generic_decl) abbrev_code.generic_decl else abbrev_code.decl);2271 try wip_nav.abbrevCode(if (is_specification) abbrev_code.decl_specification else abbrev_code.decl);
2252 try wip_nav.refType((if (is_generic_decl) null else parent_type) orelse2272 try wip_nav.refType((if (is_specification) null else parent_type) orelse
2253 .fromInterned(zcu.fileRootType(file)));2273 .fromInterned(zcu.fileRootType(file)));
2254 assert(diw.end == DebugInfo.declEntryLineOff(dwarf));2274 assert(diw.end == DebugInfo.declEntryLineOff(dwarf));
2255 try diw.writeInt(u32, decl.src_line + 1, dwarf.endian);2275 try diw.writeInt(u32, decl.src_line + 1, dwarf.endian);
...@@ -2257,14 +2277,14 @@ pub const WipNav = struct {...@@ -2257,14 +2277,14 @@ pub const WipNav = struct {
2257 try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);2277 try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
2258 try wip_nav.strp(nav.name.toSlice(ip));2278 try wip_nav.strp(nav.name.toSlice(ip));
22592279
2260 if (!is_generic_decl) return;2280 if (!is_specification) return;
2261 const generic_decl_entry = wip_nav.entry;2281 const specification_entry = wip_nav.entry;
2262 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, generic_decl_entry, dwarf, wip_nav.debug_info.written());2282 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, specification_entry, dwarf, wip_nav.debug_info.written());
2263 wip_nav.debug_info.clearRetainingCapacity();2283 wip_nav.debug_info.clearRetainingCapacity();
2264 wip_nav.entry = orig_entry;2284 wip_nav.entry = orig_entry;
2265 try wip_nav.abbrevCode(abbrev_code.decl_instance);2285 try wip_nav.abbrevCode(abbrev_code.decl_instance);
2266 try wip_nav.refType(parent_type.?);2286 try wip_nav.refType(parent_type.?);
2267 try wip_nav.infoSectionOffset(.debug_info, wip_nav.unit, generic_decl_entry, 0);2287 try wip_nav.infoSectionOffset(.debug_info, wip_nav.unit, specification_entry, 0);
2268 }2288 }
2269};2289};
22702290
...@@ -2278,10 +2298,9 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {...@@ -2278,10 +2298,9 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
22782298
2279pub fn init(lf: *link.File, format: DW.Format) Dwarf {2299pub fn init(lf: *link.File, format: DW.Format) Dwarf {
2280 const comp = lf.comp;2300 const comp = lf.comp;
2281 const gpa = comp.gpa;
2282 const target = &comp.root_mod.resolved_target.result;2301 const target = &comp.root_mod.resolved_target.result;
2283 return .{2302 return .{
2284 .gpa = gpa,2303 .gpa = comp.gpa,
2285 .bin_file = lf,2304 .bin_file = lf,
2286 .format = format,2305 .format = format,
2287 .address_size = switch (target.ptrBitWidth()) {2306 .address_size = switch (target.ptrBitWidth()) {
...@@ -2566,7 +2585,7 @@ pub fn initWipNav(...@@ -2566,7 +2585,7 @@ pub fn initWipNav(
2566 pt: Zcu.PerThread,2585 pt: Zcu.PerThread,
2567 nav_index: InternPool.Nav.Index,2586 nav_index: InternPool.Nav.Index,
2568 sym_index: link.File.SymbolId,2587 sym_index: link.File.SymbolId,
2569) error{ OutOfMemory, AlreadyReported }!WipNav {2588) link.Error!WipNav {
2570 return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) {2589 return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) {
2571 error.OutOfMemory => error.OutOfMemory,2590 error.OutOfMemory => error.OutOfMemory,
2572 else => |e| pt.zcu.codegenFail(nav_index, "failed to init dwarf: {s}", .{@errorName(e)}),2591 else => |e| pt.zcu.codegenFail(nav_index, "failed to init dwarf: {s}", .{@errorName(e)}),
...@@ -2661,11 +2680,11 @@ fn initWipNavInner(...@@ -2661,11 +2680,11 @@ fn initWipNavInner(
2661 const diw = &wip_nav.debug_info.writer;2680 const diw = &wip_nav.debug_info.writer;
2662 try wip_nav.declCommon(if (func_type.param_types.len > 0 or func_type.is_var_args) .{2681 try wip_nav.declCommon(if (func_type.param_types.len > 0 or func_type.is_var_args) .{
2663 .decl = .decl_extern_func,2682 .decl = .decl_extern_func,
2664 .generic_decl = .generic_decl_func,2683 .decl_specification = .decl_specification_func,
2665 .decl_instance = .decl_instance_extern_func,2684 .decl_instance = .decl_instance_extern_func,
2666 } else .{2685 } else .{
2667 .decl = .decl_extern_nullary_func,2686 .decl = .decl_extern_nullary_func,
2668 .generic_decl = .generic_decl_func,2687 .decl_specification = .decl_specification_func,
2669 .decl_instance = .decl_instance_extern_nullary_func,2688 .decl_instance = .decl_instance_extern_nullary_func,
2670 }, &nav, inst_info.file, &decl);2689 }, &nav, inst_info.file, &decl);
2671 try wip_nav.strp(@"extern".name.toSlice(ip));2690 try wip_nav.strp(@"extern".name.toSlice(ip));
...@@ -2686,7 +2705,7 @@ fn initWipNavInner(...@@ -2686,7 +2705,7 @@ fn initWipNavInner(
2686 .func => |func| if (func.owner_nav != nav_index) {2705 .func => |func| if (func.owner_nav != nav_index) {
2687 try wip_nav.declCommon(.{2706 try wip_nav.declCommon(.{
2688 .decl = .decl_alias,2707 .decl = .decl_alias,
2689 .generic_decl = .generic_decl_const,2708 .decl_specification = .decl_specification_const,
2690 .decl_instance = .decl_instance_alias,2709 .decl_instance = .decl_instance_alias,
2691 }, &nav, inst_info.file, &decl);2710 }, &nav, inst_info.file, &decl);
2692 try wip_nav.refNav(func.owner_nav);2711 try wip_nav.refNav(func.owner_nav);
...@@ -2739,7 +2758,7 @@ fn initWipNavInner(...@@ -2739,7 +2758,7 @@ fn initWipNavInner(
2739 const diw = &wip_nav.debug_info.writer;2758 const diw = &wip_nav.debug_info.writer;
2740 try wip_nav.declCommon(.{2759 try wip_nav.declCommon(.{
2741 .decl = .decl_func,2760 .decl = .decl_func,
2742 .generic_decl = .generic_decl_func,2761 .decl_specification = .decl_specification_func,
2743 .decl_instance = .decl_instance_func,2762 .decl_instance = .decl_instance_func,
2744 }, &nav, inst_info.file, &decl);2763 }, &nav, inst_info.file, &decl);
2745 try wip_nav.strp(switch (decl.linkage) {2764 try wip_nav.strp(switch (decl.linkage) {
...@@ -2774,7 +2793,7 @@ fn initWipNavInner(...@@ -2774,7 +2793,7 @@ fn initWipNavInner(
2774 try dlw.writeByte(DW.LNS.set_column);2793 try dlw.writeByte(DW.LNS.set_column);
2775 try dlw.writeUleb128(func.lbrace_column + 1);2794 try dlw.writeUleb128(func.lbrace_column + 1);
27762795
2777 try wip_nav.advancePCAndLine(func.lbrace_line, 0);2796 try wip_nav.advanceLineAndPc(func.lbrace_line, 0, false);
2778 } else {2797 } else {
2779 try dlw.writeUleb128(1 + @backingInt(dwarf.address_size));2798 try dlw.writeUleb128(1 + @backingInt(dwarf.address_size));
2780 try dlw.writeByte(DW.LNE.set_address);2799 try dlw.writeByte(DW.LNE.set_address);
...@@ -2791,17 +2810,17 @@ fn initWipNavInner(...@@ -2791,17 +2810,17 @@ fn initWipNavInner(
2791 try dlw.writeByte(DW.LNS.set_column);2810 try dlw.writeByte(DW.LNS.set_column);
2792 try dlw.writeUleb128(func.lbrace_column + 1);2811 try dlw.writeUleb128(func.lbrace_column + 1);
27932812
2794 try wip_nav.advancePCAndLine(@intCast(decl.src_line + func.lbrace_line), 0);2813 try wip_nav.advanceLineAndPc(decl.src_line + func.lbrace_line, 0, false);
2795 }2814 }
2796 },2815 },
2797 else => {2816 else => {
2798 const diw = &wip_nav.debug_info.writer;2817 const diw = &wip_nav.debug_info.writer;
2799 try wip_nav.declCommon(.{2818 try wip_nav.declCommon(.{
2800 .decl = .decl_var,2819 .decl = .decl_var,
2801 .generic_decl = switch (decl.kind) {2820 .decl_specification = switch (decl.kind) {
2802 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,2821 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
2803 .@"const" => .generic_decl_const,2822 .@"const" => .decl_specification_const,
2804 .@"var" => .generic_decl_var,2823 .@"var" => .decl_specification_var,
2805 },2824 },
2806 .decl_instance = .decl_instance_var,2825 .decl_instance = .decl_instance_var,
2807 }, &nav, inst_info.file, &decl);2826 }, &nav, inst_info.file, &decl);
...@@ -2983,19 +3002,13 @@ fn finishWipNavWriterError(...@@ -2983,19 +3002,13 @@ fn finishWipNavWriterError(
2983 log.debug("finishWipNav({f})", .{nav.fqn.fmt(ip)});3002 log.debug("finishWipNav({f})", .{nav.fqn.fmt(ip)});
29843003
2985 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());3004 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
2986 const dlw = &wip_nav.debug_line.writer;3005 try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.written());
2987 if (dlw.end > 0) {
2988 try dlw.writeByte(DW.LNS.extended_op);
2989 try dlw.writeUleb128(1);
2990 try dlw.writeByte(DW.LNE.end_sequence);
2991 try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.written());
2992 }
2993 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written());3006 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written());
29943007
2995 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });3008 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
2996}3009}
29973010
2998pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error{ OutOfMemory, AlreadyReported }!void {3011pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void {
2999 return updateComptimeNavInner(dwarf, pt, nav_index) catch |err| switch (err) {3012 return updateComptimeNavInner(dwarf, pt, nav_index) catch |err| switch (err) {
3000 error.OutOfMemory => error.OutOfMemory,3013 error.OutOfMemory => error.OutOfMemory,
3001 else => |e| pt.zcu.codegenFail(nav_index, "failed to update dwarf: {s}", .{@errorName(e)}),3014 else => |e| pt.zcu.codegenFail(nav_index, "failed to update dwarf: {s}", .{@errorName(e)}),
...@@ -3054,8 +3067,8 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3054,8 +3067,8 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3054 const loaded_struct = ip.loadStructType(nav_val.toIntern());3067 const loaded_struct = ip.loadStructType(nav_val.toIntern());
3055 if (nav_index.toOptional() == loaded_struct.name_nav) {3068 if (nav_index.toOptional() == loaded_struct.name_nav) {
3056 // This Nav's entry is populated by the type, not the actual Nav.3069 // This Nav's entry is populated by the type, not the actual Nav.
3057 _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());3070 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
3058 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });3071 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
3059 return;3072 return;
3060 }3073 }
3061 break :tag .alias;3074 break :tag .alias;
...@@ -3064,8 +3077,8 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3064,8 +3077,8 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3064 const loaded_enum = ip.loadEnumType(nav_val.toIntern());3077 const loaded_enum = ip.loadEnumType(nav_val.toIntern());
3065 if (nav_index.toOptional() == loaded_enum.name_nav) {3078 if (nav_index.toOptional() == loaded_enum.name_nav) {
3066 // This Nav's entry is populated by the type, not the actual Nav.3079 // This Nav's entry is populated by the type, not the actual Nav.
3067 _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());3080 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
3068 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });3081 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
3069 return;3082 return;
3070 }3083 }
3071 break :tag .alias;3084 break :tag .alias;
...@@ -3074,8 +3087,8 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3074,8 +3087,8 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3074 const loaded_union = ip.loadUnionType(nav_val.toIntern());3087 const loaded_union = ip.loadUnionType(nav_val.toIntern());
3075 if (nav_index.toOptional() == loaded_union.name_nav) {3088 if (nav_index.toOptional() == loaded_union.name_nav) {
3076 // This Nav's entry is populated by the type, not the actual Nav.3089 // This Nav's entry is populated by the type, not the actual Nav.
3077 _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());3090 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
3078 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });3091 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
3079 return;3092 return;
3080 }3093 }
3081 break :tag .alias;3094 break :tag .alias;
...@@ -3084,8 +3097,8 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3084,8 +3097,8 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3084 const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());3097 const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
3085 if (nav_index.toOptional() == loaded_opaque.name_nav) {3098 if (nav_index.toOptional() == loaded_opaque.name_nav) {
3086 // This Nav's entry is populated by the type, not the actual Nav.3099 // This Nav's entry is populated by the type, not the actual Nav.
3087 _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());3100 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
3088 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });3101 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
3089 return;3102 return;
3090 }3103 }
3091 break :tag .alias;3104 break :tag .alias;
...@@ -3168,7 +3181,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3168,7 +3181,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3168 .alias => {3181 .alias => {
3169 try wip_nav.declCommon(.{3182 try wip_nav.declCommon(.{
3170 .decl = .decl_alias,3183 .decl = .decl_alias,
3171 .generic_decl = .generic_decl_const,3184 .decl_specification = .decl_specification_const,
3172 .decl_instance = .decl_instance_alias,3185 .decl_instance = .decl_instance_alias,
3173 }, &nav, inst_info.file, &decl);3186 }, &nav, inst_info.file, &decl);
3174 try wip_nav.refType(nav_val.toType());3187 try wip_nav.refType(nav_val.toType());
...@@ -3176,7 +3189,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3176,7 +3189,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3176 .@"var" => {3189 .@"var" => {
3177 try wip_nav.declCommon(.{3190 try wip_nav.declCommon(.{
3178 .decl = .decl_var,3191 .decl = .decl_var,
3179 .generic_decl = .generic_decl_var,3192 .decl_specification = .decl_specification_var,
3180 .decl_instance = .decl_instance_var,3193 .decl_instance = .decl_instance_var,
3181 }, &nav, inst_info.file, &decl);3194 }, &nav, inst_info.file, &decl);
3182 try wip_nav.strp(switch (decl.linkage) {3195 try wip_nav.strp(switch (decl.linkage) {
...@@ -3196,19 +3209,19 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3196,19 +3209,19 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3196 const has_comptime_state = nav_ty.comptimeOnly(zcu);3209 const has_comptime_state = nav_ty.comptimeOnly(zcu);
3197 try wip_nav.declCommon(if (has_runtime_bits and has_comptime_state) .{3210 try wip_nav.declCommon(if (has_runtime_bits and has_comptime_state) .{
3198 .decl = .decl_const_runtime_bits_comptime_state,3211 .decl = .decl_const_runtime_bits_comptime_state,
3199 .generic_decl = .generic_decl_const,3212 .decl_specification = .decl_specification_const,
3200 .decl_instance = .decl_instance_const_runtime_bits_comptime_state,3213 .decl_instance = .decl_instance_const_runtime_bits_comptime_state,
3201 } else if (has_comptime_state) .{3214 } else if (has_comptime_state) .{
3202 .decl = .decl_const_comptime_state,3215 .decl = .decl_const_comptime_state,
3203 .generic_decl = .generic_decl_const,3216 .decl_specification = .decl_specification_const,
3204 .decl_instance = .decl_instance_const_comptime_state,3217 .decl_instance = .decl_instance_const_comptime_state,
3205 } else if (has_runtime_bits) .{3218 } else if (has_runtime_bits) .{
3206 .decl = .decl_const_runtime_bits,3219 .decl = .decl_const_runtime_bits,
3207 .generic_decl = .generic_decl_const,3220 .decl_specification = .decl_specification_const,
3208 .decl_instance = .decl_instance_const_runtime_bits,3221 .decl_instance = .decl_instance_const_runtime_bits,
3209 } else .{3222 } else .{
3210 .decl = .decl_const,3223 .decl = .decl_const,
3211 .generic_decl = .generic_decl_const,3224 .decl_specification = .decl_specification_const,
3212 .decl_instance = .decl_instance_const,3225 .decl_instance = .decl_instance_const,
3213 }, &nav, inst_info.file, &decl);3226 }, &nav, inst_info.file, &decl);
3214 try wip_nav.strp(switch (decl.linkage) {3227 try wip_nav.strp(switch (decl.linkage) {
...@@ -3232,11 +3245,11 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3232,11 +3245,11 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3232 } else true;3245 } else true;
3233 try wip_nav.declCommon(if (is_nullary) .{3246 try wip_nav.declCommon(if (is_nullary) .{
3234 .decl = .decl_nullary_func_generic,3247 .decl = .decl_nullary_func_generic,
3235 .generic_decl = .generic_decl_func,3248 .decl_specification = .decl_specification_func,
3236 .decl_instance = .decl_instance_nullary_func_generic,3249 .decl_instance = .decl_instance_nullary_func_generic,
3237 } else .{3250 } else .{
3238 .decl = .decl_func_generic,3251 .decl = .decl_func_generic,
3239 .generic_decl = .generic_decl_func,3252 .decl_specification = .decl_specification_func,
3240 .decl_instance = .decl_instance_func_generic,3253 .decl_instance = .decl_instance_func_generic,
3241 }, &nav, inst_info.file, &decl);3254 }, &nav, inst_info.file, &decl);
3242 try wip_nav.refType(.fromInterned(func_type.return_type));3255 try wip_nav.refType(.fromInterned(func_type.return_type));
...@@ -3254,14 +3267,14 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3254,14 +3267,14 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3254 .func_alias => |owner_nav| {3267 .func_alias => |owner_nav| {
3255 try wip_nav.declCommon(.{3268 try wip_nav.declCommon(.{
3256 .decl = .decl_alias,3269 .decl = .decl_alias,
3257 .generic_decl = .generic_decl_const,3270 .decl_specification = .decl_specification_const,
3258 .decl_instance = .decl_instance_alias,3271 .decl_instance = .decl_instance_alias,
3259 }, &nav, inst_info.file, &decl);3272 }, &nav, inst_info.file, &decl);
3260 try wip_nav.refNav(owner_nav);3273 try wip_nav.refNav(owner_nav);
3261 },3274 },
3262 }3275 }
3263 try dwarf.debug_info.section.replaceEntry(unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());3276 try dwarf.debug_info.section.replaceEntry(unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
3264 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });3277 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
3265}3278}
32663279
3267pub fn updateContainerType(3280pub fn updateContainerType(
...@@ -3270,7 +3283,7 @@ pub fn updateContainerType(...@@ -3270,7 +3283,7 @@ pub fn updateContainerType(
3270 ty: InternPool.Index,3283 ty: InternPool.Index,
3271 success: bool,3284 success: bool,
3272) !void {3285) !void {
3273 try dwarf.const_pool.updateContainerType(pt, .{ .dwarf = dwarf }, ty, success);3286 try dwarf.const_pool.updateContainerType(pt, dwarf.constPoolUser(), ty, success);
3274}3287}
3275/// Should only be called by the `link.ConstPool` implementation.3288/// Should only be called by the `link.ConstPool` implementation.
3276pub fn addConst(dwarf: *Dwarf, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {3289pub fn addConst(dwarf: *Dwarf, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
...@@ -3374,12 +3387,12 @@ fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_inde...@@ -3374,12 +3387,12 @@ fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_inde
3374 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file_index);3387 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file_index);
3375 try wip_nav.abbrevCode(.empty_file);3388 try wip_nav.abbrevCode(.empty_file);
3376 try wip_nav.debug_info.writer.writeUleb128(file_gop.index);3389 try wip_nav.debug_info.writer.writeUleb128(file_gop.index);
3377 try wip_nav.strp(loaded_struct.name.toSlice(ip));3390 try wip_nav.strp(loaded_struct.fqn.toSlice(ip));
3378 } else {3391 } else {
3379 try dwarf.emitIncompleteContainerType(3392 try dwarf.emitIncompleteContainerType(
3380 &wip_nav,3393 &wip_nav,
3381 loaded_struct.zir_index,3394 loaded_struct.zir_index,
3382 loaded_struct.name,3395 loaded_struct.fqn,
3383 loaded_struct.name_nav,3396 loaded_struct.name_nav,
3384 );3397 );
3385 }3398 }
...@@ -3389,7 +3402,7 @@ fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_inde...@@ -3389,7 +3402,7 @@ fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_inde
3389 try dwarf.emitIncompleteContainerType(3402 try dwarf.emitIncompleteContainerType(
3390 &wip_nav,3403 &wip_nav,
3391 loaded_union.zir_index,3404 loaded_union.zir_index,
3392 loaded_union.name,3405 loaded_union.fqn,
3393 loaded_union.name_nav,3406 loaded_union.name_nav,
3394 );3407 );
3395 },3408 },
...@@ -3399,12 +3412,12 @@ fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_inde...@@ -3399,12 +3412,12 @@ fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_inde
3399 try dwarf.emitIncompleteContainerType(3412 try dwarf.emitIncompleteContainerType(
3400 &wip_nav,3413 &wip_nav,
3401 zir_index,3414 zir_index,
3402 loaded_enum.name,3415 loaded_enum.fqn,
3403 loaded_enum.name_nav,3416 loaded_enum.name_nav,
3404 );3417 );
3405 } else {3418 } else {
3406 try wip_nav.abbrevCode(.generated_empty_struct_type);3419 try wip_nav.abbrevCode(.generated_empty_struct_type);
3407 try wip_nav.strp(loaded_enum.name.toSlice(ip));3420 try wip_nav.strp(loaded_enum.fqn.toSlice(ip));
3408 try wip_nav.debug_info.writer.writeByte(@intFromBool(true));3421 try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
3409 }3422 }
3410 },3423 },
...@@ -3413,7 +3426,7 @@ fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_inde...@@ -3413,7 +3426,7 @@ fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_inde
3413 try dwarf.emitIncompleteContainerType(3426 try dwarf.emitIncompleteContainerType(
3414 &wip_nav,3427 &wip_nav,
3415 loaded_opaque.zir_index,3428 loaded_opaque.zir_index,
3416 loaded_opaque.name,3429 loaded_opaque.fqn,
3417 loaded_opaque.name_nav,3430 loaded_opaque.name_nav,
3418 );3431 );
3419 },3432 },
...@@ -3438,7 +3451,7 @@ fn emitIncompleteContainerType(...@@ -3438,7 +3451,7 @@ fn emitIncompleteContainerType(
3438 dwarf: *Dwarf,3451 dwarf: *Dwarf,
3439 wip_nav: *WipNav,3452 wip_nav: *WipNav,
3440 zir_index: InternPool.TrackedInst.Index,3453 zir_index: InternPool.TrackedInst.Index,
3441 name: InternPool.NullTerminatedString,3454 fqn: InternPool.NullTerminatedString,
3442 name_nav: InternPool.Nav.Index.Optional,3455 name_nav: InternPool.Nav.Index.Optional,
3443) !void {3456) !void {
3444 const zcu = wip_nav.pt.zcu;3457 const zcu = wip_nav.pt.zcu;
...@@ -3450,7 +3463,7 @@ fn emitIncompleteContainerType(...@@ -3450,7 +3463,7 @@ fn emitIncompleteContainerType(
3450 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);3463 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
3451 try wip_nav.declCommon(.{3464 try wip_nav.declCommon(.{
3452 .decl = .decl_namespace_struct,3465 .decl = .decl_namespace_struct,
3453 .generic_decl = .generic_decl_const,3466 .decl_specification = .decl_specification_const,
3454 .decl_instance = .decl_instance_namespace_struct,3467 .decl_instance = .decl_instance_namespace_struct,
3455 }, &nav, file, &decl);3468 }, &nav, file, &decl);
3456 try wip_nav.debug_info.writer.writeByte(@intFromBool(true));3469 try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
...@@ -3459,7 +3472,7 @@ fn emitIncompleteContainerType(...@@ -3459,7 +3472,7 @@ fn emitIncompleteContainerType(
3459 const file_gop = try dwarf.getModInfo(wip_nav.unit).files.getOrPut(dwarf.gpa, file);3472 const file_gop = try dwarf.getModInfo(wip_nav.unit).files.getOrPut(dwarf.gpa, file);
3460 try wip_nav.abbrevCode(.empty_struct_type);3473 try wip_nav.abbrevCode(.empty_struct_type);
3461 try diw.writeUleb128(file_gop.index);3474 try diw.writeUleb128(file_gop.index);
3462 try wip_nav.strp(name.toSlice(ip));3475 try wip_nav.strp(fqn.toSlice(ip));
3463 try diw.writeByte(@intFromBool(true));3476 try diw.writeByte(@intFromBool(true));
3464 }3477 }
3465}3478}
...@@ -3868,11 +3881,11 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -3868,11 +3881,11 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
3868 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);3881 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
3869 try wip_nav.declCommon(if (loaded_struct.field_types.len == 0) .{3882 try wip_nav.declCommon(if (loaded_struct.field_types.len == 0) .{
3870 .decl = .decl_namespace_struct,3883 .decl = .decl_namespace_struct,
3871 .generic_decl = .generic_decl_const,3884 .decl_specification = .decl_specification_const,
3872 .decl_instance = .decl_instance_namespace_struct,3885 .decl_instance = .decl_instance_namespace_struct,
3873 } else .{3886 } else .{
3874 .decl = .decl_struct,3887 .decl = .decl_struct,
3875 .generic_decl = .generic_decl_const,3888 .decl_specification = .decl_specification_const,
3876 .decl_instance = .decl_instance_struct,3889 .decl_instance = .decl_instance_struct,
3877 }, &nav, file, &decl);3890 }, &nav, file, &decl);
3878 } else {3891 } else {
...@@ -3882,7 +3895,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -3882,7 +3895,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
3882 else => if (struct_is_file) .file else .struct_type,3895 else => if (struct_is_file) .file else .struct_type,
3883 });3896 });
3884 try diw.writeUleb128(file_gop.index);3897 try diw.writeUleb128(file_gop.index);
3885 try wip_nav.strp(loaded_struct.name.toSlice(ip));3898 try wip_nav.strp(loaded_struct.fqn.toSlice(ip));
3886 }3899 }
3887 if (loaded_struct.field_types.len == 0) {3900 if (loaded_struct.field_types.len == 0) {
3888 if (!struct_is_file) try diw.writeByte(@intFromBool(false));3901 if (!struct_is_file) try diw.writeByte(@intFromBool(false));
...@@ -3947,7 +3960,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -3947,7 +3960,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
3947 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);3960 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
3948 try wip_nav.declCommon(.{3961 try wip_nav.declCommon(.{
3949 .decl = .decl_packed_struct,3962 .decl = .decl_packed_struct,
3950 .generic_decl = .generic_decl_const,3963 .decl_specification = .decl_specification_const,
3951 .decl_instance = .decl_instance_packed_struct,3964 .decl_instance = .decl_instance_packed_struct,
3952 }, &nav, file, &decl);3965 }, &nav, file, &decl);
3953 break :t true;3966 break :t true;
...@@ -3955,7 +3968,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -3955,7 +3968,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
3955 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);3968 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
3956 try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type);3969 try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type);
3957 try diw.writeUleb128(file_gop.index);3970 try diw.writeUleb128(file_gop.index);
3958 try wip_nav.strp(loaded_struct.name.toSlice(ip));3971 try wip_nav.strp(loaded_struct.fqn.toSlice(ip));
3959 break :t loaded_struct.field_types.len > 0;3972 break :t loaded_struct.field_types.len > 0;
3960 };3973 };
3961 try wip_nav.refType(.fromInterned(loaded_struct.packed_backing_int_type));3974 try wip_nav.refType(.fromInterned(loaded_struct.packed_backing_int_type));
...@@ -3984,7 +3997,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -3984,7 +3997,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
3984 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);3997 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
3985 try wip_nav.declCommon(.{3998 try wip_nav.declCommon(.{
3986 .decl = .decl_union,3999 .decl = .decl_union,
3987 .generic_decl = .generic_decl_const,4000 .decl_specification = .decl_specification_const,
3988 .decl_instance = .decl_instance_union,4001 .decl_instance = .decl_instance_union,
3989 }, &nav, file, &decl);4002 }, &nav, file, &decl);
3990 break :t true;4003 break :t true;
...@@ -3992,7 +4005,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -3992,7 +4005,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
3992 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);4005 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
3993 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);4006 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);
3994 try diw.writeUleb128(file_gop.index);4007 try diw.writeUleb128(file_gop.index);
3995 try wip_nav.strp(loaded_union.name.toSlice(ip));4008 try wip_nav.strp(loaded_union.fqn.toSlice(ip));
3996 break :t loaded_union.field_types.len > 0;4009 break :t loaded_union.field_types.len > 0;
3997 };4010 };
3998 const union_layout = Type.getUnionLayout(loaded_union, zcu);4011 const union_layout = Type.getUnionLayout(loaded_union, zcu);
...@@ -4046,7 +4059,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -4046,7 +4059,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
4046 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);4059 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
4047 try wip_nav.declCommon(.{4060 try wip_nav.declCommon(.{
4048 .decl = .decl_packed_union,4061 .decl = .decl_packed_union,
4049 .generic_decl = .generic_decl_const,4062 .decl_specification = .decl_specification_const,
4050 .decl_instance = .decl_instance_packed_union,4063 .decl_instance = .decl_instance_packed_union,
4051 }, &nav, file, &decl);4064 }, &nav, file, &decl);
4052 break :t true;4065 break :t true;
...@@ -4054,7 +4067,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -4054,7 +4067,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
4054 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);4067 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
4055 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .packed_union_type else .empty_packed_union_type);4068 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .packed_union_type else .empty_packed_union_type);
4056 try diw.writeUleb128(file_gop.index);4069 try diw.writeUleb128(file_gop.index);
4057 try wip_nav.strp(loaded_union.name.toSlice(ip));4070 try wip_nav.strp(loaded_union.fqn.toSlice(ip));
4058 break :t loaded_union.field_types.len > 0;4071 break :t loaded_union.field_types.len > 0;
4059 };4072 };
4060 try wip_nav.refType(.fromInterned(loaded_union.packed_backing_int_type));4073 try wip_nav.refType(.fromInterned(loaded_union.packed_backing_int_type));
...@@ -4079,18 +4092,18 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -4079,18 +4092,18 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
4079 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);4092 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
4080 try wip_nav.declCommon(if (loaded_enum.field_names.len > 0) .{4093 try wip_nav.declCommon(if (loaded_enum.field_names.len > 0) .{
4081 .decl = .decl_enum,4094 .decl = .decl_enum,
4082 .generic_decl = .generic_decl_const,4095 .decl_specification = .decl_specification_const,
4083 .decl_instance = .decl_instance_enum,4096 .decl_instance = .decl_instance_enum,
4084 } else .{4097 } else .{
4085 .decl = .decl_empty_enum,4098 .decl = .decl_empty_enum,
4086 .generic_decl = .generic_decl_const,4099 .decl_specification = .decl_specification_const,
4087 .decl_instance = .decl_instance_empty_enum,4100 .decl_instance = .decl_instance_empty_enum,
4088 }, &nav, file, &decl);4101 }, &nav, file, &decl);
4089 } else {4102 } else {
4090 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);4103 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
4091 try wip_nav.abbrevCode(if (loaded_enum.field_names.len > 0) .enum_type else .empty_enum_type);4104 try wip_nav.abbrevCode(if (loaded_enum.field_names.len > 0) .enum_type else .empty_enum_type);
4092 try diw.writeUleb128(file_gop.index);4105 try diw.writeUleb128(file_gop.index);
4093 try wip_nav.strp(loaded_enum.name.toSlice(ip));4106 try wip_nav.strp(loaded_enum.fqn.toSlice(ip));
4094 }4107 }
4095 try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));4108 try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
4096 for (0..loaded_enum.field_names.len) |field_index| {4109 for (0..loaded_enum.field_names.len) |field_index| {
...@@ -4102,7 +4115,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -4102,7 +4115,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
4102 } else {4115 } else {
4103 assert(loaded_enum.owner_union != .none);4116 assert(loaded_enum.owner_union != .none);
4104 try wip_nav.abbrevCode(if (loaded_enum.field_names.len == 0) .generated_empty_enum_type else .generated_enum_type);4117 try wip_nav.abbrevCode(if (loaded_enum.field_names.len == 0) .generated_empty_enum_type else .generated_enum_type);
4105 try wip_nav.strp(loaded_enum.name.toSlice(ip));4118 try wip_nav.strp(loaded_enum.fqn.toSlice(ip));
4106 try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));4119 try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
4107 for (0..loaded_enum.field_names.len) |field_index| {4120 for (0..loaded_enum.field_names.len) |field_index| {
4108 try wip_nav.abbrevCode(.enum_field);4121 try wip_nav.abbrevCode(.enum_field);
...@@ -4121,14 +4134,14 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -4121,14 +4134,14 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
4121 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);4134 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
4122 try wip_nav.declCommon(.{4135 try wip_nav.declCommon(.{
4123 .decl = .decl_namespace_struct,4136 .decl = .decl_namespace_struct,
4124 .generic_decl = .generic_decl_const,4137 .decl_specification = .decl_specification_const,
4125 .decl_instance = .decl_instance_namespace_struct,4138 .decl_instance = .decl_instance_namespace_struct,
4126 }, &nav, file, &decl);4139 }, &nav, file, &decl);
4127 } else {4140 } else {
4128 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);4141 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
4129 try wip_nav.abbrevCode(.empty_struct_type);4142 try wip_nav.abbrevCode(.empty_struct_type);
4130 try diw.writeUleb128(file_gop.index);4143 try diw.writeUleb128(file_gop.index);
4131 try wip_nav.strp(loaded_opaque.name.toSlice(ip));4144 try wip_nav.strp(loaded_opaque.fqn.toSlice(ip));
4132 }4145 }
4133 try diw.writeByte(@intFromBool(true));4146 try diw.writeByte(@intFromBool(true));
4134 },4147 },
...@@ -4614,6 +4627,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -4614,6 +4627,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
4614 }4627 }
4615 try diw.writeUleb128(@backingInt(AbbrevCode.null));4628 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4616 },4629 },
4630
4617 .memoized_call => unreachable, // not a value4631 .memoized_call => unreachable, // not a value
4618 }4632 }
4619 try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written());4633 try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written());
...@@ -4632,25 +4646,17 @@ fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { unpacked, opv_null, err...@@ -4632,25 +4646,17 @@ fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { unpacked, opv_null, err
4632 };4646 };
4633}4647}
46344648
4635pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedInst.Index) UpdateError!void {4649pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedInst.Index, line: u32) UpdateError!void {
4636 const comp = dwarf.bin_file.comp;4650 const comp = dwarf.bin_file.comp;
4637 const io = comp.io;4651 const io = comp.io;
4638 const ip = &zcu.intern_pool;4652 const ip = &zcu.intern_pool;
46394653
4640 const inst_info = zir_index.resolveFull(ip).?;4654 const inst_info = zir_index.resolveFull(ip).?;
4641 assert(inst_info.inst != .main_struct_inst);4655 if (inst_info.inst == .main_struct_inst) return;
4642 const file = zcu.fileByIndex(inst_info.file);4656 const file = zcu.fileByIndex(inst_info.file);
4643 const decl = file.zir.?.getDeclaration(inst_info.inst);
4644 log.debug("updateLineNumber({s}:{d}:{d} %{d} = {s})", .{
4645 file.sub_file_path,
4646 decl.src_line + 1,
4647 decl.src_column + 1,
4648 @backingInt(inst_info.inst),
4649 file.zir.?.nullTerminatedString(decl.name),
4650 });
46514657
4652 var line_buf: [4]u8 = undefined;4658 var line_buf: [4]u8 = undefined;
4653 std.mem.writeInt(u32, &line_buf, decl.src_line + 1, dwarf.endian);4659 std.mem.writeInt(u32, &line_buf, line + 1, dwarf.endian);
46544660
4655 const unit = dwarf.debug_info.section.getUnit(dwarf.getUnitIfExists(file.mod.?) orelse return);4661 const unit = dwarf.debug_info.section.getUnit(dwarf.getUnitIfExists(file.mod.?) orelse return);
4656 const entry = unit.getEntry(dwarf.decls.get(zir_index) orelse return);4662 const entry = unit.getEntry(dwarf.decls.get(zir_index) orelse return);
...@@ -4696,7 +4702,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Err...@@ -4696,7 +4702,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Err
46964702
4697 // Update `anyerror` based on the finished global error set.4703 // Update `anyerror` based on the finished global error set.
4698 {4704 {
4699 const index = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, .anyerror_type);4705 const index = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), .anyerror_type);
4700 const unit, const entry = dwarf.values.items[@backingInt(index)];4706 const unit, const entry = dwarf.values.items[@backingInt(index)];
4701 var wip_nav: WipNav = .{4707 var wip_nav: WipNav = .{
4702 .dwarf = dwarf,4708 .dwarf = dwarf,
...@@ -4731,7 +4737,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Err...@@ -4731,7 +4737,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Err
4731 }4737 }
4732 if (global_error_set_names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null));4738 if (global_error_set_names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4733 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());4739 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
4734 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });4740 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
4735 }4741 }
47364742
4737 for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {4743 for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {
...@@ -4783,7 +4789,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Err...@@ -4783,7 +4789,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Err
4783 .debug_frame => unreachable,4789 .debug_frame => unreachable,
4784 .eh_frame => switch (target.cpu.arch) {4790 .eh_frame => switch (target.cpu.arch) {
4785 .x86_64 => {4791 .x86_64 => {
4786 dev.check(.x86_64_backend);4792 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
4787 const Register = @import("../codegen/x86_64/bits.zig").Register;4793 const Register = @import("../codegen/x86_64/bits.zig").Register;
4788 for (dwarf.debug_frame.section.units.items) |*unit| {4794 for (dwarf.debug_frame.section.units.items) |*unit| {
4789 header_aw.clearRetainingCapacity();4795 header_aw.clearRetainingCapacity();
...@@ -5131,9 +5137,9 @@ const AbbrevCode = enum {...@@ -5131,9 +5137,9 @@ const AbbrevCode = enum {
5131 decl_func_generic,5137 decl_func_generic,
5132 decl_extern_nullary_func,5138 decl_extern_nullary_func,
5133 decl_extern_func,5139 decl_extern_func,
5134 generic_decl_var,5140 decl_specification_var,
5135 generic_decl_const,5141 decl_specification_const,
5136 generic_decl_func,5142 decl_specification_func,
5137 decl_instance_alias,5143 decl_instance_alias,
5138 decl_instance_empty_enum,5144 decl_instance_empty_enum,
5139 decl_instance_enum,5145 decl_instance_enum,
...@@ -5257,7 +5263,7 @@ const AbbrevCode = enum {...@@ -5257,7 +5263,7 @@ const AbbrevCode = enum {
5257 .{ .accessibility, .data1 },5263 .{ .accessibility, .data1 },
5258 .{ .name, .strp },5264 .{ .name, .strp },
5259 };5265 };
5260 const generic_decl_abbrev_common_attrs = decl_abbrev_common_attrs ++ &[_]Attr{5266 const decl_specification_abbrev_common_attrs = decl_abbrev_common_attrs ++ &[_]Attr{
5261 .{ .declaration, .flag_present },5267 .{ .declaration, .flag_present },
5262 };5268 };
5263 const decl_instance_abbrev_common_attrs = &[_]Attr{5269 const decl_instance_abbrev_common_attrs = &[_]Attr{
...@@ -5442,17 +5448,17 @@ const AbbrevCode = enum {...@@ -5442,17 +5448,17 @@ const AbbrevCode = enum {
5442 .{ .noreturn, .flag },5448 .{ .noreturn, .flag },
5443 },5449 },
5444 },5450 },
5445 .generic_decl_var = .{5451 .decl_specification_var = .{
5446 .tag = .variable,5452 .tag = .variable,
5447 .attrs = generic_decl_abbrev_common_attrs,5453 .attrs = decl_specification_abbrev_common_attrs,
5448 },5454 },
5449 .generic_decl_const = .{5455 .decl_specification_const = .{
5450 .tag = .constant,5456 .tag = .constant,
5451 .attrs = generic_decl_abbrev_common_attrs,5457 .attrs = decl_specification_abbrev_common_attrs,
5452 },5458 },
5453 .generic_decl_func = .{5459 .decl_specification_func = .{
5454 .tag = .subprogram,5460 .tag = .subprogram,
5455 .attrs = generic_decl_abbrev_common_attrs,5461 .attrs = decl_specification_abbrev_common_attrs,
5456 },5462 },
5457 .decl_instance_alias = .{5463 .decl_instance_alias = .{
5458 .tag = .imported_declaration,5464 .tag = .imported_declaration,
...@@ -6301,6 +6307,14 @@ fn getFile(dwarf: *Dwarf) ?Io.File {...@@ -6301,6 +6307,14 @@ fn getFile(dwarf: *Dwarf) ?Io.File {
6301 return dwarf.bin_file.file;6307 return dwarf.bin_file.file;
6302}6308}
63036309
6310fn constPoolUser(dwarf: *Dwarf) link.ConstPool.User {
6311 return switch (dwarf.bin_file.tag) {
6312 else => unreachable,
6313 .elf => .{ .elf = dwarf },
6314 .macho => .{ .macho = dwarf },
6315 };
6316}
6317
6304fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {6318fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {
6305 const entry = try dwarf.debug_aranges.section.getUnit(unit).addEntry(dwarf.gpa);6319 const entry = try dwarf.debug_aranges.section.getUnit(unit).addEntry(dwarf.gpa);
6306 assert(try dwarf.debug_frame.section.getUnit(unit).addEntry(dwarf.gpa) == entry);6320 assert(try dwarf.debug_frame.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
...@@ -6362,14 +6376,14 @@ fn uleb128Bytes(value: anytype) u32 {...@@ -6362,14 +6376,14 @@ fn uleb128Bytes(value: anytype) u32 {
6362 var buf: [64]u8 = undefined;6376 var buf: [64]u8 = undefined;
6363 var dw: Writer.Discarding = .init(&buf);6377 var dw: Writer.Discarding = .init(&buf);
6364 dw.writer.writeUleb128(value) catch unreachable;6378 dw.writer.writeUleb128(value) catch unreachable;
6365 return @intCast(dw.count + dw.writer.end);6379 return @intCast(dw.fullCount());
6366}6380}
63676381
6368fn sleb128Bytes(value: anytype) u32 {6382fn sleb128Bytes(value: anytype) u32 {
6369 var buf: [64]u8 = undefined;6383 var buf: [64]u8 = undefined;
6370 var dw: Writer.Discarding = .init(&buf);6384 var dw: Writer.Discarding = .init(&buf);
6371 dw.writer.writeSleb128(value) catch unreachable;6385 dw.writer.writeSleb128(value) catch unreachable;
6372 return @intCast(dw.count + dw.writer.end);6386 return @intCast(dw.fullCount());
6373}6387}
63746388
6375/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional6389/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
src/link/Dwarf2.zig created+5247
...@@ -0,0 +1,5247 @@
1lf: *link.File,
2format: DW.Format,
3endian: std.lang.Endian,
4address_size: AddressSize,
5const_pool: link.ConstPool,
6
7units: []Unit,
8/// Indices are `link.ConstPool.Index`.
9consts: std.ArrayList(Const),
10globals: std.array_hash_map.Auto(InternPool.Nav.Index, Global),
11funcs: std.array_hash_map.Auto(InternPool.Nav.Index, Func),
12decls: std.array_hash_map.Auto(InternPool.TrackedInst.Index, Decl),
13pending_decl: struct { di: Decl.Index, instance_val: InternPool.Index },
14
15debug_abbrev: Abbrev,
16frame: Frame,
17debug_info: Info,
18debug_line: Line,
19debug_line_str: Str,
20debug_rnglists: Rnglists,
21debug_str: Str,
22debug_str_offsets: StrOffsets,
23
24pub const AddressSize = enum(u8) { @"32" = 4, @"64" = 8, _ };
25
26pub const Unit = struct {
27 alive: bool,
28 dirs: std.array_hash_map.Auto(Unit.Index, void),
29 files: std.array_hash_map.Auto(Zcu.File.Index, void),
30 frame_ni: link.MappedFile.Node.Index.Optional,
31 cie_ni: link.MappedFile.Node.Index.Optional,
32 debug_info_ni: link.MappedFile.Node.Index.Optional,
33 debug_info_header_ni: link.MappedFile.Node.Index.Optional,
34 debug_info_footer_ni: link.MappedFile.Node.Index.Optional,
35 debug_line_ni: link.MappedFile.Node.Index.Optional,
36 debug_line_header_ni: link.MappedFile.Node.Index.Optional,
37 debug_line_header_changed: bool,
38 debug_rnglists_ni: link.MappedFile.Node.Index.Optional,
39 debug_rnglists_offsets_table_offset: usize,
40 debug_rnglists_end: usize,
41
42 pub const Index = enum(u32) {
43 _,
44
45 pub fn mod(ui: Unit.Index, dwarf: *Dwarf) *Module {
46 return dwarf.lf.comp.zcu.?.module_roots.keys()[@backingInt(ui)];
47 }
48
49 pub fn get(ui: Unit.Index, dwarf: *Dwarf) *Unit {
50 return &dwarf.units[@backingInt(ui)];
51 }
52 };
53
54 pub const DirIndex = enum(u32) {
55 root = 0,
56 _,
57
58 fn get(di: DirIndex, unit: *Unit) Unit.Index {
59 return unit.dirs.keys()[@backingInt(di)];
60 }
61 };
62
63 pub const FileIndex = enum(u32) {
64 root = 0,
65 _,
66
67 fn get(fi: FileIndex, unit: *Unit) Zcu.File.Index {
68 return unit.files.keys()[@backingInt(fi)];
69 }
70 };
71
72 fn deinit(unit: *Unit, gpa: std.mem.Allocator) void {
73 unit.dirs.deinit(gpa);
74 unit.files.deinit(gpa);
75 unit.* = undefined;
76 }
77
78 fn getFile(
79 unit: *Unit,
80 gpa: std.mem.Allocator,
81 ui: Unit.Index,
82 zfi: Zcu.File.Index,
83 ) std.mem.Allocator.Error!struct { DirIndex, FileIndex } {
84 try unit.dirs.ensureUnusedCapacity(gpa, 1);
85 try unit.files.ensureUnusedCapacity(gpa, 1);
86 const dir_gop = unit.dirs.getOrPutAssumeCapacity(ui);
87 const file_gop = unit.files.getOrPutAssumeCapacity(zfi);
88 if (!dir_gop.found_existing or !file_gop.found_existing) unit.debug_line_header_changed = true;
89 return .{ @fromBackingInt(@intCast(dir_gop.index)), @fromBackingInt(@intCast(file_gop.index)) };
90 }
91
92 pub fn cleanDebugLineHeaderChanged(unit: *Unit) bool {
93 defer unit.debug_line_header_changed = false;
94 return unit.debug_line_header_changed;
95 }
96};
97
98pub const Const = struct {
99 debug_info_ni: link.MappedFile.Node.Index.Optional,
100
101 pub fn get(cpi: link.ConstPool.Index, dwarf: *Dwarf) *Const {
102 return &dwarf.consts.items[@backingInt(cpi)];
103 }
104};
105
106pub const Global = struct {
107 debug_info_ni: link.MappedFile.Node.Index.Optional,
108
109 pub const Index = enum(u32) {
110 _,
111
112 pub fn nav(gi: Global.Index, dwarf: *Dwarf) InternPool.Nav.Index {
113 return dwarf.globals.keys()[@backingInt(gi)];
114 }
115
116 pub fn get(gi: Global.Index, dwarf: *Dwarf) *Global {
117 return &dwarf.globals.values()[@backingInt(gi)];
118 }
119 };
120};
121
122pub const Func = struct {
123 state: State,
124 fde_ni: link.MappedFile.Node.Index.Optional,
125 debug_info_ni: link.MappedFile.Node.Index.Optional,
126 debug_line_ni: link.MappedFile.Node.Index.Optional,
127
128 pub const State = enum { unresolved, resolved };
129
130 pub const Index = enum(u32) {
131 _,
132
133 pub fn nav(fi: Func.Index, dwarf: *Dwarf) InternPool.Nav.Index {
134 return dwarf.funcs.keys()[@backingInt(fi)];
135 }
136
137 pub fn get(fi: Func.Index, dwarf: *Dwarf) *Func {
138 return &dwarf.funcs.values()[@backingInt(fi)];
139 }
140 };
141};
142
143pub const Decl = struct {
144 debug_info_ni: link.MappedFile.Node.Index.Optional,
145
146 pub const Index = enum(u32) {
147 _,
148
149 pub fn srcInst(di: Decl.Index, dwarf: *Dwarf) InternPool.TrackedInst.Index {
150 return dwarf.decls.keys()[@backingInt(di)];
151 }
152
153 pub fn get(di: Decl.Index, dwarf: *Dwarf) *Decl {
154 return &dwarf.decls.values()[@backingInt(di)];
155 }
156 };
157};
158
159pub const Frame = struct {
160 header: Header,
161
162 pub const Header = struct {
163 code_alignment_factor: u32,
164 data_alignment_factor: i32,
165 return_address_register: u32,
166 initial_instructions: []const Cfa,
167 };
168
169 pub const Format = std.debug.Dwarf.Unwind.Section;
170};
171
172pub const Abbrev = struct {
173 ni: link.MappedFile.Node.Index.Optional,
174 end: usize,
175 set: std.enums.EnumSet(AbbrevCode),
176};
177
178pub const Info = struct {};
179
180pub const Line = struct {
181 header: Header,
182
183 pub const Header = struct {
184 minimum_instruction_length: u8,
185 maximum_operations_per_instruction: u8,
186 default_is_stmt: bool,
187 line_base: i8,
188 line_range: u8,
189 opcode_base: u8,
190 };
191};
192
193pub const Str = struct {
194 ni: link.MappedFile.Node.Index.Optional,
195 offset: usize,
196 map: std.HashMapUnmanaged(usize, void, Context, std.hash_map.default_max_load_percentage),
197
198 fn get(
199 s: *Str,
200 gpa: std.mem.Allocator,
201 mf: *link.MappedFile,
202 str: []const u8,
203 ) link.MappedFile.Error!usize {
204 const ni = s.ni.unwrap().?;
205 const slice = ni.sliceConst(mf);
206 const gop = try s.map.getOrPutContextAdapted(
207 gpa,
208 str,
209 Adapter{ .slice = slice },
210 .{ .slice = slice },
211 );
212 if (!gop.found_existing) {
213 gop.key_ptr.* = s.offset;
214 try ni.ensureMinimumSize(gpa, mf, s.offset + str.len + 1);
215 const slice_mut = ni.slice(mf);
216 @memcpy(slice_mut[s.offset..][0..str.len], str);
217 s.offset += str.len;
218 slice_mut[s.offset] = 0;
219 s.offset += 1;
220 }
221 return gop.key_ptr.*;
222 }
223
224 const Context = struct {
225 slice: []const u8,
226 pub fn hash(context: Context, offset: usize) u64 {
227 return std.hash.Wyhash.hash(0, std.mem.sliceTo(context.slice[offset..], 0));
228 }
229 pub fn eql(_: Context, lhs_offset: usize, rhs_offset: usize) bool {
230 return lhs_offset == rhs_offset;
231 }
232 };
233
234 const Adapter = struct {
235 slice: []const u8,
236 pub fn hash(_: Adapter, key: []const u8) u64 {
237 return std.hash.Wyhash.hash(0, key);
238 }
239 pub fn eql(adapter: Adapter, key: []const u8, rhs_offset: usize) bool {
240 return std.mem.startsWith(u8, adapter.slice[rhs_offset..], key) and
241 adapter.slice[rhs_offset + key.len] == 0;
242 }
243 };
244};
245
246pub const Rnglists = struct {
247 fn offsetsTableOffset(dwarf: *Dwarf) usize {
248 return dwarf.unitLengthSize() + 2 + 1 + 1 + 4;
249 }
250};
251
252pub const StrOffsets = struct {
253 ni: link.MappedFile.Node.Index.Optional,
254 offset: usize,
255};
256
257pub const SharedSection = enum { debug_abbrev, debug_line_str, debug_str, debug_str_offsets };
258
259pub const Loc = union(enum) {
260 empty,
261 addr_reloc: link.File.SymbolId,
262 deref: *const Loc,
263 constu: u64,
264 consts: i64,
265 plus: Bin,
266 reg: u32,
267 breg: u32,
268 push_object_address,
269 call: struct {
270 args: []const Loc = &.{},
271 node: link.MappedFile.Node.Index,
272 },
273 form_tls_address: *const Loc,
274 implicit_value: []const u8,
275 stack_value: *const Loc,
276 implicit_pointer: struct {
277 node: link.MappedFile.Node.Index,
278 offset: i65 = 0,
279 },
280 wasm_ext: union(enum) {
281 local: u32,
282 global: u32,
283 operand_stack: u32,
284 },
285
286 pub const Bin = struct { *const Loc, *const Loc };
287
288 fn getConst(loc: Loc, comptime Int: type) ?Int {
289 return switch (loc) {
290 .constu => |constu| std.math.cast(Int, constu),
291 .consts => |consts| std.math.cast(Int, consts),
292 else => null,
293 };
294 }
295
296 fn getBaseReg(loc: Loc) ?u32 {
297 return switch (loc) {
298 .breg => |breg| breg,
299 else => null,
300 };
301 }
302
303 fn writeReg(reg: u32, op0: u8, opx: u8, writer: *std.Io.Writer) std.Io.Writer.Error!void {
304 if (std.math.cast(u5, reg)) |small_reg| {
305 try writer.writeByte(op0 + small_reg);
306 } else {
307 try writer.writeByte(opx);
308 try writer.writeUleb128(reg);
309 }
310 }
311
312 fn write(loc: Loc, writer: union(enum) {
313 io: *std.Io.Writer,
314 mf: *link.MappedFile.Node.Writer,
315 }, dwarf: *Dwarf) link.EmitError!void {
316 const w = switch (writer) {
317 .io => |w| w,
318 .mf => |nw| &nw.interface,
319 };
320 switch (loc) {
321 .empty => {},
322 .addr_reloc => |si| {
323 try w.writeByte(DW.OP.addr);
324 switch (writer) {
325 .io => try dwarf.addrPlaceholder(w),
326 .mf => |nw| try dwarf.addrSym(nw, si, 0),
327 }
328 },
329 .deref => |addr| {
330 try addr.write(writer, dwarf);
331 try w.writeByte(DW.OP.deref);
332 },
333 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
334 try w.writeByte(@as(u8, DW.OP.lit0) + lit);
335 } else if (std.math.cast(u8, constu)) |const1u| {
336 try w.writeAll(&.{ DW.OP.const1u, const1u });
337 } else if (std.math.cast(u16, constu)) |const2u| {
338 try w.writeByte(DW.OP.const2u);
339 try w.writeInt(u16, const2u, dwarf.endian);
340 } else if (std.math.cast(u21, constu)) |const3u| {
341 try w.writeByte(DW.OP.constu);
342 try w.writeUleb128(const3u);
343 } else if (std.math.cast(u32, constu)) |const4u| {
344 try w.writeByte(DW.OP.const4u);
345 try w.writeInt(u32, const4u, dwarf.endian);
346 } else if (std.math.cast(u49, constu)) |const7u| {
347 try w.writeByte(DW.OP.constu);
348 try w.writeUleb128(const7u);
349 } else {
350 try w.writeByte(DW.OP.const8u);
351 try w.writeInt(u64, constu, dwarf.endian);
352 },
353 .consts => |consts| if (std.math.cast(i8, consts)) |const1s| {
354 try w.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) });
355 } else if (std.math.cast(i16, consts)) |const2s| {
356 try w.writeByte(DW.OP.const2s);
357 try w.writeInt(i16, const2s, dwarf.endian);
358 } else if (std.math.cast(i21, consts)) |const3s| {
359 try w.writeByte(DW.OP.consts);
360 try w.writeSleb128(const3s);
361 } else if (std.math.cast(i32, consts)) |const4s| {
362 try w.writeByte(DW.OP.const4s);
363 try w.writeInt(i32, const4s, dwarf.endian);
364 } else if (std.math.cast(i49, consts)) |const7s| {
365 try w.writeByte(DW.OP.consts);
366 try w.writeSleb128(const7s);
367 } else {
368 try w.writeByte(DW.OP.const8s);
369 try w.writeInt(i64, consts, dwarf.endian);
370 },
371 .plus => |plus| done: {
372 if (plus[0].getConst(u0)) |_| {
373 try plus[1].write(writer, dwarf);
374 break :done;
375 }
376 if (plus[1].getConst(u0)) |_| {
377 try plus[0].write(writer, dwarf);
378 break :done;
379 }
380 if (plus[0].getBaseReg()) |breg| {
381 if (plus[1].getConst(i65)) |offset| {
382 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, w);
383 try w.writeSleb128(offset);
384 break :done;
385 }
386 }
387 if (plus[1].getBaseReg()) |breg| {
388 if (plus[0].getConst(i65)) |offset| {
389 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, w);
390 try w.writeSleb128(offset);
391 break :done;
392 }
393 }
394 if (plus[0].getConst(u64)) |uconst| {
395 try plus[1].write(writer, dwarf);
396 try w.writeByte(DW.OP.plus_uconst);
397 try w.writeUleb128(uconst);
398 break :done;
399 }
400 if (plus[1].getConst(u64)) |uconst| {
401 try plus[0].write(writer, dwarf);
402 try w.writeByte(DW.OP.plus_uconst);
403 try w.writeUleb128(uconst);
404 break :done;
405 }
406 try plus[0].write(writer, dwarf);
407 try plus[1].write(writer, dwarf);
408 try w.writeByte(DW.OP.plus);
409 },
410 .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, w),
411 .breg => |breg| {
412 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, w);
413 try w.writeSleb128(0);
414 },
415 .push_object_address => try w.writeByte(DW.OP.push_object_address),
416 .call => |call| {
417 for (call.args) |arg| try arg.write(writer, dwarf);
418 try w.writeByte(DW.OP.call_ref);
419 switch (writer) {
420 .io => try dwarf.secOffsetPlaceholder(w),
421 .mf => |nw| try dwarf.secOffset(nw, call.node, 0),
422 }
423 },
424 .form_tls_address => |addr| {
425 try addr.write(writer, dwarf);
426 try w.writeByte(DW.OP.form_tls_address);
427 },
428 .implicit_value => |value| {
429 try w.writeByte(DW.OP.implicit_value);
430 try w.writeUleb128(value.len);
431 try w.writeAll(value);
432 },
433 .stack_value => |value| {
434 try value.write(writer, dwarf);
435 try w.writeByte(DW.OP.stack_value);
436 },
437 .implicit_pointer => |implicit_pointer| {
438 try w.writeByte(DW.OP.implicit_pointer);
439 switch (writer) {
440 .io => try dwarf.secOffsetPlaceholder(w),
441 .mf => |nw| try dwarf.secOffset(nw, implicit_pointer.node, 0),
442 }
443 try w.writeSleb128(implicit_pointer.offset);
444 },
445 .wasm_ext => |wasm_ext| {
446 try w.writeByte(DW.OP.WASM_location);
447 switch (wasm_ext) {
448 .local => |local| {
449 try w.writeByte(DW.OP.WASM_local);
450 try w.writeUleb128(local);
451 },
452 .global => |global| if (std.math.cast(u21, global)) |global_u21| {
453 try w.writeByte(DW.OP.WASM_global);
454 try w.writeUleb128(global_u21);
455 } else {
456 try w.writeByte(DW.OP.WASM_global_u32);
457 try w.writeInt(u32, global, dwarf.endian);
458 },
459 .operand_stack => |operand_stack| {
460 try w.writeByte(DW.OP.WASM_operand_stack);
461 try w.writeUleb128(operand_stack);
462 },
463 }
464 },
465 }
466 }
467};
468
469pub const Cfa = union(enum) {
470 nop,
471 advance_loc: u32,
472 offset: RegOff,
473 rel_offset: RegOff,
474 restore: u32,
475 undefined: u32,
476 same_value: u32,
477 register: [2]u32,
478 remember_state,
479 restore_state,
480 def_cfa: RegOff,
481 def_cfa_register: u32,
482 def_cfa_offset: i64,
483 adjust_cfa_offset: i64,
484 def_cfa_expression: Loc,
485 expression: RegExpr,
486 val_offset: RegOff,
487 val_expression: RegExpr,
488 escape: []const u8,
489
490 const RegOff = struct { reg: u32, off: i64 };
491 const RegExpr = struct { reg: u32, expr: Loc };
492
493 fn write(cfa: Cfa, wip_nav: *WipNav) link.EmitError!void {
494 const df_nw = &wip_nav.fde_writer;
495 const df_w = &df_nw.interface;
496 switch (cfa) {
497 .nop => try df_w.writeByte(DW.CFA.nop),
498 .advance_loc => |loc| {
499 const delta =
500 @divExact(loc - wip_nav.cfi.loc, wip_nav.dwarf.frame.header.code_alignment_factor);
501 if (delta == 0) {} else if (std.math.cast(u6, delta)) |small_delta|
502 try df_w.writeByte(@as(u8, DW.CFA.advance_loc) + small_delta)
503 else if (std.math.cast(u8, delta)) |ubyte_delta|
504 try df_w.writeAll(&.{ DW.CFA.advance_loc1, ubyte_delta })
505 else if (std.math.cast(u16, delta)) |uhalf_delta| {
506 try df_w.writeByte(DW.CFA.advance_loc2);
507 try df_w.writeInt(u16, uhalf_delta, wip_nav.dwarf.endian);
508 } else if (std.math.cast(u32, delta)) |uword_delta| {
509 try df_w.writeByte(DW.CFA.advance_loc4);
510 try df_w.writeInt(u32, uword_delta, wip_nav.dwarf.endian);
511 }
512 wip_nav.cfi.loc = loc;
513 },
514 .offset, .rel_offset => |reg_off| {
515 const factored_off = @divExact(reg_off.off - switch (cfa) {
516 else => unreachable,
517 .offset => 0,
518 .rel_offset => wip_nav.cfi.cfa.off,
519 }, wip_nav.dwarf.frame.header.data_alignment_factor);
520 if (std.math.cast(u63, factored_off)) |unsigned_off| {
521 if (std.math.cast(u6, reg_off.reg)) |small_reg| {
522 try df_w.writeByte(@as(u8, DW.CFA.offset) + small_reg);
523 } else {
524 try df_w.writeByte(DW.CFA.offset_extended);
525 try df_w.writeUleb128(reg_off.reg);
526 }
527 try df_w.writeUleb128(unsigned_off);
528 } else {
529 try df_w.writeByte(DW.CFA.offset_extended_sf);
530 try df_w.writeUleb128(reg_off.reg);
531 try df_w.writeSleb128(factored_off);
532 }
533 },
534 .restore => |reg| if (std.math.cast(u6, reg)) |small_reg|
535 try df_w.writeByte(@as(u8, DW.CFA.restore) + small_reg)
536 else {
537 try df_w.writeByte(DW.CFA.restore_extended);
538 try df_w.writeUleb128(reg);
539 },
540 .undefined => |reg| {
541 try df_w.writeByte(DW.CFA.undefined);
542 try df_w.writeUleb128(reg);
543 },
544 .same_value => |reg| {
545 try df_w.writeByte(DW.CFA.same_value);
546 try df_w.writeUleb128(reg);
547 },
548 .register => |regs| if (regs[0] != regs[1]) {
549 try df_w.writeByte(DW.CFA.register);
550 for (regs) |reg| try df_w.writeUleb128(reg);
551 } else {
552 try df_w.writeByte(DW.CFA.same_value);
553 try df_w.writeUleb128(regs[0]);
554 },
555 .remember_state => try df_w.writeByte(DW.CFA.remember_state),
556 .restore_state => try df_w.writeByte(DW.CFA.restore_state),
557 .def_cfa, .def_cfa_register, .def_cfa_offset, .adjust_cfa_offset => {
558 const reg_off: RegOff = switch (cfa) {
559 else => unreachable,
560 .def_cfa => |reg_off| reg_off,
561 .def_cfa_register => |reg| .{ .reg = reg, .off = wip_nav.cfi.cfa.off },
562 .def_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = off },
563 .adjust_cfa_offset => |off| .{
564 .reg = wip_nav.cfi.cfa.reg,
565 .off = wip_nav.cfi.cfa.off + off,
566 },
567 };
568 const changed_reg = reg_off.reg != wip_nav.cfi.cfa.reg;
569 const unsigned_off = std.math.cast(u63, reg_off.off);
570 if (reg_off.off == wip_nav.cfi.cfa.off) {
571 if (changed_reg) {
572 try df_w.writeByte(DW.CFA.def_cfa_register);
573 try df_w.writeUleb128(reg_off.reg);
574 }
575 } else if (switch (wip_nav.dwarf.frame.header.data_alignment_factor) {
576 0 => unreachable,
577 1 => unsigned_off != null,
578 else => |data_alignment_factor| @rem(reg_off.off, data_alignment_factor) != 0,
579 }) {
580 try df_w.writeByte(if (changed_reg) DW.CFA.def_cfa else DW.CFA.def_cfa_offset);
581 if (changed_reg) try df_w.writeUleb128(reg_off.reg);
582 try df_w.writeUleb128(unsigned_off.?);
583 } else {
584 try df_w.writeByte(if (changed_reg) DW.CFA.def_cfa_sf else DW.CFA.def_cfa_offset_sf);
585 if (changed_reg) try df_w.writeUleb128(reg_off.reg);
586 try df_w.writeSleb128(
587 @divExact(reg_off.off, wip_nav.dwarf.frame.header.data_alignment_factor),
588 );
589 }
590 wip_nav.cfi.cfa = reg_off;
591 },
592 .def_cfa_expression => |expr| {
593 try df_w.writeByte(DW.CFA.def_cfa_expression);
594 try wip_nav.dwarf.exprLoc(df_nw, expr);
595 },
596 .expression => |reg_expr| {
597 try df_w.writeByte(DW.CFA.expression);
598 try df_w.writeUleb128(reg_expr.reg);
599 try wip_nav.dwarf.exprLoc(df_nw, reg_expr.expr);
600 },
601 .val_offset => |reg_off| {
602 const factored_off =
603 @divExact(reg_off.off, wip_nav.dwarf.frame.header.data_alignment_factor);
604 if (std.math.cast(u63, factored_off)) |unsigned_off| {
605 try df_w.writeByte(DW.CFA.val_offset);
606 try df_w.writeUleb128(reg_off.reg);
607 try df_w.writeUleb128(unsigned_off);
608 } else {
609 try df_w.writeByte(DW.CFA.val_offset_sf);
610 try df_w.writeUleb128(reg_off.reg);
611 try df_w.writeSleb128(factored_off);
612 }
613 },
614 .val_expression => |reg_expr| {
615 try df_w.writeByte(DW.CFA.val_expression);
616 try df_w.writeUleb128(reg_expr.reg);
617 try wip_nav.dwarf.exprLoc(df_nw, reg_expr.expr);
618 },
619 .escape => |bytes| try df_w.writeAll(bytes),
620 }
621 }
622};
623
624pub const WipNav = struct {
625 dwarf: *Dwarf,
626 unit: Unit.Index,
627 func: InternPool.Index,
628 func_si: link.File.SymbolId,
629 cfi: struct {
630 loc: u32,
631 cfa: Cfa.RegOff,
632 },
633 frame_format: Frame.Format,
634 fde_writer: link.MappedFile.Node.Writer,
635 frame_func_length: struct { offset: usize, size: AddressSize },
636
637 pub const Debug = struct {
638 wip_nav: WipNav,
639 pt: Zcu.PerThread,
640 any_children: bool,
641 blocks: std.ArrayList(struct {
642 abbrev_code: u32,
643 low_pc_off: usize,
644 high_pc: u32,
645 }),
646 info_writer: link.MappedFile.Node.Writer,
647 info_func_length_offset: usize,
648 line_writer: link.MappedFile.Node.Writer,
649
650 pub fn deinit(debug: *Debug) void {
651 const gpa = debug.pt.zcu.gpa;
652 debug.line_writer.deinit();
653 debug.info_writer.deinit();
654 debug.blocks.deinit(gpa);
655 debug.wip_nav.deinit();
656 debug.* = undefined;
657 }
658
659 pub fn genDebugFrame(debug: *Debug, loc: u32, cfa: Cfa) link.Error!void {
660 return debug.wip_nav.genDebugFrame(loc, cfa);
661 }
662
663 pub fn startFuncDebugInfo(debug: *Debug) link.Error!void {
664 assert(debug.wip_nav.func != .none);
665 debug.startFuncDebugInfoInner() catch |err| switch (err) {
666 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer),
667 else => |e| return e,
668 };
669 }
670 fn startFuncDebugInfoInner(debug: *Debug) link.EmitError!void {
671 const dwarf = debug.wip_nav.dwarf;
672 const pt = debug.pt;
673 const zcu = pt.zcu;
674 const ip = &zcu.intern_pool;
675 const func = zcu.funcInfo(debug.wip_nav.func);
676 const nav = ip.getNav(func.owner_nav);
677 const func_type = ip.indexToKey(func.ty).func_type;
678 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
679 const zf = zcu.fileByIndex(inst_info.file);
680 const target = &zf.mod.?.resolved_target.result;
681 const decl = zf.zir.?.getDeclaration(inst_info.inst);
682 const di_nw = &debug.info_writer;
683 const di_w = &di_nw.interface;
684 try dwarf.abbrevCode(di_nw, .decl_func);
685 try dwarf.refType(pt, di_nw, .fromInterned(ip.namespacePtr(switch (func.generic_owner) {
686 .none => nav,
687 else => |generic_owner| ip.getNav(zcu.funcInfo(generic_owner).owner_nav),
688 }.analysis.?.namespace).owner_type));
689 try di_w.writeInt(u32, decl.src_line + 1, dwarf.endian);
690 try di_w.writeUleb128(decl.src_column + 1);
691 try di_w.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
692 try dwarf.strp(&dwarf.debug_str, di_nw, nav.name.toSlice(ip));
693 try dwarf.strp(&dwarf.debug_str, di_nw, switch (decl.linkage) {
694 .normal => nav.fqn,
695 .@"extern", .@"export" => nav.name,
696 }.toSlice(ip));
697 try dwarf.refType(pt, di_nw, .fromInterned(func_type.return_type));
698 try dwarf.addrSym(di_nw, debug.wip_nav.func_si, 0);
699 debug.info_func_length_offset = di_w.end;
700 try di_w.writeInt(u32, undefined, dwarf.endian);
701 try di_w.writeUleb128(
702 target_info.minFunctionAlignment(target).max(nav.resolved.?.@"align").toByteUnits().?,
703 );
704 try di_w.writeByte(@intFromBool(decl.linkage != .normal));
705 try di_w.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
706 }
707
708 pub fn startDebugLine(debug: *Debug) link.Error!void {
709 assert(debug.wip_nav.func != .none);
710 debug.startDebugLineInner() catch |err| switch (err) {
711 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer),
712 else => |e| return e,
713 };
714 }
715 fn startDebugLineInner(debug: *Debug) link.EmitError!void {
716 const dwarf = debug.wip_nav.dwarf;
717 const zcu = debug.pt.zcu;
718 const ip = &zcu.intern_pool;
719 const func = zcu.funcInfo(debug.wip_nav.func);
720 const inst_info = ip.getNav(func.owner_nav).srcInst(ip).resolveFull(ip).?;
721 const zf = zcu.fileByIndex(inst_info.file);
722 const decl = zf.zir.?.getDeclaration(inst_info.inst);
723 const dl_nw = &debug.line_writer;
724 const dl_w = &dl_nw.interface;
725 try dl_w.writeByte(DW.LNS.extended_op);
726 if (zcu.comp.config.incremental) {
727 try dl_w.writeUleb128(1 + dwarf.secOffsetSize());
728 try dl_w.writeByte(DW.LNE.ZIG_set_decl);
729 try dwarf.secOffset(dl_nw, debug.info_writer.ni, 0);
730
731 try dl_w.writeByte(DW.LNS.set_column);
732 try dl_w.writeUleb128(func.lbrace_column + 1);
733
734 try debug.advanceLineAndPc(func.lbrace_line, 0, false);
735 } else {
736 try dl_w.writeUleb128(1 + @backingInt(dwarf.address_size));
737 try dl_w.writeByte(DW.LNE.set_address);
738 try dwarf.addrSym(dl_nw, debug.wip_nav.func_si, 0);
739
740 const unit = dwarf.getUnit(zf.mod.?);
741 _, const fi = try unit.get(dwarf).getFile(zcu.gpa, unit, inst_info.file);
742 try dl_w.writeByte(DW.LNS.set_file);
743 try dl_w.writeUleb128(@backingInt(fi));
744
745 try dl_w.writeByte(DW.LNS.set_column);
746 try dl_w.writeUleb128(func.lbrace_column + 1);
747
748 try debug.advanceLineAndPc(decl.src_line + func.lbrace_line, 0, false);
749 }
750 }
751
752 pub fn finishFunc(debug: *Debug, func_length: u64) link.Error!void {
753 assert(debug.wip_nav.func != .none);
754 const di_nw = &debug.info_writer;
755 debug.finishDebugInfo(func_length) catch |err| switch (err) {
756 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(di_nw),
757 else => |e| return e,
758 };
759 debug.finishDebugLine() catch |err| switch (err) {
760 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(di_nw),
761 else => |e| return e,
762 };
763 }
764 fn finishDebugInfo(debug: *Debug, func_length: u64) link.EmitError!void {
765 const dwarf = debug.wip_nav.dwarf;
766 const di_w = &debug.info_writer.interface;
767 std.mem.writeInt(
768 u32,
769 di_w.buffered()[debug.info_func_length_offset..][0..4],
770 @intCast(func_length),
771 dwarf.endian,
772 );
773 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
774 try dwarf.genDebugInfoPadding(di_w, di_w.unusedCapacityLen());
775 }
776 fn finishDebugLine(debug: *Debug) link.EmitError!void {
777 const dl_w = &debug.line_writer.interface;
778 try genDebugLinePadding(dl_w, dl_w.unusedCapacityLen());
779 }
780
781 pub const LocalVarTag = enum { arg, local_var };
782 pub fn genLocalVarDebugInfo(
783 debug: *Debug,
784 tag: LocalVarTag,
785 opt_name: ?[]const u8,
786 ty: Type,
787 loc: Loc,
788 ) link.Error!void {
789 return debug.genLocalVarDebugInfoInner(tag, opt_name, ty, loc) catch |err| switch (err) {
790 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer),
791 else => |e| e,
792 };
793 }
794 fn genLocalVarDebugInfoInner(
795 debug: *Debug,
796 tag: LocalVarTag,
797 opt_name: ?[]const u8,
798 ty: Type,
799 loc: Loc,
800 ) link.EmitError!void {
801 assert(debug.wip_nav.func != .none);
802 const dwarf = debug.wip_nav.dwarf;
803 const di_nw = &debug.info_writer;
804 try dwarf.abbrevCode(di_nw, switch (tag) {
805 .arg => if (opt_name) |_| .arg else .unnamed_arg,
806 .local_var => if (opt_name) |_| .local_var else unreachable,
807 });
808 if (opt_name) |name| try dwarf.strp(&dwarf.debug_str, di_nw, name);
809 try dwarf.refType(debug.pt, di_nw, ty);
810 try dwarf.exprLoc(di_nw, loc);
811 debug.any_children = true;
812 }
813
814 pub const LocalConstTag = enum { comptime_arg, local_const };
815 pub fn genLocalConstDebugInfo(
816 debug: *Debug,
817 tag: LocalConstTag,
818 opt_name: ?[]const u8,
819 val: Value,
820 ) link.Error!void {
821 return debug.genLocalConstDebugInfoInner(tag, opt_name, val) catch |err| switch (err) {
822 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer),
823 else => |e| e,
824 };
825 }
826 fn genLocalConstDebugInfoInner(
827 debug: *Debug,
828 tag: LocalConstTag,
829 opt_name: ?[]const u8,
830 val: Value,
831 ) link.EmitError!void {
832 assert(debug.wip_nav.func != .none);
833 const dwarf = debug.wip_nav.dwarf;
834 const pt = debug.pt;
835 const zcu = debug.pt.zcu;
836 const ty = val.typeOf(zcu);
837 const ty_class = ty.classify(zcu);
838 const di_nw = &debug.info_writer;
839 try dwarf.abbrevCode(di_nw, switch (tag) {
840 .comptime_arg => if (opt_name) |_| switch (ty_class) {
841 .no_possible_value => unreachable,
842 .one_possible_value => .comptime_arg,
843 .runtime => .comptime_arg_fully_runtime,
844 .partially_comptime => .comptime_arg_partially_comptime,
845 .fully_comptime => .comptime_arg_fully_comptime,
846 } else switch (ty_class) {
847 .no_possible_value => unreachable,
848 .one_possible_value => .unnamed_comptime_arg,
849 .runtime => .unnamed_comptime_arg_fully_runtime,
850 .partially_comptime => .unnamed_comptime_arg_partially_comptime,
851 .fully_comptime => .unnamed_comptime_arg_fully_comptime,
852 },
853 .local_const => if (opt_name) |_| switch (ty_class) {
854 .no_possible_value => unreachable,
855 .one_possible_value => .local_const,
856 .runtime => .local_const_fully_runtime,
857 .partially_comptime => .local_const_partially_comptime,
858 .fully_comptime => .local_const_fully_comptime,
859 } else unreachable,
860 });
861 if (opt_name) |name| try dwarf.strp(&dwarf.debug_str, di_nw, name);
862 try dwarf.refType(pt, di_nw, ty);
863 if (ty_class.hasRuntimeBits()) try dwarf.blockConst(pt, di_nw, val);
864 if (ty_class.comptimeOnly()) try dwarf.refConst(pt, di_nw, val);
865 debug.any_children = true;
866 }
867
868 pub fn genVarArgsDebugInfo(debug: *Debug) link.Error!void {
869 return debug.genVarArgsDebugInfoInner() catch |err| switch (err) {
870 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer),
871 else => |e| e,
872 };
873 }
874 fn genVarArgsDebugInfoInner(debug: *Debug) link.EmitError!void {
875 assert(debug.wip_nav.func != .none);
876 try debug.wip_nav.dwarf.abbrevCode(&debug.info_writer, .is_var_args);
877 debug.any_children = true;
878 }
879
880 pub fn advanceLineAndPc(
881 debug: *Debug,
882 delta_line: i33,
883 delta_pc: u64,
884 end: bool,
885 ) link.Error!void {
886 return debug.advanceLineAndPcInner(delta_line, delta_pc, end) catch |err| switch (err) {
887 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer),
888 };
889 }
890 fn advanceLineAndPcInner(
891 debug: *Debug,
892 delta_line: i33,
893 delta_pc: u64,
894 end: bool,
895 ) std.Io.Writer.Error!void {
896 const dl_w = &debug.line_writer.interface;
897
898 const header = debug.wip_nav.dwarf.debug_line.header;
899 assert(header.maximum_operations_per_instruction == 1);
900 const delta_op: u64 = 0;
901
902 const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or
903 delta_line - header.line_base >= header.line_range)
904 remaining: {
905 assert(delta_line != 0);
906 try dl_w.writeByte(DW.LNS.advance_line);
907 try dl_w.writeSleb128(delta_line);
908 break :remaining 0;
909 } else delta_line);
910
911 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
912 header.maximum_operations_per_instruction + delta_op;
913 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
914 const remaining_op_advance: u8 = @intCast(if (end or
915 op_advance >= 2 * max_op_advance)
916 remaining: {
917 if (op_advance == max_op_advance) {
918 try dl_w.writeByte(DW.LNS.const_add_pc);
919 } else if (op_advance != 0) {
920 try dl_w.writeByte(DW.LNS.advance_pc);
921 try dl_w.writeUleb128(op_advance);
922 } else assert(end);
923 break :remaining 0;
924 } else if (op_advance >= max_op_advance) remaining: {
925 try dl_w.writeByte(DW.LNS.const_add_pc);
926 break :remaining op_advance - max_op_advance;
927 } else op_advance);
928
929 if (remaining_delta_line != 0 or remaining_op_advance != 0) {
930 assert(!end);
931 try dl_w.writeByte(@intCast((remaining_delta_line - header.line_base) +
932 (header.line_range * remaining_op_advance) + header.opcode_base));
933 } else if (end) {
934 try dl_w.writeByte(DW.LNS.extended_op);
935 try dl_w.writeUleb128(1);
936 try dl_w.writeByte(DW.LNE.end_sequence);
937 } else try dl_w.writeByte(DW.LNS.copy);
938 }
939
940 pub fn setColumn(debug: *Debug, column: u32) link.Error!void {
941 return debug.setColumnInner(column) catch |err| switch (err) {
942 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer),
943 };
944 }
945 fn setColumnInner(debug: *Debug, column: u32) std.Io.Writer.Error!void {
946 const dl_w = &debug.line_writer.interface;
947 try dl_w.writeByte(DW.LNS.set_column);
948 try dl_w.writeUleb128(column + 1);
949 }
950
951 pub fn negateStmt(debug: *Debug) link.Error!void {
952 return debug.negateStmtInner() catch |err| switch (err) {
953 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer),
954 };
955 }
956 fn negateStmtInner(debug: *Debug) std.Io.Writer.Error!void {
957 try debug.line_writer.interface.writeByte(DW.LNS.negate_stmt);
958 }
959
960 pub fn setPrologueEnd(debug: *Debug) link.Error!void {
961 return debug.setPrologueEndInner() catch |err| switch (err) {
962 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer),
963 };
964 }
965 fn setPrologueEndInner(debug: *Debug) std.Io.Writer.Error!void {
966 try debug.line_writer.interface.writeByte(DW.LNS.set_prologue_end);
967 }
968
969 pub fn setEpilogueBegin(debug: *Debug) link.Error!void {
970 return debug.setEpilogueBeginInner() catch |err| switch (err) {
971 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer),
972 };
973 }
974 fn setEpilogueBeginInner(debug: *Debug) std.Io.Writer.Error!void {
975 try debug.line_writer.interface.writeByte(DW.LNS.set_epilogue_begin);
976 }
977
978 pub fn enterBlock(debug: *Debug, code_off: usize) link.Error!void {
979 return debug.enterBlockInner(code_off) catch |err| switch (err) {
980 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer),
981 else => |e| e,
982 };
983 }
984 fn enterBlockInner(debug: *Debug, code_off: usize) link.EmitError!void {
985 const dwarf = debug.wip_nav.dwarf;
986 const block = try debug.blocks.addOne(dwarf.lf.comp.gpa);
987
988 const di_nw = &debug.info_writer;
989 const di_w = &di_nw.interface;
990 block.abbrev_code = @intCast(di_w.end);
991 try dwarf.abbrevCode(di_nw, .block);
992 block.low_pc_off = code_off;
993 try dwarf.addrSym(di_nw, debug.wip_nav.func_si, code_off);
994 block.high_pc = @intCast(di_w.end);
995 try di_w.writeInt(u32, 0, dwarf.endian);
996 debug.any_children = false;
997 }
998
999 pub fn leaveBlock(debug: *Debug, code_off: usize) link.Error!void {
1000 return debug.leaveBlockInner(code_off) catch |err| switch (err) {
1001 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer),
1002 else => |e| e,
1003 };
1004 }
1005 fn leaveBlockInner(debug: *Debug, code_off: usize) link.EmitError!void {
1006 const dwarf = debug.wip_nav.dwarf;
1007 const block_size = comptime uleb128Size(@backingInt(AbbrevCode.block));
1008 const block = debug.blocks.pop().?;
1009
1010 const di_nw = &debug.info_writer;
1011 const di_w = &di_nw.interface;
1012 if (debug.any_children)
1013 try di_w.writeUleb128(@backingInt(AbbrevCode.null))
1014 else
1015 std.leb.writeUnsignedFixed(
1016 block_size,
1017 di_w.buffered()[block.abbrev_code..][0..block_size],
1018 @intCast(try dwarf.refAbbrevCode(di_nw.mf, .empty_block)),
1019 );
1020 std.mem.writeInt(
1021 u32,
1022 di_nw.interface.buffered()[block.high_pc..][0..4],
1023 @intCast(code_off - block.low_pc_off),
1024 dwarf.endian,
1025 );
1026 debug.any_children = true;
1027 }
1028
1029 pub fn enterInlineFunc(
1030 debug: *Debug,
1031 func: InternPool.Index,
1032 code_off: usize,
1033 line: u32,
1034 column: u32,
1035 ) link.Error!void {
1036 return debug.enterInlineFuncInner(func, code_off, line, column) catch |err| switch (err) {
1037 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer),
1038 else => |e| e,
1039 };
1040 }
1041 fn enterInlineFuncInner(
1042 debug: *Debug,
1043 func: InternPool.Index,
1044 code_off: usize,
1045 line: u32,
1046 column: u32,
1047 ) link.EmitError!void {
1048 const dwarf = debug.wip_nav.dwarf;
1049 const zcu = debug.pt.zcu;
1050 const block = try debug.blocks.addOne(zcu.gpa);
1051
1052 const di_nw = &debug.info_writer;
1053 const di_w = &di_nw.interface;
1054 block.abbrev_code = @intCast(di_w.end);
1055 try dwarf.abbrevCode(di_nw, .inlined_func);
1056 try debug.refFunc(func);
1057 try di_w.writeUleb128((if (zcu.comp.config.incremental)
1058 0
1059 else
1060 zcu.navSrcLine(zcu.funcInfo(debug.wip_nav.func).owner_nav) + 1) + line);
1061 try di_w.writeUleb128(column + 1);
1062 block.low_pc_off = code_off;
1063 try dwarf.addrSym(di_nw, debug.wip_nav.func_si, code_off);
1064 block.high_pc = @intCast(di_w.end);
1065 try di_w.writeInt(u32, 0, dwarf.endian);
1066 try debug.setInlineFunc(func);
1067 debug.any_children = false;
1068 }
1069
1070 pub fn leaveInlineFunc(debug: *Debug, func: InternPool.Index, code_off: usize) link.Error!void {
1071 return debug.leaveInlineFuncInner(func, code_off) catch |err| switch (err) {
1072 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.info_writer),
1073 else => |e| e,
1074 };
1075 }
1076 fn leaveInlineFuncInner(
1077 debug: *Debug,
1078 func: InternPool.Index,
1079 code_off: usize,
1080 ) link.EmitError!void {
1081 const dwarf = debug.wip_nav.dwarf;
1082 const inlined_func_size = comptime uleb128Size(@backingInt(AbbrevCode.inlined_func));
1083 const block = debug.blocks.pop().?;
1084
1085 const di_nw = &debug.info_writer;
1086 const di_w = &di_nw.interface;
1087 if (debug.any_children)
1088 try di_w.writeUleb128(@backingInt(AbbrevCode.null))
1089 else
1090 std.leb.writeUnsignedFixed(
1091 inlined_func_size,
1092 di_w.buffered()[block.abbrev_code..][0..inlined_func_size],
1093 @intCast(try dwarf.refAbbrevCode(di_nw.mf, .empty_inlined_func)),
1094 );
1095 std.mem.writeInt(
1096 u32,
1097 di_w.buffered()[block.high_pc..][0..4],
1098 @intCast(code_off - block.low_pc_off),
1099 dwarf.endian,
1100 );
1101 try debug.setInlineFunc(func);
1102 debug.any_children = true;
1103 }
1104
1105 pub fn setInlineFunc(debug: *Debug, func: InternPool.Index) link.Error!void {
1106 return debug.setInlineFuncInner(func) catch |err| switch (err) {
1107 error.WriteFailed => return debug.wip_nav.dwarf.reportWriteError(&debug.line_writer),
1108 else => |e| e,
1109 };
1110 }
1111 fn setInlineFuncInner(debug: *Debug, func: InternPool.Index) link.EmitError!void {
1112 const zcu = debug.pt.zcu;
1113 const ip = &zcu.intern_pool;
1114 const dwarf = debug.wip_nav.dwarf;
1115 if (debug.wip_nav.func == func) return;
1116
1117 const dl_nw = &debug.line_writer;
1118 const dl_w = &dl_nw.interface;
1119 const new_owner_nav = zcu.funcInfo(func).owner_nav;
1120 if (zcu.comp.config.incremental) {
1121 const new_func = try dwarf.getFunc(new_owner_nav);
1122 try dl_w.writeByte(DW.LNS.extended_op);
1123 try dl_w.writeUleb128(1 + dwarf.secOffsetSize());
1124 try dl_w.writeByte(DW.LNE.ZIG_set_decl);
1125 try dwarf.secOffset(dl_nw, new_func.get(dwarf).debug_info_ni.unwrap().?, 0);
1126 return;
1127 }
1128
1129 const old_owner_nav = zcu.funcInfo(debug.wip_nav.func).owner_nav;
1130 const old_inst_info = ip.getNav(old_owner_nav).srcInst(ip).resolveFull(ip).?;
1131 const old_zf = zcu.fileByIndex(old_inst_info.file);
1132 const new_inst_info = ip.getNav(new_owner_nav).srcInst(ip).resolveFull(ip).?;
1133 const new_zf = zcu.fileByIndex(new_inst_info.file);
1134 if (old_inst_info.file != new_inst_info.file) {
1135 const new_ui = dwarf.getUnit(new_zf.mod.?);
1136 _, const new_fi =
1137 try debug.wip_nav.unit.get(dwarf).getFile(zcu.gpa, new_ui, new_inst_info.file);
1138
1139 try dl_w.writeByte(DW.LNS.set_file);
1140 try dl_w.writeUleb128(@backingInt(new_fi));
1141 }
1142
1143 const old_src_line: i33 = old_zf.zir.?.getDeclaration(old_inst_info.inst).src_line;
1144 const new_src_line: i33 = new_zf.zir.?.getDeclaration(new_inst_info.inst).src_line;
1145 if (new_src_line != old_src_line) {
1146 try dl_w.writeByte(DW.LNS.advance_line);
1147 try dl_w.writeSleb128(new_src_line - old_src_line);
1148 }
1149
1150 debug.wip_nav.func = func;
1151 }
1152
1153 fn refFunc(debug: *Debug, func: InternPool.Index) link.EmitError!void {
1154 const dwarf = debug.wip_nav.dwarf;
1155 const fi = try dwarf.getFunc(debug.pt.zcu.funcInfo(func).owner_nav);
1156 try debug.wip_nav.dwarf.secOffset(
1157 &debug.info_writer,
1158 fi.get(dwarf).debug_info_ni.unwrap().?,
1159 0,
1160 );
1161 }
1162 };
1163
1164 pub fn deinit(wip_nav: *WipNav) void {
1165 wip_nav.fde_writer.deinit();
1166 wip_nav.* = undefined;
1167 }
1168
1169 pub fn genDebugFrameHeader(wip_nav: *WipNav) link.Error!void {
1170 wip_nav.genDebugFrameHeaderInner() catch |err| switch (err) {
1171 error.WriteFailed => return wip_nav.dwarf.reportWriteError(&wip_nav.fde_writer),
1172 else => |e| return e,
1173 };
1174 }
1175 fn genDebugFrameHeaderInner(wip_nav: *WipNav) link.EmitError!void {
1176 assert(wip_nav.func != .none);
1177 const dwarf = wip_nav.dwarf;
1178 const df_nw = &wip_nav.fde_writer;
1179 const df_w = &df_nw.interface;
1180 try dwarf.genUnitLength(df_w);
1181 switch (wip_nav.frame_format) {
1182 .eh_frame => {
1183 try df_w.writeInt(u32, undefined, dwarf.endian);
1184 {
1185 const offset = df_w.end;
1186 try df_w.writeInt(u32, 0, dwarf.endian);
1187 if (dwarf.lf.cast(.elf2)) |elf| try elf.addReloc(
1188 @bitCast(df_nw.ni),
1189 offset,
1190 wip_nav.func_si,
1191 0,
1192 .rel32(elf),
1193 ) else unreachable;
1194 }
1195 wip_nav.frame_func_length = .{ .offset = df_w.end, .size = .@"32" };
1196 try df_w.writeInt(u32, undefined, dwarf.endian);
1197 try df_w.writeUleb128(0);
1198 },
1199 .debug_frame => {
1200 try dwarf.secOffset(df_nw, wip_nav.unit.get(dwarf).cie_ni.unwrap().?, 0);
1201 try dwarf.addrSym(df_nw, wip_nav.func_si, 0);
1202 wip_nav.frame_func_length = .{ .offset = df_w.end, .size = dwarf.address_size };
1203 try dwarf.addrPlaceholder(df_w);
1204 },
1205 }
1206 }
1207
1208 pub fn genDebugFrame(wip_nav: *WipNav, loc: u32, cfa: Cfa) link.Error!void {
1209 return wip_nav.genDebugFrameInner(loc, cfa) catch |err| switch (err) {
1210 error.WriteFailed => return wip_nav.dwarf.reportWriteError(&wip_nav.fde_writer),
1211 else => |e| return e,
1212 };
1213 }
1214 fn genDebugFrameInner(wip_nav: *WipNav, loc: u32, cfa: Cfa) link.EmitError!void {
1215 assert(wip_nav.func != .none);
1216 const loc_cfa: Cfa = .{ .advance_loc = loc };
1217 try loc_cfa.write(wip_nav);
1218 try cfa.write(wip_nav);
1219 }
1220
1221 pub fn finishDebugFrameFde(wip_nav: *WipNav, func_length: u64) void {
1222 const dwarf = wip_nav.dwarf;
1223 const df_w = &wip_nav.fde_writer.interface;
1224 switch (wip_nav.frame_func_length.size) {
1225 _ => unreachable,
1226 .@"32" => std.mem.writeInt(
1227 u32,
1228 df_w.buffered()[wip_nav.frame_func_length.offset..][0..4],
1229 @intCast(func_length),
1230 dwarf.endian,
1231 ),
1232 .@"64" => std.mem.writeInt(
1233 u64,
1234 df_w.buffered()[wip_nav.frame_func_length.offset..][0..8],
1235 func_length,
1236 dwarf.endian,
1237 ),
1238 }
1239 @memset(df_w.unusedCapacitySlice(), DW.CFA.nop);
1240 }
1241};
1242
1243pub fn init(lf: *link.File, format: DW.Format) Dwarf {
1244 const target = &lf.comp.root_mod.resolved_target.result;
1245 return .{
1246 .lf = lf,
1247 .format = format,
1248 .address_size = switch (target.ptrBitWidth()) {
1249 0...32 => .@"32",
1250 33...64 => .@"64",
1251 else => unreachable,
1252 },
1253 .endian = target.cpu.arch.endian(),
1254 .const_pool = .empty,
1255
1256 .units = &.{},
1257 .consts = .empty,
1258 .globals = .empty,
1259 .funcs = .empty,
1260 .decls = .empty,
1261 .pending_decl = .{ .di = undefined, .instance_val = .none },
1262
1263 .debug_abbrev = .{
1264 .ni = .none,
1265 .end = 0,
1266 .set = .empty,
1267 },
1268 .frame = .{
1269 .header = if (target.cpu.arch == .x86_64 and target.ofmt == .elf) header: {
1270 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1271 const Register = @import("../codegen/x86_64/bits.zig").Register;
1272 break :header comptime .{
1273 .code_alignment_factor = 1,
1274 .data_alignment_factor = -8,
1275 .return_address_register = Register.rip.dwarfNum(),
1276 .initial_instructions = &.{
1277 .{ .def_cfa = .{ .reg = Register.rsp.dwarfNum(), .off = 8 } },
1278 .{ .offset = .{ .reg = Register.rip.dwarfNum(), .off = -8 } },
1279 },
1280 };
1281 } else .{
1282 .code_alignment_factor = undefined,
1283 .data_alignment_factor = undefined,
1284 .return_address_register = undefined,
1285 .initial_instructions = &.{},
1286 },
1287 },
1288 .debug_info = .{},
1289 .debug_line = .{
1290 .header = switch (target.cpu.arch) {
1291 .x86_64, .aarch64 => .{
1292 .minimum_instruction_length = 1,
1293 .maximum_operations_per_instruction = 1,
1294 .default_is_stmt = true,
1295 .line_base = -5,
1296 .line_range = 14,
1297 .opcode_base = DW.LNS.set_isa + 1,
1298 },
1299 else => .{
1300 .minimum_instruction_length = 1,
1301 .maximum_operations_per_instruction = 1,
1302 .default_is_stmt = true,
1303 .line_base = 0,
1304 .line_range = 1,
1305 .opcode_base = DW.LNS.set_isa + 1,
1306 },
1307 },
1308 },
1309 .debug_line_str = .{
1310 .ni = .none,
1311 .offset = 0,
1312 .map = .empty,
1313 },
1314 .debug_rnglists = .{},
1315 .debug_str = .{
1316 .ni = .none,
1317 .offset = 0,
1318 .map = .empty,
1319 },
1320 .debug_str_offsets = .{
1321 .ni = .none,
1322 .offset = 0,
1323 },
1324 };
1325}
1326
1327pub fn deinit(dwarf: *Dwarf) void {
1328 const gpa = dwarf.lf.comp.gpa;
1329 dwarf.const_pool.deinit(gpa);
1330 for (dwarf.units) |*unit| unit.deinit(gpa);
1331 gpa.free(dwarf.units);
1332 dwarf.consts.deinit(gpa);
1333 dwarf.globals.deinit(gpa);
1334 dwarf.funcs.deinit(gpa);
1335 dwarf.decls.deinit(gpa);
1336 dwarf.debug_line_str.map.deinit(gpa);
1337 dwarf.debug_str.map.deinit(gpa);
1338 dwarf.* = undefined;
1339}
1340
1341pub fn initUnits(dwarf: *Dwarf, gpa: std.mem.Allocator, units_len: usize) std.mem.Allocator.Error!void {
1342 assert(dwarf.units.len == 0);
1343 dwarf.units = try gpa.alloc(Unit, units_len);
1344 @memset(dwarf.units, .{
1345 .alive = false,
1346 .dirs = .empty,
1347 .files = .empty,
1348 .frame_ni = .none,
1349 .cie_ni = .none,
1350 .debug_info_ni = .none,
1351 .debug_info_header_ni = .none,
1352 .debug_info_footer_ni = .none,
1353 .debug_line_ni = .none,
1354 .debug_line_header_ni = .none,
1355 .debug_line_header_changed = false,
1356 .debug_rnglists_ni = .none,
1357 .debug_rnglists_offsets_table_offset = undefined,
1358 .debug_rnglists_end = undefined,
1359 });
1360}
1361pub fn updateUnits(dwarf: *Dwarf, zcu: *Zcu) std.mem.Allocator.Error!bool {
1362 var units_changed = false;
1363 for (zcu.module_roots.values(), dwarf.units, 0..) |root, *unit, ui| {
1364 const root_zfi = root.unwrap() orelse continue; // non-zig
1365 const alive = zcu.alive_files.contains(root_zfi);
1366 if (unit.alive == alive) continue; // unchanged
1367 unit.alive = alive;
1368 units_changed = true;
1369 if (!alive) continue; // unreferenced
1370 assert(zcu.fileByIndex(root_zfi).mod != null);
1371 const root_di, const root_fi = try unit.getFile(
1372 zcu.gpa,
1373 @fromBackingInt(@intCast(ui)),
1374 root_zfi,
1375 );
1376 assert(root_di == .root and root_fi == .root);
1377 }
1378 return units_changed;
1379}
1380
1381pub fn getUnit(dwarf: *Dwarf, mod: *Module) Unit.Index {
1382 return @fromBackingInt(@intCast(dwarf.lf.comp.zcu.?.module_roots.getIndex(mod).?));
1383}
1384
1385pub fn getConst(dwarf: *Dwarf, pt: Zcu.PerThread, val: Value) link.Error!link.ConstPool.Index {
1386 assert(val.typeOf(pt.zcu).comptimeOnly(pt.zcu));
1387 return dwarf.const_pool.get(pt, dwarf.constPoolUser(), val.toIntern());
1388}
1389
1390pub fn getGlobal(dwarf: *Dwarf, nav: InternPool.Nav.Index) link.Error!Global.Index {
1391 const comp = dwarf.lf.comp;
1392 const gpa = comp.gpa;
1393 const global_gop = try dwarf.globals.getOrPut(gpa, nav);
1394 if (!global_gop.found_existing) global_gop.value_ptr.* = .{
1395 .debug_info_ni = .none,
1396 };
1397 const gi: Global.Index = @fromBackingInt(@intCast(global_gop.index));
1398 if (global_gop.value_ptr.debug_info_ni != .none) return gi;
1399 const mod = comp.zcu.?.navFileScope(nav).mod.?;
1400 assert(!mod.strip);
1401 const elf = dwarf.lf.cast(.elf2).?;
1402 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1403 try elf.dwarf_globals.append(gpa, .{
1404 .debug_info_first_target_reloc = .none,
1405 .debug_info_first_node_reloc = .none,
1406 .debug_info_first_symbol_reloc = .none,
1407 });
1408 const unit = dwarf.getUnit(mod).get(dwarf);
1409 global_gop.value_ptr.debug_info_ni = .wrap(elf.addNodeAssumeCapacity(
1410 unit.debug_info_ni.unwrap().?.addFloatingChild(gpa, &elf.mf, .{
1411 .enable_next_moved = true,
1412 }) catch |err| switch (err) {
1413 else => |e| return e,
1414 error.MappedFileIo => return comp.link_diags.fail("failed to write output file: {t}", .{
1415 elf.mf.io_err.?,
1416 }),
1417 },
1418 .{ .global_debug_info = gi },
1419 ));
1420 return gi;
1421}
1422pub fn getGlobalIfExists(dwarf: *Dwarf, nav: InternPool.Nav.Index) ?Global.Index {
1423 return @fromBackingInt(@intCast(dwarf.globals.getIndex(nav) orelse return null));
1424}
1425
1426pub fn getFunc(dwarf: *Dwarf, nav: InternPool.Nav.Index) link.Error!Func.Index {
1427 const comp = dwarf.lf.comp;
1428 const gpa = comp.gpa;
1429 const func_gop = try dwarf.funcs.getOrPut(gpa, nav);
1430 if (!func_gop.found_existing) func_gop.value_ptr.* = .{
1431 .state = .unresolved,
1432 .fde_ni = .none,
1433 .debug_info_ni = .none,
1434 .debug_line_ni = .none,
1435 };
1436 const fi: Func.Index = @fromBackingInt(@intCast(func_gop.index));
1437 if (func_gop.value_ptr.debug_info_ni != .none) return fi;
1438 const mod = comp.zcu.?.navFileScope(nav).mod.?;
1439 const elf = dwarf.lf.cast(.elf2).?;
1440 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1441 try elf.dwarf_funcs.append(gpa, .{
1442 .frame_fde_first_symbol_reloc = .none,
1443 .frame_fde_first_node_reloc = .none,
1444 .debug_info_first_target_reloc = .none,
1445 .debug_info_first_symbol_reloc = .none,
1446 .debug_info_first_node_reloc = .none,
1447 .debug_line_first_symbol_reloc = .none,
1448 .debug_line_first_node_reloc = .none,
1449 });
1450 if (mod.strip) return fi;
1451 const unit = dwarf.getUnit(mod).get(dwarf);
1452 func_gop.value_ptr.debug_info_ni = .wrap(elf.addNodeAssumeCapacity(
1453 unit.debug_info_ni.unwrap().?.addFloatingChild(gpa, &elf.mf, .{
1454 .enable_next_moved = true,
1455 }) catch |err| switch (err) {
1456 else => |e| return e,
1457 error.MappedFileIo => return comp.link_diags.fail("failed to write output file: {t}", .{
1458 elf.mf.io_err.?,
1459 }),
1460 },
1461 .{ .func_debug_info = fi },
1462 ));
1463 return fi;
1464}
1465pub fn getFuncIfExists(dwarf: *Dwarf, nav: InternPool.Nav.Index) ?Func.Index {
1466 return @fromBackingInt(@intCast(dwarf.funcs.getIndex(nav) orelse return null));
1467}
1468
1469fn getDeclInst(dwarf: *Dwarf, val: InternPool.Index) ?InternPool.TrackedInst.Index {
1470 const ip = &dwarf.lf.comp.zcu.?.intern_pool;
1471 switch (ip.indexToKey(val)) {
1472 else => unreachable,
1473 .struct_type, .union_type, .enum_type, .opaque_type => |container, tag| switch (container) {
1474 .declared => |declared| switch (declared.captures.owned.len) {
1475 0 => return null,
1476 else => switch (tag) {
1477 else => unreachable,
1478 .struct_type => {
1479 const loaded_struct = ip.loadStructType(val);
1480 return ip.getNav(loaded_struct.name_nav.unwrap() orelse
1481 return loaded_struct.zir_index).srcInst(ip);
1482 },
1483 .union_type => {
1484 const loaded_union = ip.loadUnionType(val);
1485 return ip.getNav(loaded_union.name_nav.unwrap() orelse
1486 return loaded_union.zir_index).srcInst(ip);
1487 },
1488 .enum_type => {
1489 const loaded_enum = ip.loadEnumType(val);
1490 return ip.getNav(loaded_enum.name_nav.unwrap() orelse
1491 return loaded_enum.zir_index.unwrap().?).srcInst(ip);
1492 },
1493 .opaque_type => {
1494 const loaded_opaque = ip.loadOpaqueType(val);
1495 return ip.getNav(loaded_opaque.name_nav.unwrap() orelse
1496 return loaded_opaque.zir_index).srcInst(ip);
1497 },
1498 },
1499 },
1500 .reified => |reified| {
1501 assert(reified.zir_index.resolve(ip).? != .main_struct_inst);
1502 return reified.zir_index;
1503 },
1504 .generated_union_tag => unreachable,
1505 },
1506 .func => |func| return ip.getNav(switch (func.generic_owner) {
1507 .none => func.owner_nav,
1508 else => |generic_owner| ip.indexToKey(generic_owner).func.owner_nav,
1509 }).srcInst(ip),
1510 }
1511}
1512pub fn getDecl(
1513 dwarf: *Dwarf,
1514 pt: Zcu.PerThread,
1515 instance_val: InternPool.Index,
1516) link.Error!link.MappedFile.Node.Index {
1517 assert(dwarf.pending_decl.instance_val == .none);
1518 const comp = dwarf.lf.comp;
1519 const gpa = comp.gpa;
1520 const zcu = pt.zcu;
1521 const ip = &zcu.intern_pool;
1522 const inst = dwarf.getDeclInst(instance_val) orelse {
1523 const cpi = try dwarf.getConst(pt, .fromInterned(instance_val));
1524 return Const.get(cpi, dwarf).debug_info_ni.unwrap().?;
1525 };
1526 const decl_gop = try dwarf.decls.getOrPut(gpa, inst);
1527 if (!decl_gop.found_existing) decl_gop.value_ptr.* = .{
1528 .debug_info_ni = .none,
1529 };
1530 const di: Decl.Index = @fromBackingInt(@intCast(decl_gop.index));
1531 if (decl_gop.value_ptr.debug_info_ni.unwrap()) |debug_info_ni| return debug_info_ni;
1532 dwarf.pending_decl = .{ .di = di, .instance_val = instance_val };
1533 const elf = dwarf.lf.cast(.elf2).?;
1534 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1535 try elf.dwarf_decls.putNoClobber(gpa, di, .{
1536 .debug_info_first_target_reloc = .none,
1537 .debug_info_first_node_reloc = .none,
1538 });
1539 const unit = dwarf.getUnit(zcu.fileByIndex(di.srcInst(dwarf).resolveFile(ip)).mod.?).get(dwarf);
1540 const debug_info_ni = elf.addNodeAssumeCapacity(
1541 unit.debug_info_ni.unwrap().?.addFloatingChild(gpa, &elf.mf, .{
1542 .enable_next_moved = true,
1543 }) catch |err| switch (err) {
1544 else => |e| return e,
1545 error.MappedFileIo => return comp.link_diags.fail("failed to write output file: {t}", .{
1546 elf.mf.io_err.?,
1547 }),
1548 },
1549 .{ .decl_debug_info = di },
1550 );
1551 decl_gop.value_ptr.debug_info_ni = .wrap(debug_info_ni);
1552 return debug_info_ni;
1553}
1554pub fn getDeclIfExists(dwarf: *Dwarf, inst: InternPool.TrackedInst.Index) ?Decl.Index {
1555 return @fromBackingInt(@intCast(dwarf.decls.getIndex(inst) orelse return null));
1556}
1557
1558pub fn unitLengthSize(dwarf: *Dwarf) usize {
1559 return switch (dwarf.format) {
1560 .@"32" => 4,
1561 .@"64" => 4 + 8,
1562 };
1563}
1564pub fn genUnitLength(dwarf: *Dwarf, w: *std.Io.Writer) std.Io.Writer.Error!void {
1565 switch (dwarf.format) {
1566 .@"32" => try w.writeInt(u32, undefined, dwarf.endian),
1567 .@"64" => {
1568 try w.writeInt(u32, std.math.maxInt(u32), dwarf.endian);
1569 try w.writeInt(u64, undefined, dwarf.endian);
1570 },
1571 }
1572}
1573pub fn updateUnitLength(dwarf: *Dwarf, header: []u8, unit_length: u64) void {
1574 switch (dwarf.format) {
1575 .@"32" => std.mem.writeInt(u32, header[0..4], @intCast(unit_length - 4), dwarf.endian),
1576 .@"64" => std.mem.writeInt(u64, header[4..12], unit_length - 12, dwarf.endian),
1577 }
1578}
1579
1580pub fn genUnitPadding(dwarf: *Dwarf, w: *std.Io.Writer) std.Io.Writer.Error!void {
1581 try dwarf.genUnitLength(w);
1582 try w.writeInt(u16, 0, dwarf.endian);
1583}
1584
1585pub const EhFrameHdr = extern struct {
1586 version: u8,
1587 eh_frame_ptr_enc: std.dwarf.EH.PE,
1588 fde_count_enc: std.dwarf.EH.PE,
1589 table_enc: std.dwarf.EH.PE,
1590 eh_frame_ptr: u32,
1591};
1592pub fn genEhFrameHdr(
1593 dwarf: *Dwarf,
1594 eh_frame_hdr_ai: link.File.AtomId,
1595 eh_frame_hdr: *EhFrameHdr,
1596 eh_frame_si: link.File.SymbolId,
1597) link.Error!void {
1598 eh_frame_hdr.* = .{
1599 .version = 1,
1600 .eh_frame_ptr_enc = .{ .type = .sdata4, .rel = .pcrel },
1601 .fde_count_enc = .omit,
1602 .table_enc = .omit,
1603 .eh_frame_ptr = undefined,
1604 };
1605 if (dwarf.lf.cast(.elf2)) |elf| try elf.addReloc(
1606 eh_frame_hdr_ai,
1607 @offsetOf(EhFrameHdr, "eh_frame_ptr"),
1608 eh_frame_si,
1609 0,
1610 .rel32(elf),
1611 ) else unreachable;
1612}
1613
1614pub fn genDebugFrameCie(
1615 dwarf: *Dwarf,
1616 df_w: *std.Io.Writer,
1617 /// `null` means to generate an architecture-agnostic padding cie
1618 arch: ?std.Target.Cpu.Arch,
1619 format: Frame.Format,
1620) std.Io.Writer.Error!void {
1621 try dwarf.genUnitLength(df_w);
1622 switch (format) {
1623 .eh_frame => try df_w.writeInt(u32, 0, dwarf.endian),
1624 .debug_frame => switch (dwarf.format) {
1625 .@"32" => try df_w.writeInt(u32, std.math.maxInt(u32), dwarf.endian),
1626 .@"64" => try df_w.writeInt(u64, std.math.maxInt(u64), dwarf.endian),
1627 },
1628 }
1629 try df_w.writeByte(if (arch) |_| switch (format) {
1630 .eh_frame => 1,
1631 .debug_frame => 4,
1632 } else 0);
1633 switch (arch orelse return) {
1634 else => unreachable,
1635 .x86_64 => {
1636 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1637 const Register = @import("../codegen/x86_64/bits.zig").Register;
1638 switch (format) {
1639 .eh_frame => try df_w.writeAll("zR\x00"),
1640 .debug_frame => {
1641 try df_w.writeAll("\x00");
1642 try df_w.writeByte(@backingInt(dwarf.address_size));
1643 try df_w.writeByte(0);
1644 },
1645 }
1646 try df_w.writeUleb128(dwarf.frame.header.code_alignment_factor);
1647 try df_w.writeSleb128(dwarf.frame.header.data_alignment_factor);
1648 switch (format) {
1649 .eh_frame => try df_w.writeByte(@intCast(dwarf.frame.header.return_address_register)),
1650 .debug_frame => try df_w.writeUleb128(dwarf.frame.header.return_address_register),
1651 }
1652 switch (format) {
1653 .eh_frame => {
1654 try df_w.writeUleb128(1);
1655 try df_w.writeByte(@bitCast(@as(DW.EH.PE, .{ .type = .sdata4, .rel = .pcrel })));
1656 },
1657 .debug_frame => {},
1658 }
1659 try df_w.writeByte(DW.CFA.def_cfa_sf);
1660 try df_w.writeUleb128(Register.rsp.dwarfNum());
1661 try df_w.writeSleb128(-1);
1662 try df_w.writeByte(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum());
1663 try df_w.writeUleb128(1);
1664 },
1665 }
1666 @memset(df_w.unusedCapacitySlice(), DW.CFA.nop);
1667}
1668
1669pub fn updateEhFrameFde(dwarf: *Dwarf, fde: []u8, fde_offset: u64) void {
1670 const cie_pointer_offset = dwarf.unitLengthSize();
1671 std.mem.writeInt(
1672 u32,
1673 fde[cie_pointer_offset..][0..4],
1674 @intCast(fde_offset + cie_pointer_offset),
1675 dwarf.endian,
1676 );
1677}
1678
1679pub fn genDebugInfoHeader(
1680 dwarf: *Dwarf,
1681 zcu: *Zcu,
1682 mod: *Module,
1683 unit: *Unit,
1684 dih_nw: *link.MappedFile.Node.Writer,
1685) link.EmitError!void {
1686 const comp = zcu.comp;
1687 const dih_w = &dih_nw.interface;
1688 if (!unit.alive) return dwarf.genUnitPadding(dih_w);
1689 try dwarf.genUnitLength(dih_w);
1690 try dih_w.writeInt(u16, 5, dwarf.endian);
1691 try dih_w.writeByte(DW.UT.compile);
1692 try dih_w.writeByte(@backingInt(dwarf.address_size));
1693 try dwarf.secOffset(dih_nw, dwarf.debug_abbrev.ni.unwrap().?, 0);
1694 const compile_unit_offset = dih_w.end;
1695 try dwarf.abbrevCode(dih_nw, .compile_unit);
1696 try dih_w.writeByte(DW.LANG.Zig);
1697 try dwarf.strp(&dwarf.debug_str, dih_nw, "zig " ++ @import("build_options").version);
1698 const root_dir_path = try mod.root.toAbsolute(&comp.dirs, comp.gpa);
1699 defer comp.gpa.free(root_dir_path);
1700 try dwarf.strp(&dwarf.debug_line_str, dih_nw, root_dir_path);
1701 try dwarf.strp(&dwarf.debug_line_str, dih_nw, mod.root_src_path);
1702 try dwarf.secOffset(
1703 dih_nw,
1704 dwarf.getUnit(zcu.root_mod).get(dwarf).debug_info_header_ni.unwrap().?,
1705 compile_unit_offset,
1706 );
1707 try dwarf.secOffset(dih_nw, unit.debug_line_header_ni.unwrap().?, 0);
1708 try dwarf.secOffset(dih_nw, unit.debug_rnglists_ni.unwrap().?, Rnglists.offsetsTableOffset(dwarf));
1709 try dih_w.writeUleb128(0);
1710 const module_offset = dih_w.end;
1711 try dwarf.abbrevCode(dih_nw, .module);
1712 try dwarf.strp(&dwarf.debug_str, dih_nw, mod.fully_qualified_name);
1713 try dih_w.writeUleb128(0);
1714 try dwarf.genModuleDependency(
1715 dih_nw,
1716 "builtin",
1717 zcu.builtin_modules.get(mod.getBuiltinOptions(comp.config).hash()).?,
1718 module_offset,
1719 );
1720 try dwarf.genModuleDependency(dih_nw, "root", zcu.root_mod, module_offset);
1721 try dwarf.genModuleDependency(dih_nw, "std", zcu.std_mod, module_offset);
1722 for (mod.deps.keys(), mod.deps.values()) |name, dep|
1723 try dwarf.genModuleDependency(dih_nw, name, dep, module_offset);
1724 for ([2]AbbrevCode{ .pad_1, .pad_n }) |pad| _ = try dwarf.refAbbrevCode(dih_nw.mf, pad);
1725 try dwarf.genDebugInfoPadding(dih_w, dih_w.unusedCapacityLen());
1726}
1727
1728fn genModuleDependency(
1729 dwarf: *Dwarf,
1730 di_nw: *link.MappedFile.Node.Writer,
1731 name: []const u8,
1732 dep: *Module,
1733 module_offset: usize,
1734) link.EmitError!void {
1735 const dep_unit = dwarf.getUnit(dep).get(dwarf);
1736 if (!dep_unit.alive) return;
1737 try dwarf.abbrevCode(di_nw, .module_dependency);
1738 try dwarf.strp(&dwarf.debug_str, di_nw, name);
1739 try dwarf.secOffset(di_nw, dep_unit.debug_info_header_ni.unwrap().?, module_offset);
1740}
1741
1742pub fn genDebugInfoPadding(dwarf: *Dwarf, di_w: *std.Io.Writer, size: u64) std.Io.Writer.Error!void {
1743 switch (size) {
1744 0 => {},
1745 1 => try di_w.writeUleb128(dwarf.refAbbrevCodeIfExists(.pad_1).?),
1746 else => {
1747 const abbrev_code_offset = di_w.end;
1748 try di_w.writeUleb128(dwarf.refAbbrevCodeIfExists(.pad_n).?);
1749 const abbrev_code_size = di_w.end - abbrev_code_offset;
1750 var block_len_size: u5 = 1;
1751 while (true) switch (std.math.order(
1752 size - abbrev_code_size - block_len_size,
1753 @as(u64, 1) << 7 * block_len_size,
1754 )) {
1755 .lt => break try di_w.writeUleb128(size - abbrev_code_size - block_len_size),
1756 .eq => {
1757 // no length will ever work, so undercount and futz with
1758 // the leb encoding to make up the missing byte
1759 block_len_size += 1;
1760 std.leb.writeUnsignedExtended(
1761 try di_w.writableSlice(block_len_size),
1762 size - abbrev_code_size - block_len_size,
1763 );
1764 break;
1765 },
1766 .gt => block_len_size += 1,
1767 };
1768 },
1769 }
1770}
1771
1772pub fn genDebugLineHeader(
1773 dwarf: *Dwarf,
1774 unit: *Unit,
1775 dlh_nw: *link.MappedFile.Node.Writer,
1776 zcu: *Zcu,
1777) link.EmitError!void {
1778 const comp = zcu.comp;
1779 const dlh_w = &dlh_nw.interface;
1780 try dwarf.genUnitLength(dlh_w);
1781 try dlh_w.writeInt(u16, 5, dwarf.endian);
1782 try dlh_w.writeByte(@backingInt(dwarf.address_size));
1783 try dlh_w.writeByte(0);
1784 const header_length_offset = dlh_w.end;
1785 switch (dwarf.format) {
1786 .@"32" => try dlh_w.writeInt(u32, undefined, dwarf.endian),
1787 .@"64" => try dlh_w.writeInt(u64, undefined, dwarf.endian),
1788 }
1789 const header_start = dlh_w.end;
1790 const StandardOpcode = DeclValEnum(DW.LNS);
1791 try dlh_w.writeAll(&.{
1792 dwarf.debug_line.header.minimum_instruction_length,
1793 dwarf.debug_line.header.maximum_operations_per_instruction,
1794 @intFromBool(dwarf.debug_line.header.default_is_stmt),
1795 @bitCast(dwarf.debug_line.header.line_base),
1796 dwarf.debug_line.header.line_range,
1797 dwarf.debug_line.header.opcode_base,
1798 });
1799 try dlh_w.writeAll(std.enums.EnumArray(StandardOpcode, u8).init(.{
1800 .extended_op = undefined,
1801 .copy = 0,
1802 .advance_pc = 1,
1803 .advance_line = 1,
1804 .set_file = 1,
1805 .set_column = 1,
1806 .negate_stmt = 0,
1807 .set_basic_block = 0,
1808 .const_add_pc = 0,
1809 .fixed_advance_pc = 1,
1810 .set_prologue_end = 0,
1811 .set_epilogue_begin = 0,
1812 .set_isa = 1,
1813 }).values[1..dwarf.debug_line.header.opcode_base]);
1814 try dlh_w.writeByte(1);
1815 try dlh_w.writeUleb128(DW.LNCT.path);
1816 try dlh_w.writeUleb128(DW.FORM.line_strp);
1817 const dir_count = unit.dirs.count();
1818 const directory_index_form: DeclValEnum(DW.FORM) = if (dir_count <= 1 << 8)
1819 .data1
1820 else if (dir_count <= 1 << 16)
1821 .data2
1822 else
1823 .udata;
1824 try dlh_w.writeUleb128(dir_count);
1825 for (unit.dirs.keys()) |ui| {
1826 const root_dir_path = try ui.mod(dwarf).root.toAbsolute(&zcu.comp.dirs, comp.gpa);
1827 defer comp.gpa.free(root_dir_path);
1828 try dwarf.strp(&dwarf.debug_line_str, dlh_nw, root_dir_path);
1829 }
1830 try dlh_w.writeByte(5);
1831 try dlh_w.writeUleb128(DW.LNCT.path);
1832 try dlh_w.writeUleb128(DW.FORM.line_strp);
1833 try dlh_w.writeUleb128(DW.LNCT.directory_index);
1834 try dlh_w.writeUleb128(@backingInt(directory_index_form));
1835 try dlh_w.writeUleb128(DW.LNCT.timestamp);
1836 try dlh_w.writeUleb128(DW.FORM.data8);
1837 try dlh_w.writeUleb128(DW.LNCT.size);
1838 try dlh_w.writeUleb128(DW.FORM.data8);
1839 try dlh_w.writeUleb128(DW.LNCT.LLVM_source);
1840 try dlh_w.writeUleb128(DW.FORM.line_strp);
1841 try dlh_w.writeUleb128(unit.files.count());
1842 for (unit.files.keys()) |zfi| {
1843 const zf = zcu.fileByIndex(zfi);
1844 try dwarf.strp(&dwarf.debug_line_str, dlh_nw, zf.sub_file_path);
1845 const di =
1846 if (zcu.alive_files.contains(zfi)) unit.dirs.getIndex(dwarf.getUnit(zf.mod.?)).? else 0;
1847 switch (directory_index_form) {
1848 else => unreachable,
1849 .data1 => try dlh_w.writeByte(@intCast(di)),
1850 .data2 => try dlh_w.writeInt(u16, @intCast(di), dwarf.endian),
1851 .udata => try dlh_w.writeUleb128(di),
1852 }
1853 try dlh_w.writeInt(i64, @truncate(zf.stat.mtime.nanoseconds), dwarf.endian);
1854 try dlh_w.writeInt(u64, zf.stat.size, dwarf.endian);
1855 try dwarf.strp(
1856 &dwarf.debug_line_str,
1857 dlh_nw,
1858 if (zf.is_builtin) zf.source.? else "",
1859 );
1860 }
1861 switch (dwarf.format) {
1862 .@"32" => std.mem.writeInt(
1863 u32,
1864 dlh_w.buffer[header_length_offset..][0..4],
1865 @intCast(dlh_w.end - header_start),
1866 dwarf.endian,
1867 ),
1868 .@"64" => std.mem.writeInt(
1869 u64,
1870 dlh_w.buffer[header_length_offset..][0..8],
1871 dlh_w.end - header_start,
1872 dwarf.endian,
1873 ),
1874 }
1875 try genDebugLinePadding(dlh_w, dlh_w.unusedCapacityLen());
1876}
1877
1878pub fn genDebugLinePadding(dl_w: *std.Io.Writer, size: u64) std.Io.Writer.Error!void {
1879 switch (size) {
1880 0 => {},
1881 1 => try dl_w.writeByte(DW.LNS.const_add_pc),
1882 2 => try dl_w.writeAll(&.{ DW.LNS.negate_stmt, DW.LNS.negate_stmt }),
1883 else => {
1884 const extended_op_offset = dl_w.end;
1885 try dl_w.writeByte(DW.LNS.extended_op);
1886 const extended_op_size = dl_w.end - extended_op_offset;
1887 var op_len_size: u5 = 1;
1888 while (true) switch (std.math.order(
1889 size - extended_op_size - op_len_size,
1890 @as(u64, 1) << 7 * op_len_size,
1891 )) {
1892 .lt => break try dl_w.writeUleb128(size - extended_op_size - op_len_size),
1893 .eq => {
1894 // no length will ever work, so undercount and futz with
1895 // the leb encoding to make up the missing byte
1896 op_len_size += 1;
1897 std.leb.writeUnsignedExtended(
1898 try dl_w.writableSlice(op_len_size),
1899 size - extended_op_size - op_len_size,
1900 );
1901 break;
1902 },
1903 .gt => op_len_size += 1,
1904 };
1905 try dl_w.writeByte(DW.LNE.padding);
1906 },
1907 }
1908}
1909
1910pub fn genDebugRnglistsHeader(
1911 dwarf: *Dwarf,
1912 unit: *Unit,
1913 drh_nw: *link.MappedFile.Node.Writer,
1914) std.Io.Writer.Error!void {
1915 const drh_w = &drh_nw.interface;
1916 try dwarf.genUnitLength(drh_w);
1917 try drh_w.writeInt(u16, 5, dwarf.endian);
1918 try drh_w.writeByte(@backingInt(dwarf.address_size));
1919 try drh_w.writeByte(0);
1920 try drh_w.writeInt(u32, 1, dwarf.endian);
1921 assert(drh_w.end == Rnglists.offsetsTableOffset(dwarf));
1922 switch (dwarf.format) {
1923 .@"32" => try drh_w.writeInt(u32, 4, dwarf.endian),
1924 .@"64" => try drh_w.writeInt(u64, 8, dwarf.endian),
1925 }
1926 unit.debug_rnglists_end = drh_w.end;
1927 try drh_w.writeByte(DW.RLE.end_of_list);
1928}
1929
1930pub fn genDebugRnglists(
1931 dwarf: *Dwarf,
1932 unit: *Unit,
1933 dr_nw: *link.MappedFile.Node.Writer,
1934 func_si: link.File.SymbolId,
1935 func_length: u64,
1936) link.EmitError!void {
1937 const dr_w = &dr_nw.interface;
1938 dr_w.end = unit.debug_rnglists_end;
1939 try dr_w.writeByte(DW.RLE.start_length);
1940 try dwarf.addrSym(dr_nw, func_si, 0);
1941 try dr_w.writeUleb128(func_length);
1942 unit.debug_rnglists_end = dr_w.end;
1943 try dr_w.writeByte(DW.RLE.end_of_list);
1944}
1945
1946pub fn updateComptimeNav(
1947 dwarf: *Dwarf,
1948 pt: Zcu.PerThread,
1949 nav_index: InternPool.Nav.Index,
1950) link.Error!void {
1951 const zcu = pt.zcu;
1952 const ip = &zcu.intern_pool;
1953 const nav = ip.getNav(nav_index);
1954 log.debug("updateComptimeNav({f})", .{nav.fqn.fmt(ip)});
1955 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
1956 const nav_val: Value = .fromInterned(nav.resolved.?.value);
1957 const zf = zcu.fileByIndex(inst_info.file);
1958 const decl = zf.zir.?.getDeclaration(inst_info.inst);
1959 switch (decl.kind) {
1960 .unnamed_test, .@"test", .decltest => return,
1961 .@"comptime", .@"const", .@"var" => {},
1962 }
1963 done: switch (ip.indexToKey(nav_val.toIntern())) {
1964 .struct_type => {
1965 const loaded_struct = ip.loadStructType(nav_val.toIntern());
1966 if (nav_index.toOptional() == loaded_struct.name_nav) {
1967 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
1968 break :done;
1969 }
1970 return;
1971 },
1972 .enum_type => {
1973 const loaded_enum = ip.loadEnumType(nav_val.toIntern());
1974 if (nav_index.toOptional() == loaded_enum.name_nav) {
1975 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
1976 break :done;
1977 }
1978 return;
1979 },
1980 .union_type => {
1981 const loaded_union = ip.loadUnionType(nav_val.toIntern());
1982 if (nav_index.toOptional() == loaded_union.name_nav) {
1983 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
1984 break :done;
1985 }
1986 return;
1987 },
1988 .opaque_type => {
1989 const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
1990 if (nav_index.toOptional() == loaded_opaque.name_nav) {
1991 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
1992 break :done;
1993 }
1994 return;
1995 },
1996 .func => |func| if (func.owner_nav == nav_index and func.generic_owner == .none) {
1997 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
1998 break :done;
1999 } else return,
2000
2001 else => return,
2002
2003 // memoization, not values
2004 .memoized_call => unreachable,
2005 }
2006 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
2007}
2008
2009pub fn addConst(
2010 dwarf: *Dwarf,
2011 cpi: link.ConstPool.Index,
2012 val: InternPool.Index,
2013 addConstNode: *const fn (
2014 lf: *link.File,
2015 ui: Unit.Index,
2016 cpi: link.ConstPool.Index,
2017 ) link.Error!link.MappedFile.Node.Index,
2018) link.Error!void {
2019 const zcu = dwarf.lf.comp.zcu.?;
2020 const ip = &zcu.intern_pool;
2021 assert(@backingInt(cpi) == dwarf.consts.items.len);
2022 dwarf.consts.appendAssumeCapacity(.{
2023 .debug_info_ni = debug_info_ni: switch (ip.indexToKey(val)) {
2024 else => try addConstNode(dwarf.lf, dwarf.getUnit(zcu.root_mod), cpi),
2025 .func => |func| {
2026 const fi = try dwarf.getFunc(func.owner_nav);
2027 break :debug_info_ni fi.get(dwarf).debug_info_ni.unwrap().?;
2028 },
2029 .@"extern" => |@"extern"| {
2030 const gi = try dwarf.getGlobal(@"extern".owner_nav);
2031 break :debug_info_ni gi.get(dwarf).debug_info_ni.unwrap().?;
2032 },
2033 .struct_type, .union_type, .enum_type, .opaque_type => |_, tag| {
2034 if (switch (tag) {
2035 else => unreachable,
2036 .struct_type => ip.loadStructType(val).name_nav,
2037 .union_type => ip.loadUnionType(val).name_nav,
2038 .enum_type => ip.loadEnumType(val).name_nav,
2039 .opaque_type => ip.loadOpaqueType(val).name_nav,
2040 }.unwrap()) |name_nav| {
2041 const name_gi = try dwarf.getGlobal(name_nav);
2042 break :debug_info_ni name_gi.get(dwarf).debug_info_ni.unwrap().?;
2043 }
2044 break :debug_info_ni try addConstNode(dwarf.lf, dwarf.getUnit(zcu.fileByIndex(
2045 Type.fromInterned(val).typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip),
2046 ).mod.?), cpi);
2047 },
2048 }.toOptional(),
2049 });
2050}
2051
2052pub fn updateConst(
2053 dwarf: *Dwarf,
2054 pt: Zcu.PerThread,
2055 di_nw: *link.MappedFile.Node.Writer,
2056 val: InternPool.Index,
2057) link.Error!void {
2058 switch (val) {
2059 .generic_poison_type => log.debug("updateConst(anytype)", .{}),
2060 else => log.debug("updateConst({f})", .{Value.fromInterned(val).fmtValue(pt)}),
2061 }
2062 dwarf.updateConstInner(pt, di_nw, val) catch |err| switch (err) {
2063 else => |e| return e,
2064 error.WriteFailed => return dwarf.reportWriteError(di_nw),
2065 };
2066}
2067fn updateConstInner(
2068 dwarf: *Dwarf,
2069 pt: Zcu.PerThread,
2070 di_nw: *link.MappedFile.Node.Writer,
2071 val: InternPool.Index,
2072) link.EmitError!void {
2073 const zcu = pt.zcu;
2074 const ip = &zcu.intern_pool;
2075 const di_w = &di_nw.interface;
2076 switch (ip.indexToKey(val)) {
2077 .int_type => |int_type| {
2078 const ty: Type = .fromInterned(val);
2079 try dwarf.abbrevCode(di_nw, .numeric_type);
2080 var name_buf: [std.fmt.count("i{d}", .{std.math.maxInt(u16)})]u8 = undefined;
2081 try dwarf.strp(&dwarf.debug_str, di_nw, std.mem.print(&name_buf, "{f}", .{
2082 ty.fmt(pt),
2083 }) catch unreachable);
2084 try di_w.writeByte(switch (int_type.signedness) {
2085 .signed => DW.ATE.signed,
2086 .unsigned => DW.ATE.unsigned,
2087 });
2088 try di_w.writeUleb128(int_type.bits);
2089 try di_w.writeUleb128(ty.abiSize(zcu));
2090 try di_w.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
2091 },
2092 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
2093 .one, .many, .c => {
2094 const name = try zcu.gpa.print("{f}", .{Type.fromInterned(val).fmt(pt)});
2095 defer zcu.gpa.free(name);
2096 try dwarf.abbrevCode(di_nw, switch (ptr_type.sentinel) {
2097 .none => switch (ptr_type.flags.alignment) {
2098 .none => .ptr_type,
2099 else => .ptr_aligned_type,
2100 },
2101 else => switch (ptr_type.flags.alignment) {
2102 .none => .ptr_sentinel_type,
2103 else => .ptr_aligned_sentinel_type,
2104 },
2105 });
2106 try dwarf.strp(&dwarf.debug_str, di_nw, name);
2107 switch (ptr_type.sentinel) {
2108 .none => {},
2109 else => |sentinel| try dwarf.blockConst(pt, di_nw, .fromInterned(sentinel)),
2110 }
2111 if (ptr_type.flags.alignment.toByteUnits()) |a| try di_w.writeUleb128(a);
2112 try di_w.writeByte(@backingInt(ptr_type.flags.address_space));
2113 if (ptr_type.flags.is_const or ptr_type.flags.is_volatile) try dwarf.secOffset(
2114 di_nw,
2115 di_nw.ni,
2116 di_w.end + dwarf.secOffsetSize(),
2117 );
2118 if (ptr_type.flags.is_const) {
2119 try dwarf.abbrevCode(di_nw, .is_const);
2120 if (ptr_type.flags.is_volatile) try dwarf.secOffset(
2121 di_nw,
2122 di_nw.ni,
2123 di_w.end + dwarf.secOffsetSize(),
2124 );
2125 }
2126 if (ptr_type.flags.is_volatile) try dwarf.abbrevCode(di_nw, .is_volatile);
2127 try dwarf.refType(pt, di_nw, .fromInterned(ptr_type.child));
2128 },
2129 .slice => {
2130 const ty: Type = .fromInterned(val);
2131 const name = try zcu.gpa.print("{f}", .{ty.fmt(pt)});
2132 defer zcu.gpa.free(name);
2133 try dwarf.abbrevCode(di_nw, .generated_struct_type);
2134 try dwarf.strp(&dwarf.debug_str, di_nw, name);
2135 try di_w.writeUleb128(ty.abiSize(zcu));
2136 try di_w.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
2137 try dwarf.abbrevCode(di_nw, .generated_field);
2138 try dwarf.strp(&dwarf.debug_str, di_nw, "ptr");
2139 const ptr_field_ty = ty.slicePtrFieldType(zcu);
2140 try dwarf.refType(pt, di_nw, ptr_field_ty);
2141 try di_w.writeUleb128(0);
2142 try dwarf.abbrevCode(di_nw, .generated_field);
2143 try dwarf.strp(&dwarf.debug_str, di_nw, "len");
2144 const len_field_ty: Type = .usize;
2145 try dwarf.refType(pt, di_nw, len_field_ty);
2146 try di_w.writeUleb128(len_field_ty.abiAlignment(zcu).forward(ptr_field_ty.abiSize(zcu)));
2147 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2148 },
2149 },
2150 .array_type => |array_type| {
2151 const name = try zcu.gpa.print("{f}", .{Type.fromInterned(val).fmt(pt)});
2152 defer zcu.gpa.free(name);
2153 try dwarf.abbrevCode(
2154 di_nw,
2155 if (array_type.sentinel == .none) .array_type else .array_sentinel_type,
2156 );
2157 try dwarf.strp(&dwarf.debug_str, di_nw, name);
2158 if (array_type.sentinel != .none)
2159 try dwarf.blockConst(pt, di_nw, .fromInterned(array_type.sentinel));
2160 try dwarf.refType(pt, di_nw, .fromInterned(array_type.child));
2161 try dwarf.abbrevCode(di_nw, .array_len);
2162 try dwarf.refType(pt, di_nw, .usize);
2163 try di_w.writeUleb128(array_type.len);
2164 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2165 },
2166 .vector_type => |vector_type| {
2167 const name = try zcu.gpa.print("{f}", .{Type.fromInterned(val).fmt(pt)});
2168 defer zcu.gpa.free(name);
2169 try dwarf.abbrevCode(di_nw, .vector_type);
2170 try dwarf.strp(&dwarf.debug_str, di_nw, name);
2171 try dwarf.refType(pt, di_nw, .fromInterned(vector_type.child));
2172 try dwarf.abbrevCode(di_nw, .array_len);
2173 try dwarf.refType(pt, di_nw, .usize);
2174 try di_w.writeUleb128(vector_type.len);
2175 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2176 },
2177 .opt_type => |opt_child_type_index| {
2178 const opt_ty: Type = .fromInterned(val);
2179 const opt_child_ty: Type = .fromInterned(opt_child_type_index);
2180 const opt_repr = optRepr(opt_child_ty, zcu);
2181 const name = try zcu.gpa.print("{f}", .{opt_ty.fmt(pt)});
2182 defer zcu.gpa.free(name);
2183 try dwarf.abbrevCode(di_nw, .generated_union_type);
2184 try dwarf.strp(&dwarf.debug_str, di_nw, name);
2185 try di_w.writeUleb128(opt_ty.abiSize(zcu));
2186 try di_w.writeUleb128(opt_ty.abiAlignment(zcu).toByteUnits().?);
2187 switch (opt_repr) {
2188 .opv_null => {
2189 try dwarf.abbrevCode(di_nw, .generated_field);
2190 try dwarf.strp(&dwarf.debug_str, di_nw, "null");
2191 try dwarf.refType(pt, di_nw, .null);
2192 try di_w.writeUleb128(0);
2193 },
2194 .unpacked, .error_set, .pointer => {
2195 try dwarf.abbrevCode(di_nw, .tagged_union);
2196 try dwarf.secOffset(di_nw, di_nw.ni, di_w.end + dwarf.secOffsetSize());
2197 {
2198 try dwarf.abbrevCode(di_nw, .generated_field);
2199 try dwarf.strp(&dwarf.debug_str, di_nw, "has_value");
2200 switch (opt_repr) {
2201 .opv_null => unreachable,
2202 .unpacked => {
2203 try dwarf.refType(pt, di_nw, .bool);
2204 try di_w.writeUleb128(if (opt_child_ty.hasRuntimeBits(zcu))
2205 opt_child_ty.abiSize(zcu)
2206 else
2207 0);
2208 },
2209 .error_set => {
2210 try dwarf.refType(pt, di_nw, try pt.intType(.unsigned, zcu.errorSetBits()));
2211 try di_w.writeUleb128(0);
2212 },
2213 .pointer => {
2214 try dwarf.refType(pt, di_nw, .usize);
2215 try di_w.writeUleb128(0);
2216 },
2217 }
2218
2219 try dwarf.abbrevCode(di_nw, .tagged_union_field);
2220 try di_w.writeUleb128(DW.FORM.data1);
2221 try di_w.writeByte(0);
2222 {
2223 try dwarf.abbrevCode(di_nw, .generated_field);
2224 try dwarf.strp(&dwarf.debug_str, di_nw, "null");
2225 try dwarf.refType(pt, di_nw, .null);
2226 try di_w.writeUleb128(0);
2227 }
2228 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2229
2230 try dwarf.abbrevCode(di_nw, .tagged_union_default_field);
2231 {
2232 try dwarf.abbrevCode(di_nw, .generated_field);
2233 try dwarf.strp(&dwarf.debug_str, di_nw, "?");
2234 try dwarf.refType(pt, di_nw, opt_child_ty);
2235 try di_w.writeUleb128(0);
2236 }
2237 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2238 }
2239 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2240 },
2241 }
2242 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2243 },
2244 .anyframe_type => unreachable,
2245 .error_union_type => |error_union_type| {
2246 const eu_ty: Type = .fromInterned(val);
2247 const eu_error_set_ty: Type = .fromInterned(error_union_type.error_set_type);
2248 const eu_payload_ty: Type = .fromInterned(error_union_type.payload_type);
2249 const eu_error_set_offset, const eu_payload_offset = switch (error_union_type.payload_type) {
2250 .generic_poison_type => .{ 0, 0 },
2251 else => .{
2252 codegen.errUnionErrorOffset(eu_payload_ty, zcu),
2253 codegen.errUnionPayloadOffset(eu_payload_ty, zcu),
2254 },
2255 };
2256 const name = try zcu.gpa.print("{f}", .{eu_ty.fmt(pt)});
2257 defer zcu.gpa.free(name);
2258
2259 try dwarf.abbrevCode(di_nw, .generated_union_type);
2260 try dwarf.strp(&dwarf.debug_str, di_nw, name);
2261 if (error_union_type.error_set_type != .generic_poison_type and
2262 error_union_type.payload_type != .generic_poison_type)
2263 {
2264 try di_w.writeUleb128(eu_ty.abiSize(zcu));
2265 try di_w.writeUleb128(eu_ty.abiAlignment(zcu).toByteUnits().?);
2266 } else {
2267 try di_w.writeUleb128(0);
2268 try di_w.writeUleb128(1);
2269 }
2270 {
2271 try dwarf.abbrevCode(di_nw, .tagged_union);
2272 try dwarf.secOffset(di_nw, di_nw.ni, di_w.end + dwarf.secOffsetSize());
2273 {
2274 try dwarf.abbrevCode(di_nw, .generated_field);
2275 try dwarf.strp(&dwarf.debug_str, di_nw, "is_error");
2276 try dwarf.refType(pt, di_nw, try pt.intType(.unsigned, zcu.errorSetBits()));
2277 try di_w.writeUleb128(eu_error_set_offset);
2278
2279 try dwarf.abbrevCode(di_nw, .tagged_union_field);
2280 try di_w.writeUleb128(DW.FORM.udata);
2281 try di_w.writeUleb128(0);
2282 {
2283 try dwarf.abbrevCode(di_nw, .generated_field);
2284 try dwarf.strp(&dwarf.debug_str, di_nw, "value");
2285 try dwarf.refType(pt, di_nw, eu_payload_ty);
2286 try di_w.writeUleb128(eu_payload_offset);
2287 }
2288 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2289
2290 try dwarf.abbrevCode(di_nw, .tagged_union_default_field);
2291 {
2292 try dwarf.abbrevCode(di_nw, .generated_field);
2293 try dwarf.strp(&dwarf.debug_str, di_nw, "error");
2294 try dwarf.refType(pt, di_nw, eu_error_set_ty);
2295 try di_w.writeUleb128(eu_error_set_offset);
2296 }
2297 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2298 }
2299 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2300 }
2301 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2302 },
2303 .simple_type => |simple_type| switch (simple_type) {
2304 .f16,
2305 .f32,
2306 .f64,
2307 .f80,
2308 .f128,
2309 .usize,
2310 .isize,
2311 .c_char,
2312 .c_short,
2313 .c_ushort,
2314 .c_int,
2315 .c_uint,
2316 .c_long,
2317 .c_ulong,
2318 .c_longlong,
2319 .c_ulonglong,
2320 .c_longdouble,
2321 .bool,
2322 => {
2323 const ty: Type = .fromInterned(val);
2324 try dwarf.abbrevCode(di_nw, .numeric_type);
2325 try dwarf.strp(&dwarf.debug_str, di_nw, @tagName(simple_type));
2326 try di_w.writeByte(if (val == .bool_type)
2327 DW.ATE.boolean
2328 else if (ty.isRuntimeFloat())
2329 DW.ATE.float
2330 else if (ty.isSignedInt(zcu))
2331 DW.ATE.signed
2332 else if (ty.isUnsignedInt(zcu))
2333 DW.ATE.unsigned
2334 else
2335 unreachable);
2336 try di_w.writeUleb128(ty.bitSize(zcu));
2337 try di_w.writeUleb128(ty.abiSize(zcu));
2338 try di_w.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
2339 },
2340 .generic_poison => {
2341 try dwarf.abbrevCode(di_nw, .void_type);
2342 try dwarf.strp(&dwarf.debug_str, di_nw, "anytype");
2343 },
2344 .anyopaque,
2345 .void,
2346 .type,
2347 .comptime_int,
2348 .comptime_float,
2349 .noreturn,
2350 .null,
2351 .undefined,
2352 .enum_literal,
2353 => {
2354 const ty: Type = .fromInterned(val);
2355 try dwarf.abbrevCode(di_nw, .void_type);
2356 var name_buf: ["@TypeOf(undefined)".len]u8 = undefined;
2357 try dwarf.strp(&dwarf.debug_str, di_nw, std.mem.print(&name_buf, "{f}", .{
2358 ty.fmt(pt),
2359 }) catch unreachable);
2360 },
2361 .anyerror => {
2362 const global_error_set_names = ip.global_error_set.getNamesFromMainThread();
2363 try dwarf.abbrevCode(di_nw, if (global_error_set_names.len > 0)
2364 .generated_enum_type
2365 else
2366 .generated_empty_enum_type);
2367 try dwarf.strp(&dwarf.debug_str, di_nw, "anyerror");
2368 try dwarf.refType(pt, di_nw, try pt.intType(.unsigned, zcu.errorSetBits()));
2369 for (global_error_set_names, 1..) |name, value| {
2370 try dwarf.abbrevCode(di_nw, .enum_field);
2371 try di_w.writeUleb128(DW.FORM.udata);
2372 try di_w.writeUleb128(value);
2373 try dwarf.strp(&dwarf.debug_str, di_nw, name.toSlice(ip));
2374 }
2375 if (global_error_set_names.len > 0) try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2376 },
2377 .adhoc_inferred_error_set => unreachable,
2378 },
2379 .tuple_type => |tuple_type| {
2380 const ty: Type = .fromInterned(val);
2381 const name = try zcu.gpa.print("{f}", .{ty.fmt(pt)});
2382 defer zcu.gpa.free(name);
2383 if (tuple_type.types.len == 0) {
2384 try dwarf.abbrevCode(di_nw, .generated_empty_struct_type);
2385 try dwarf.strp(&dwarf.debug_str, di_nw, name);
2386 try di_w.writeByte(@intFromBool(false));
2387 } else {
2388 try dwarf.abbrevCode(di_nw, .generated_struct_type);
2389 try dwarf.strp(&dwarf.debug_str, di_nw, name);
2390 try di_w.writeUleb128(ty.abiSize(zcu));
2391 try di_w.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
2392 var field_byte_offset: u64 = 0;
2393 for (0..tuple_type.types.len) |field_index| {
2394 const comptime_value = tuple_type.values.get(ip)[field_index];
2395 const field_ty: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);
2396 const comptime_value_class = switch (comptime_value) {
2397 .none => .no_possible_value,
2398 else => field_ty.classify(zcu),
2399 };
2400 try dwarf.abbrevCode(di_nw, switch (comptime_value) {
2401 .none => .field,
2402 else => switch (comptime_value_class) {
2403 .no_possible_value, .one_possible_value => .field_comptime,
2404 .runtime => .field_comptime_fully_runtime,
2405 .partially_comptime => .field_comptime_partially_comptime,
2406 .fully_comptime => .field_comptime_fully_comptime,
2407 },
2408 });
2409 var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined;
2410 try dwarf.strp(&dwarf.debug_str, di_nw, std.mem.print(&field_name_buf, "{d}", .{
2411 field_index,
2412 }) catch unreachable);
2413 try dwarf.refType(pt, di_nw, field_ty);
2414 if (comptime_value == .none) {
2415 const field_align = field_ty.abiAlignment(zcu);
2416 field_byte_offset = field_align.forward(field_byte_offset);
2417 try di_w.writeUleb128(field_byte_offset);
2418 try di_w.writeUleb128(field_ty.abiAlignment(zcu).toByteUnits().?);
2419 field_byte_offset += field_ty.abiSize(zcu);
2420 }
2421 if (comptime_value_class.hasRuntimeBits())
2422 try dwarf.blockConst(pt, di_nw, .fromInterned(comptime_value));
2423 if (comptime_value_class.comptimeOnly())
2424 try dwarf.refConst(pt, di_nw, .fromInterned(comptime_value));
2425 }
2426 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2427 }
2428 },
2429 .struct_type => {
2430 const loaded_struct = ip.loadStructType(val);
2431 const zfi = loaded_struct.zir_index.resolveFile(ip);
2432 const zf = zcu.fileByIndex(zfi);
2433 const src_inst = loaded_struct.zir_index.resolve(ip);
2434 if (src_inst == .main_struct_inst) {
2435 assert(loaded_struct.captures.len == 0);
2436 const ui = dwarf.getUnit(zf.mod.?);
2437 _, const fi = try ui.get(dwarf).getFile(zcu.gpa, ui, zfi);
2438 try dwarf.abbrevCode(di_nw, switch (loaded_struct.layout) {
2439 .auto => if (loaded_struct.field_types.len > 0) .file else .empty_file,
2440 .@"extern", .@"packed" => unreachable,
2441 });
2442 try di_w.writeUleb128(@backingInt(fi));
2443 try dwarf.strp(&dwarf.debug_str, di_nw, loaded_struct.name.toSlice(ip));
2444 } else if (loaded_struct.captures.len > 0 or loaded_struct.is_reified) {
2445 try dwarf.abbrevCode(di_nw, if (loaded_struct.captures.len > 0 or
2446 loaded_struct.field_types.len > 0) switch (loaded_struct.layout) {
2447 .auto, .@"extern" => .decl_instance_struct,
2448 .@"packed" => .decl_instance_packed_struct,
2449 } else switch (loaded_struct.layout) {
2450 .auto, .@"extern" => .decl_instance_empty_struct,
2451 .@"packed" => .decl_instance_empty_packed_struct,
2452 });
2453 try dwarf.secOffset(di_nw, try dwarf.getDecl(pt, val), 0);
2454 } else if (loaded_struct.name_nav.unwrap()) |name_ni| {
2455 const name_nav = ip.getNav(name_ni);
2456 const decl = zf.zir.?.getDeclaration(name_nav.srcInst(ip).resolve(ip).?);
2457 const parent_ni = try dwarf.getDecl(pt, ip.namespacePtr(
2458 name_nav.analysis.?.namespace,
2459 ).owner_type);
2460 try dwarf.abbrevCode(di_nw, if (loaded_struct.field_types.len > 0)
2461 switch (loaded_struct.layout) {
2462 .auto, .@"extern" => .decl_struct,
2463 .@"packed" => .decl_packed_struct,
2464 }
2465 else switch (loaded_struct.layout) {
2466 .auto, .@"extern" => .decl_empty_struct,
2467 .@"packed" => .decl_empty_packed_struct,
2468 });
2469 try dwarf.secOffset(di_nw, parent_ni, 0);
2470 try di_w.writeInt(u32, decl.src_line + 1, dwarf.endian);
2471 try di_w.writeUleb128(decl.src_column + 1);
2472 try di_w.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
2473 try dwarf.strp(&dwarf.debug_str, di_nw, name_nav.name.toSlice(ip));
2474 } else {
2475 const decl = zf.zir.?.getStructDecl(src_inst.?);
2476 const parent_ni = try dwarf.getDecl(pt, ip.namespacePtr(
2477 ip.namespacePtr(loaded_struct.namespace).parent.unwrap().?,
2478 ).owner_type);
2479 try dwarf.abbrevCode(di_nw, if (loaded_struct.field_types.len > 0)
2480 switch (loaded_struct.layout) {
2481 .auto, .@"extern" => .type_decl_struct,
2482 .@"packed" => .type_decl_packed_struct,
2483 }
2484 else switch (loaded_struct.layout) {
2485 .auto, .@"extern" => .type_decl_empty_struct,
2486 .@"packed" => .type_decl_empty_packed_struct,
2487 });
2488 try dwarf.secOffset(di_nw, parent_ni, 0);
2489 try di_w.writeInt(u32, decl.src_line + 1, dwarf.endian);
2490 try di_w.writeUleb128(decl.src_column + 1);
2491 try dwarf.strp(&dwarf.debug_str, di_nw, loaded_struct.name.toSlice(ip));
2492 }
2493 switch (loaded_struct.layout) {
2494 .auto, .@"extern" => {
2495 const ty: Type = .fromInterned(val);
2496 try di_w.writeUleb128(ty.abiSize(zcu));
2497 try di_w.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
2498 try dwarf.genCaptures(pt, di_nw, loaded_struct.captures);
2499 for (0..loaded_struct.field_types.len) |field_index| {
2500 const is_comptime = loaded_struct.field_is_comptime_bits.get(ip, field_index);
2501 // TODO: we currently don't emit information about default values for
2502 // non-`comptime` fields, because these default values are resolved at a
2503 // separate time in the compiler frontend. To emit this information, the
2504 // frontend needs to tell us when the default values are available: like
2505 // how `Zcu.PerThread.ensureTypeLayoutUpToDate` enqueues a link task to
2506 // indicate completion of the type's layout, a task should be enqueued
2507 // by `Zcu.PerThread.ensureStructDefaultsUpToDate`, and upon receiving
2508 // it we should patch the correct default field values in.
2509 const field_default = if (is_comptime)
2510 loaded_struct.field_defaults.getOrNone(ip, field_index)
2511 else
2512 .none;
2513 assert(!(is_comptime and field_default == .none));
2514 const field_ty: Type =
2515 .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
2516 const field_default_class = switch (field_default) {
2517 .none => .no_possible_value,
2518 else => field_ty.classify(zcu),
2519 };
2520 try dwarf.abbrevCode(di_nw, if (is_comptime) switch (field_default_class) {
2521 .no_possible_value, .one_possible_value => .field_comptime,
2522 .runtime => .field_comptime_fully_runtime,
2523 .partially_comptime => .field_comptime_partially_comptime,
2524 .fully_comptime => .field_comptime_fully_comptime,
2525 } else switch (field_default_class) {
2526 .no_possible_value, .one_possible_value => .field,
2527 .runtime => .field_default_fully_runtime,
2528 .partially_comptime => .field_default_partially_comptime,
2529 .fully_comptime => .field_default_fully_comptime,
2530 });
2531 try dwarf.strp(
2532 &dwarf.debug_str,
2533 di_nw,
2534 loaded_struct.field_names.get(ip)[field_index].toSlice(ip),
2535 );
2536 try dwarf.refType(pt, di_nw, field_ty);
2537 if (!is_comptime) {
2538 try di_w.writeUleb128(loaded_struct.field_offsets.get(ip)[field_index]);
2539 try di_w.writeUleb128(loaded_struct.field_aligns.getOrNone(
2540 ip,
2541 field_index,
2542 ).toByteUnits() orelse field_ty.abiAlignment(zcu).toByteUnits().?);
2543 }
2544 if (field_default_class.hasRuntimeBits())
2545 try dwarf.blockConst(pt, di_nw, .fromInterned(field_default));
2546 if (field_default_class.comptimeOnly())
2547 try dwarf.refConst(pt, di_nw, .fromInterned(field_default));
2548 }
2549 },
2550 .@"packed" => {
2551 try dwarf.refType(pt, di_nw, .fromInterned(loaded_struct.packed_backing_int_type));
2552 try dwarf.genCaptures(pt, di_nw, loaded_struct.captures);
2553 var field_bit_offset: u16 = 0;
2554 for (0..loaded_struct.field_types.len) |field_index| {
2555 try dwarf.abbrevCode(di_nw, .packed_field);
2556 try dwarf.strp(
2557 &dwarf.debug_str,
2558 di_nw,
2559 loaded_struct.field_names.get(ip)[field_index].toSlice(ip),
2560 );
2561 const field_ty: Type =
2562 .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
2563 try dwarf.refType(pt, di_nw, field_ty);
2564 try di_w.writeUleb128(field_bit_offset);
2565 field_bit_offset += @intCast(field_ty.bitSize(zcu));
2566 }
2567 },
2568 }
2569 if (loaded_struct.captures.len > 0 or loaded_struct.field_types.len > 0)
2570 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2571 },
2572 .union_type => {
2573 const loaded_union = ip.loadUnionType(val);
2574 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
2575 const zfi = loaded_union.zir_index.resolveFile(ip);
2576 const zf = zcu.fileByIndex(zfi);
2577 if (loaded_union.captures.len > 0 or loaded_union.is_reified) {
2578 try dwarf.abbrevCode(di_nw, if (loaded_union.captures.len > 0 or
2579 loaded_union.field_types.len > 0) switch (loaded_union.layout) {
2580 .auto, .@"extern" => .decl_instance_union,
2581 .@"packed" => .decl_instance_packed_union,
2582 } else switch (loaded_union.layout) {
2583 .auto, .@"extern" => .decl_instance_empty_union,
2584 .@"packed" => .decl_instance_empty_packed_union,
2585 });
2586 try dwarf.secOffset(di_nw, try dwarf.getDecl(pt, val), 0);
2587 } else if (loaded_union.name_nav.unwrap()) |name_ni| {
2588 const name_nav = ip.getNav(name_ni);
2589 const decl = zf.zir.?.getDeclaration(name_nav.srcInst(ip).resolve(ip).?);
2590 const parent_ni = try dwarf.getDecl(pt, ip.namespacePtr(
2591 name_nav.analysis.?.namespace,
2592 ).owner_type);
2593 try dwarf.abbrevCode(di_nw, if (loaded_union.field_types.len > 0)
2594 switch (loaded_union.layout) {
2595 .auto, .@"extern" => .decl_union,
2596 .@"packed" => .decl_packed_union,
2597 }
2598 else switch (loaded_union.layout) {
2599 .auto, .@"extern" => .decl_empty_union,
2600 .@"packed" => .decl_empty_packed_union,
2601 });
2602 try dwarf.secOffset(di_nw, parent_ni, 0);
2603 try di_w.writeInt(u32, decl.src_line + 1, dwarf.endian);
2604 try di_w.writeUleb128(decl.src_column + 1);
2605 try di_w.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
2606 try dwarf.strp(&dwarf.debug_str, di_nw, name_nav.name.toSlice(ip));
2607 } else {
2608 const decl = zf.zir.?.getUnionDecl(loaded_union.zir_index.resolve(ip).?);
2609 const parent_ni = try dwarf.getDecl(pt, ip.namespacePtr(
2610 ip.namespacePtr(loaded_union.namespace).parent.unwrap().?,
2611 ).owner_type);
2612 try dwarf.abbrevCode(di_nw, if (loaded_union.field_types.len > 0)
2613 switch (loaded_union.layout) {
2614 .auto, .@"extern" => .type_decl_union,
2615 .@"packed" => .type_decl_packed_union,
2616 }
2617 else switch (loaded_union.layout) {
2618 .auto, .@"extern" => .type_decl_empty_union,
2619 .@"packed" => .type_decl_empty_packed_union,
2620 });
2621 try dwarf.secOffset(di_nw, parent_ni, 0);
2622 try di_w.writeInt(u32, decl.src_line + 1, dwarf.endian);
2623 try di_w.writeUleb128(decl.src_column + 1);
2624 try dwarf.strp(&dwarf.debug_str, di_nw, loaded_union.name.toSlice(ip));
2625 }
2626 switch (loaded_union.layout) {
2627 .auto, .@"extern" => {
2628 const union_layout = Type.getUnionLayout(loaded_union, zcu);
2629 try di_w.writeUleb128(union_layout.abi_size);
2630 try di_w.writeUleb128(union_layout.abi_align.toByteUnits().?);
2631 try dwarf.genCaptures(pt, di_nw, loaded_union.captures);
2632 if (loaded_union.has_runtime_tag) {
2633 try dwarf.abbrevCode(di_nw, .tagged_union);
2634 try dwarf.secOffset(di_nw, di_nw.ni, di_w.end + dwarf.secOffsetSize());
2635 {
2636 try dwarf.abbrevCode(di_nw, .generated_field);
2637 try dwarf.strp(&dwarf.debug_str, di_nw, "tag");
2638 try dwarf.refType(pt, di_nw, .fromInterned(loaded_union.enum_tag_type));
2639 try di_w.writeUleb128(union_layout.tagOffset());
2640
2641 for (0..loaded_union.field_types.len) |field_index| {
2642 try dwarf.abbrevCode(di_nw, .tagged_union_field);
2643 try dwarf.enumConstValue(di_w, loaded_tag, field_index);
2644 {
2645 try dwarf.abbrevCode(di_nw, .field);
2646 try dwarf.strp(
2647 &dwarf.debug_str,
2648 di_nw,
2649 loaded_tag.field_names.get(ip)[field_index].toSlice(ip),
2650 );
2651 const field_ty: Type =
2652 .fromInterned(loaded_union.field_types.get(ip)[field_index]);
2653 try dwarf.refType(pt, di_nw, field_ty);
2654 try di_w.writeUleb128(union_layout.payloadOffset());
2655 try di_w.writeUleb128(loaded_union.field_aligns.getOrNone(
2656 ip,
2657 field_index,
2658 ).toByteUnits() orelse if (field_ty.isNoReturn(zcu))
2659 1
2660 else
2661 field_ty.abiAlignment(zcu).toByteUnits().?);
2662 }
2663 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2664 }
2665 }
2666 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2667 } else for (0..loaded_union.field_types.len) |field_index| {
2668 try dwarf.abbrevCode(di_nw, .field);
2669 try dwarf.strp(
2670 &dwarf.debug_str,
2671 di_nw,
2672 loaded_tag.field_names.get(ip)[field_index].toSlice(ip),
2673 );
2674 const field_ty: Type =
2675 .fromInterned(loaded_union.field_types.get(ip)[field_index]);
2676 try dwarf.refType(pt, di_nw, field_ty);
2677 try di_w.writeUleb128(0);
2678 try di_w.writeUleb128(loaded_union.field_aligns.getOrNone(
2679 ip,
2680 field_index,
2681 ).toByteUnits() orelse if (field_ty.isNoReturn(zcu))
2682 1
2683 else
2684 field_ty.abiAlignment(zcu).toByteUnits().?);
2685 }
2686 },
2687 .@"packed" => {
2688 try dwarf.refType(pt, di_nw, .fromInterned(loaded_union.packed_backing_int_type));
2689 for (0..loaded_union.field_types.len) |field_index| {
2690 try dwarf.abbrevCode(di_nw, .packed_field);
2691 try dwarf.strp(
2692 &dwarf.debug_str,
2693 di_nw,
2694 loaded_tag.field_names.get(ip)[field_index].toSlice(ip),
2695 );
2696 try dwarf.refType(pt, di_nw, .fromInterned(
2697 loaded_union.field_types.get(ip)[field_index],
2698 ));
2699 try di_w.writeUleb128(0);
2700 }
2701 },
2702 }
2703 if (loaded_union.captures.len > 0 or loaded_union.field_types.len > 0)
2704 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2705 },
2706 .enum_type => {
2707 const loaded_enum = ip.loadEnumType(val);
2708 switch (loaded_enum.owner_union) {
2709 .none => {
2710 const zfi = loaded_enum.zir_index.unwrap().?.resolveFile(ip);
2711 const zf = zcu.fileByIndex(zfi);
2712 if (loaded_enum.captures.len > 0 or loaded_enum.is_reified) {
2713 try dwarf.abbrevCode(di_nw, if (loaded_enum.captures.len > 0 or
2714 loaded_enum.field_names.len > 0)
2715 .decl_instance_enum
2716 else
2717 .decl_instance_empty_enum);
2718 try dwarf.secOffset(di_nw, try dwarf.getDecl(pt, val), 0);
2719 } else if (loaded_enum.name_nav.unwrap()) |name_ni| {
2720 const name_nav = ip.getNav(name_ni);
2721 const decl = zf.zir.?.getDeclaration(name_nav.srcInst(ip).resolve(ip).?);
2722 const parent_ni = try dwarf.getDecl(pt, ip.namespacePtr(
2723 name_nav.analysis.?.namespace,
2724 ).owner_type);
2725 try dwarf.abbrevCode(
2726 di_nw,
2727 if (loaded_enum.field_names.len > 0) .decl_enum else .decl_empty_enum,
2728 );
2729 try dwarf.secOffset(di_nw, parent_ni, 0);
2730 try di_w.writeInt(u32, decl.src_line + 1, dwarf.endian);
2731 try di_w.writeUleb128(decl.src_column + 1);
2732 try di_w.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
2733 try dwarf.strp(&dwarf.debug_str, di_nw, name_nav.name.toSlice(ip));
2734 } else {
2735 const decl =
2736 zf.zir.?.getEnumDecl(loaded_enum.zir_index.unwrap().?.resolve(ip).?);
2737 const parent_ni = try dwarf.getDecl(pt, ip.namespacePtr(
2738 ip.namespacePtr(loaded_enum.namespace).parent.unwrap().?,
2739 ).owner_type);
2740 try dwarf.abbrevCode(di_nw, if (loaded_enum.field_names.len > 0)
2741 .type_decl_enum
2742 else
2743 .type_decl_empty_enum);
2744 try dwarf.secOffset(di_nw, parent_ni, 0);
2745 try di_w.writeInt(u32, decl.src_line + 1, dwarf.endian);
2746 try di_w.writeUleb128(decl.src_column + 1);
2747 try dwarf.strp(&dwarf.debug_str, di_nw, loaded_enum.name.toSlice(ip));
2748 }
2749 },
2750 else => {
2751 try dwarf.abbrevCode(di_nw, if (loaded_enum.field_names.len > 0)
2752 .generated_enum_type
2753 else
2754 .generated_empty_enum_type);
2755 try dwarf.strp(&dwarf.debug_str, di_nw, loaded_enum.fqn.toSlice(ip));
2756 },
2757 }
2758 try dwarf.refType(pt, di_nw, .fromInterned(loaded_enum.int_tag_type));
2759 for (0..loaded_enum.field_names.len) |field_index| {
2760 try dwarf.abbrevCode(di_nw, .enum_field);
2761 try dwarf.enumConstValue(di_w, loaded_enum, field_index);
2762 try dwarf.strp(
2763 &dwarf.debug_str,
2764 di_nw,
2765 loaded_enum.field_names.get(ip)[field_index].toSlice(ip),
2766 );
2767 }
2768 if (loaded_enum.captures.len > 0 or loaded_enum.field_names.len > 0)
2769 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2770 },
2771 // no defined size, so lowered the same as incomplete struct types
2772 .opaque_type => return dwarf.updateConstIncompleteInner(pt, di_nw, val),
2773 .spirv_type => unreachable,
2774 .func_type => |func_type| {
2775 const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
2776 const name = try zcu.gpa.print("{f}", .{Type.fromInterned(val).fmt(pt)});
2777 defer zcu.gpa.free(name);
2778 try dwarf.abbrevCode(di_nw, if (is_nullary) .nullary_func_type else .func_type);
2779 try dwarf.strp(&dwarf.debug_str, di_nw, name);
2780 const cc: DW.CC = cc: {
2781 if (zcu.getTarget().cCallingConvention()) |cc| {
2782 if (@as(std.lang.CallingConvention.Tag, cc) == func_type.cc) {
2783 break :cc .normal;
2784 }
2785 }
2786 // For better or worse, we try to match what Clang emits.
2787 break :cc switch (func_type.cc) {
2788 .@"inline" => .nocall,
2789 .async, .auto, .naked => .normal,
2790 .x86_64_sysv => .LLVM_X86_64SysV,
2791 .x86_64_win => .LLVM_Win64,
2792 .x86_64_regcall_v3_sysv => .LLVM_X86RegCall,
2793 .x86_64_regcall_v4_win => .LLVM_X86RegCall,
2794 .x86_64_vectorcall => .LLVM_vectorcall,
2795 .x86_sysv, .x86_win, .x86_mingw => .normal,
2796 .x86_64_preserve_none => .LLVM_PreserveNone,
2797 .x86_stdcall => .BORLAND_stdcall,
2798 .x86_fastcall => .BORLAND_msfastcall,
2799 .x86_thiscall => .BORLAND_thiscall,
2800 .x86_thiscall_mingw => .BORLAND_thiscall,
2801 .x86_regcall_v3 => .LLVM_X86RegCall,
2802 .x86_regcall_v4_win => .LLVM_X86RegCall,
2803 .x86_vectorcall => .LLVM_vectorcall,
2804
2805 .aarch64_aapcs => .normal,
2806 .aarch64_aapcs_darwin => .normal,
2807 .aarch64_aapcs_win => .normal,
2808 .aarch64_vfabi => .LLVM_AAPCS,
2809 .aarch64_vfabi_sve => .LLVM_AAPCS,
2810 .aarch64_preserve_none => .LLVM_PreserveNone,
2811
2812 .arm_aapcs => .LLVM_AAPCS,
2813 .arm_aapcs_vfp => .LLVM_AAPCS_VFP,
2814
2815 .riscv64_lp64_v,
2816 .riscv32_ilp32_v,
2817 => .LLVM_RISCVVectorCall,
2818
2819 .m68k_rtd => .LLVM_M68kRTD,
2820
2821 .sh_renesas => .GNU_renesas_sh,
2822
2823 .amdgcn_kernel => .LLVM_OpenCLKernel,
2824 .nvptx_kernel,
2825 .spirv_kernel,
2826 => .nocall,
2827
2828 .x86_64_interrupt,
2829 .x86_interrupt,
2830 .arm_interrupt,
2831 .mips64_interrupt,
2832 .mips_interrupt,
2833 .riscv64_interrupt,
2834 .riscv32_interrupt,
2835 .sh_interrupt,
2836 .arc_interrupt,
2837 .avr_builtin,
2838 .avr_signal,
2839 .avr_interrupt,
2840 .csky_interrupt,
2841 .m68k_interrupt,
2842 .microblaze_interrupt,
2843 .msp430_interrupt,
2844 => .normal,
2845
2846 else => .nocall,
2847 };
2848 };
2849 try di_w.writeByte(@backingInt(cc));
2850 try dwarf.refType(pt, di_nw, .fromInterned(func_type.return_type));
2851 if (!is_nullary) {
2852 for (0..func_type.param_types.len) |param_index| {
2853 try dwarf.abbrevCode(di_nw, .unnamed_param);
2854 try dwarf.refType(pt, di_nw, .fromInterned(
2855 func_type.param_types.get(ip)[param_index],
2856 ));
2857 }
2858 if (func_type.is_var_args) try dwarf.abbrevCode(di_nw, .is_var_args);
2859 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2860 }
2861 },
2862 .error_set_type => |error_set_type| {
2863 const name = try zcu.gpa.print("{f}", .{Type.fromInterned(val).fmt(pt)});
2864 defer zcu.gpa.free(name);
2865 try dwarf.abbrevCode(
2866 di_nw,
2867 if (error_set_type.names.len > 0) .generated_enum_type else .generated_empty_enum_type,
2868 );
2869 try dwarf.strp(&dwarf.debug_str, di_nw, name);
2870 try dwarf.refType(pt, di_nw, try pt.intType(.unsigned, zcu.errorSetBits()));
2871 for (0..error_set_type.names.len) |field_index| {
2872 const field_name = error_set_type.names.get(ip)[field_index];
2873 try dwarf.abbrevCode(di_nw, .enum_field);
2874 try di_w.writeUleb128(DW.FORM.udata);
2875 try di_w.writeUleb128(ip.getErrorValueIfExists(field_name).?);
2876 try dwarf.strp(&dwarf.debug_str, di_nw, field_name.toSlice(ip));
2877 }
2878 if (error_set_type.names.len > 0) try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2879 },
2880 .inferred_error_set_type => |func| {
2881 const name = try zcu.gpa.print("{f}", .{Type.fromInterned(val).fmt(pt)});
2882 defer zcu.gpa.free(name);
2883 try dwarf.abbrevCode(di_nw, .inferred_error_set_type);
2884 try dwarf.strp(&dwarf.debug_str, di_nw, name);
2885 try dwarf.refType(pt, di_nw, switch (ies: {
2886 const fi = dwarf.getFuncIfExists(ip.indexToKey(func).func.owner_nav) orelse
2887 break :ies .none;
2888 break :ies switch (fi.get(dwarf).state) {
2889 .unresolved => .none,
2890 .resolved => ip.funcIesResolvedUnordered(func),
2891 };
2892 }) {
2893 .none => .anyerror,
2894 else => |ies| .fromInterned(ies),
2895 });
2896 },
2897
2898 else => return,
2899 .func => |func| {
2900 const fn_ty = ip.indexToKey(func.ty).func_type;
2901 const nav = ip.getNav(func.owner_nav);
2902 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
2903 const zf = zcu.fileByIndex(inst_info.file);
2904 const decl = zf.zir.?.getDeclaration(inst_info.inst);
2905 const parent_ty: Type = .fromInterned(ip.namespacePtr(nav.analysis.?.namespace).owner_type);
2906 try dwarf.abbrevCode(di_nw, .decl_func_generic);
2907 try dwarf.refType(pt, di_nw, parent_ty);
2908 try di_w.writeInt(u32, decl.src_line + 1, dwarf.endian);
2909 try di_w.writeUleb128(decl.src_column + 1);
2910 try di_w.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
2911 try dwarf.strp(&dwarf.debug_str, di_nw, nav.name.toSlice(ip));
2912 try dwarf.refType(pt, di_nw, .fromInterned(fn_ty.return_type));
2913 var param_index: u32 = 0;
2914 for (zf.zir.?.getParamBody(func.zir_body_inst.resolve(ip).?)) |param_inst| {
2915 switch (zf.zir.?.getParamName(param_inst) orelse break) {
2916 .empty => try dwarf.abbrevCode(di_nw, .unnamed_param),
2917 else => |param_name| {
2918 try dwarf.abbrevCode(di_nw, .param);
2919 try dwarf.strp(&dwarf.debug_str, di_nw, zf.zir.?.nullTerminatedString(
2920 param_name,
2921 ));
2922 },
2923 }
2924 try dwarf.refType(pt, di_nw, .fromInterned(
2925 fn_ty.param_types.get(&zcu.intern_pool)[param_index],
2926 ));
2927 param_index += 1;
2928 }
2929 if (fn_ty.is_var_args) try dwarf.abbrevCode(di_nw, .is_var_args);
2930 try di_w.writeUleb128(@backingInt(AbbrevCode.null));
2931 },
2932
2933 .memoized_call => unreachable, // not a value
2934 }
2935 try dwarf.genDebugInfoPadding(di_w, di_w.unusedCapacityLen());
2936}
2937
2938fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { unpacked, opv_null, error_set, pointer } {
2939 if (opt_child_type.isNoReturn(zcu)) return .opv_null;
2940 return switch (opt_child_type.toIntern()) {
2941 .anyerror_type => .error_set,
2942 else => switch (zcu.intern_pool.indexToKey(opt_child_type.toIntern())) {
2943 else => .unpacked,
2944 .error_set_type, .inferred_error_set_type => .error_set,
2945 .ptr_type => |ptr_type| if (ptr_type.flags.is_allowzero) .unpacked else .pointer,
2946 },
2947 };
2948}
2949
2950pub fn updateConstIncomplete(
2951 dwarf: *Dwarf,
2952 pt: Zcu.PerThread,
2953 di_nw: *link.MappedFile.Node.Writer,
2954 val: InternPool.Index,
2955) link.Error!void {
2956 log.debug("updateConstIncomplete({f})", .{Value.fromInterned(val).fmtValue(pt)});
2957 dwarf.updateConstIncompleteInner(pt, di_nw, val) catch |err| switch (err) {
2958 else => |e| return e,
2959 error.WriteFailed => return dwarf.reportWriteError(di_nw),
2960 };
2961}
2962fn updateConstIncompleteInner(
2963 dwarf: *Dwarf,
2964 pt: Zcu.PerThread,
2965 di_nw: *link.MappedFile.Node.Writer,
2966 val: InternPool.Index,
2967) link.EmitError!void {
2968 const zcu = pt.zcu;
2969 const ip = &zcu.intern_pool;
2970 const di_w = &di_nw.interface;
2971 done: {
2972 const kind: enum { @"struct", @"union", @"enum" }, const zf, const src_line, const src_column, const is_reified, const captures, const name, const maybe_name_nav, const namespace = container: switch (ip.indexToKey(val)) {
2973 .struct_type => {
2974 const loaded_struct = ip.loadStructType(val);
2975 const src_inst = loaded_struct.zir_index.resolveFull(ip) orelse {
2976 try dwarf.lostTracking(di_nw);
2977 break :done;
2978 };
2979 const zf = zcu.fileByIndex(src_inst.file);
2980 switch (src_inst.inst) {
2981 .main_struct_inst => {
2982 const ui = dwarf.getUnit(zf.mod.?);
2983 _, const fi = try ui.get(dwarf).getFile(zcu.gpa, ui, src_inst.file);
2984 try dwarf.abbrevCode(di_nw, .empty_file);
2985 try di_w.writeUleb128(@backingInt(fi));
2986 try dwarf.strp(&dwarf.debug_str, di_nw, loaded_struct.name.toSlice(ip));
2987 try di_w.writeByte(@intFromBool(true));
2988 break :done;
2989 },
2990 else => {
2991 const data =
2992 zf.zir.?.instructions.items(.data)[@backingInt(src_inst.inst)].extended;
2993 const src_line, const src_column = src_loc: switch (data.opcode) {
2994 else => unreachable,
2995 .struct_decl => {
2996 const decl = zf.zir.?.getStructDecl(src_inst.inst);
2997 break :src_loc .{ decl.src_line, decl.src_column };
2998 },
2999 .reify_struct => {
3000 const decl = zf.zir.?.extraData(
3001 std.zig.Zir.Inst.ReifyStruct,
3002 data.operand,
3003 ).data;
3004 break :src_loc .{ decl.src_line, decl.src_column };
3005 },
3006 };
3007 break :container .{
3008 .@"struct",
3009 zf,
3010 src_line,
3011 src_column,
3012 loaded_struct.is_reified,
3013 loaded_struct.captures,
3014 loaded_struct.name,
3015 loaded_struct.name_nav,
3016 loaded_struct.namespace,
3017 };
3018 },
3019 }
3020 },
3021 .union_type => {
3022 const loaded_union = ip.loadUnionType(val);
3023 const src_inst = loaded_union.zir_index.resolveFull(ip) orelse {
3024 try dwarf.lostTracking(di_nw);
3025 break :done;
3026 };
3027 const zf = zcu.fileByIndex(src_inst.file);
3028 const data = zf.zir.?.instructions.items(.data)[@backingInt(src_inst.inst)].extended;
3029 const src_line, const src_column = src_loc: switch (data.opcode) {
3030 else => unreachable,
3031 .union_decl => {
3032 const decl = zf.zir.?.getUnionDecl(src_inst.inst);
3033 break :src_loc .{ decl.src_line, decl.src_column };
3034 },
3035 .reify_union => {
3036 const decl = zf.zir.?.extraData(std.zig.Zir.Inst.ReifyUnion, data.operand).data;
3037 break :src_loc .{ decl.src_line, decl.src_column };
3038 },
3039 };
3040 break :container .{
3041 .@"union",
3042 zf,
3043 src_line,
3044 src_column,
3045 loaded_union.is_reified,
3046 loaded_union.captures,
3047 loaded_union.name,
3048 loaded_union.name_nav,
3049 loaded_union.namespace,
3050 };
3051 },
3052 .enum_type => {
3053 const loaded_enum = ip.loadEnumType(val);
3054 const zir_index = loaded_enum.zir_index.unwrap() orelse {
3055 try dwarf.abbrevCode(di_nw, .generated_empty_struct_type);
3056 try dwarf.strp(&dwarf.debug_str, di_nw, loaded_enum.name.toSlice(ip));
3057 try di_w.writeByte(@intFromBool(true));
3058 break :done;
3059 };
3060 const src_inst = zir_index.resolveFull(ip) orelse {
3061 try dwarf.lostTracking(di_nw);
3062 break :done;
3063 };
3064 const zf = zcu.fileByIndex(src_inst.file);
3065 const data = zf.zir.?.instructions.items(.data)[@backingInt(src_inst.inst)].extended;
3066 const src_line, const src_column = src_loc: switch (data.opcode) {
3067 else => unreachable,
3068 .enum_decl => {
3069 const decl = zf.zir.?.getEnumDecl(src_inst.inst);
3070 break :src_loc .{ decl.src_line, decl.src_column };
3071 },
3072 .reify_enum => {
3073 const decl = zf.zir.?.extraData(std.zig.Zir.Inst.ReifyEnum, data.operand).data;
3074 break :src_loc .{ decl.src_line, decl.src_column };
3075 },
3076 };
3077 break :container .{
3078 .@"enum",
3079 zf,
3080 src_line,
3081 src_column,
3082 loaded_enum.is_reified,
3083 loaded_enum.captures,
3084 loaded_enum.name,
3085 loaded_enum.name_nav,
3086 loaded_enum.namespace,
3087 };
3088 },
3089 // always complete, but forwarded from `updateConstInner`
3090 .opaque_type => {
3091 const loaded_opaque = ip.loadOpaqueType(val);
3092 const src_inst = loaded_opaque.zir_index.resolveFull(ip) orelse {
3093 try dwarf.lostTracking(di_nw);
3094 break :done;
3095 };
3096 const zf = zcu.fileByIndex(src_inst.file);
3097 const decl = zf.zir.?.getOpaqueDecl(src_inst.inst);
3098 break :container .{
3099 .@"struct",
3100 zf,
3101 decl.src_line,
3102 decl.src_column,
3103 false,
3104 loaded_opaque.captures,
3105 loaded_opaque.name,
3106 loaded_opaque.name_nav,
3107 loaded_opaque.namespace,
3108 };
3109 },
3110 else => |val_key| break :done switch (val_key.typeOf()) {
3111 .type_type => {
3112 const name = try zcu.gpa.print("{f}", .{Type.fromInterned(val).fmt(pt)});
3113 defer zcu.gpa.free(name);
3114 try dwarf.abbrevCode(di_nw, .generated_empty_struct_type);
3115 try dwarf.strp(&dwarf.debug_str, di_nw, name);
3116 try di_w.writeByte(@intFromBool(true));
3117 },
3118 else => |ty| {
3119 try dwarf.abbrevCode(di_nw, .undefined_comptime_value);
3120 try dwarf.refType(pt, di_nw, .fromInterned(ty));
3121 },
3122 },
3123 };
3124 if (captures.len > 0 or is_reified) {
3125 try dwarf.abbrevCode(di_nw, if (captures.len > 0) switch (kind) {
3126 .@"struct" => .decl_instance_incomplete_struct,
3127 .@"union" => .decl_instance_incomplete_union,
3128 .@"enum" => .decl_instance_incomplete_enum,
3129 } else switch (kind) {
3130 .@"struct" => .decl_instance_empty_incomplete_struct,
3131 .@"union" => .decl_instance_empty_incomplete_union,
3132 .@"enum" => .decl_instance_empty_incomplete_enum,
3133 });
3134 try dwarf.secOffset(di_nw, try dwarf.getDecl(pt, val), 0);
3135 } else if (maybe_name_nav.unwrap()) |name_ni| {
3136 const name_nav = ip.getNav(name_ni);
3137 const decl = zf.zir.?.getDeclaration(name_nav.srcInst(ip).resolve(ip).?);
3138 const parent_ni = try dwarf.getDecl(pt, ip.namespacePtr(
3139 name_nav.analysis.?.namespace,
3140 ).owner_type);
3141 try dwarf.abbrevCode(di_nw, if (captures.len > 0) switch (kind) {
3142 .@"struct" => .decl_incomplete_struct,
3143 .@"union" => .decl_incomplete_union,
3144 .@"enum" => .decl_incomplete_enum,
3145 } else switch (kind) {
3146 .@"struct" => .decl_empty_incomplete_struct,
3147 .@"union" => .decl_empty_incomplete_union,
3148 .@"enum" => .decl_empty_incomplete_enum,
3149 });
3150 try dwarf.secOffset(di_nw, parent_ni, 0);
3151 try di_w.writeInt(u32, decl.src_line + 1, dwarf.endian);
3152 try di_w.writeUleb128(decl.src_column + 1);
3153 try di_w.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
3154 try dwarf.strp(&dwarf.debug_str, di_nw, name_nav.name.toSlice(ip));
3155 } else {
3156 const parent_ni = try dwarf.getDecl(pt, ip.namespacePtr(
3157 ip.namespacePtr(namespace).parent.unwrap().?,
3158 ).owner_type);
3159 try dwarf.abbrevCode(di_nw, if (captures.len > 0) switch (kind) {
3160 .@"struct" => .type_decl_incomplete_struct,
3161 .@"union" => .type_decl_incomplete_union,
3162 .@"enum" => .type_decl_incomplete_enum,
3163 } else switch (kind) {
3164 .@"struct" => .type_decl_empty_incomplete_struct,
3165 .@"union" => .type_decl_empty_incomplete_union,
3166 .@"enum" => .type_decl_empty_incomplete_enum,
3167 });
3168 try dwarf.secOffset(di_nw, parent_ni, 0);
3169 try di_w.writeInt(u32, src_line + 1, dwarf.endian);
3170 try di_w.writeUleb128(src_column + 1);
3171 try dwarf.strp(&dwarf.debug_str, di_nw, name.toSlice(ip));
3172 }
3173 try dwarf.genCaptures(pt, di_nw, captures);
3174 if (captures.len > 0) try di_w.writeByte(@backingInt(AbbrevCode.null));
3175 }
3176 try dwarf.genDebugInfoPadding(di_w, di_w.unusedCapacityLen());
3177}
3178
3179fn genCaptures(
3180 dwarf: *Dwarf,
3181 pt: Zcu.PerThread,
3182 di_nw: *link.MappedFile.Node.Writer,
3183 captures: anytype,
3184) link.EmitError!void {
3185 const zcu = pt.zcu;
3186 const ip = &zcu.intern_pool;
3187 for (captures.get(ip)) |capture| switch (capture.unwrap()) {
3188 .@"comptime" => |capture_val| {
3189 const ty: Type = .fromInterned(ip.typeOf(capture_val));
3190 const ty_class = ty.classify(zcu);
3191 try dwarf.abbrevCode(di_nw, switch (ty_class) {
3192 .no_possible_value => unreachable,
3193 .one_possible_value => .comptime_capture,
3194 .runtime => .comptime_capture_runtime,
3195 .partially_comptime => .comptime_capture_partially_comptime,
3196 .fully_comptime => .comptime_capture_fully_comptime,
3197 });
3198 try dwarf.refType(pt, di_nw, ty);
3199 if (ty_class.hasRuntimeBits()) try dwarf.blockConst(pt, di_nw, .fromInterned(capture_val));
3200 if (ty_class.comptimeOnly()) try dwarf.refConst(pt, di_nw, .fromInterned(capture_val));
3201 },
3202 .runtime => |capture_ty| {
3203 try dwarf.abbrevCode(di_nw, .runtime_capture);
3204 try dwarf.refType(pt, di_nw, .fromInterned(capture_ty));
3205 },
3206 .nav_val => |capture_nav| {
3207 const gi = try dwarf.getGlobal(capture_nav);
3208 try dwarf.abbrevCode(di_nw, .nav_capture);
3209 try dwarf.exprLoc(di_nw, .{ .implicit_pointer = .{
3210 .node = gi.get(dwarf).debug_info_ni.unwrap().?,
3211 } });
3212 },
3213 .nav_ref => |capture_nav| {
3214 const gi = try dwarf.getGlobal(capture_nav);
3215 try dwarf.abbrevCode(di_nw, .nav_capture);
3216 try dwarf.exprLoc(di_nw, .{ .stack_value = &.{ .implicit_pointer = .{
3217 .node = gi.get(dwarf).debug_info_ni.unwrap().?,
3218 } } });
3219 },
3220 };
3221}
3222
3223pub fn genDecl(
3224 dwarf: *Dwarf,
3225 pt: Zcu.PerThread,
3226 di_nw: *link.MappedFile.Node.Writer,
3227 instance_val: InternPool.Index,
3228) link.Error!void {
3229 log.debug("genDecl({f})", .{Value.fromInterned(instance_val).fmtValue(pt)});
3230 dwarf.genDeclInner(pt, di_nw, instance_val) catch |err| switch (err) {
3231 else => |e| return e,
3232 error.WriteFailed => return dwarf.reportWriteError(di_nw),
3233 };
3234}
3235fn genDeclInner(
3236 dwarf: *Dwarf,
3237 pt: Zcu.PerThread,
3238 di_nw: *link.MappedFile.Node.Writer,
3239 instance_val: InternPool.Index,
3240) link.EmitError!void {
3241 const zcu = pt.zcu;
3242 const ip = &zcu.intern_pool;
3243 const di_w = &di_nw.interface;
3244 done: {
3245 const kind: enum { @"struct", @"union", @"enum" }, const zf, const src_line, const src_column, const capture_names, const captures, const name, const maybe_name_nav, const namespace = container: switch (ip.indexToKey(instance_val)) {
3246 else => unreachable,
3247 .struct_type => {
3248 const loaded_struct = ip.loadStructType(instance_val);
3249 const src_inst = loaded_struct.zir_index.resolveFull(ip) orelse {
3250 try dwarf.lostTracking(di_nw);
3251 break :done;
3252 };
3253 const zf = zcu.fileByIndex(src_inst.file);
3254 const inst = zf.zir.?.instructions.get(@backingInt(src_inst.inst));
3255 const src_line, const src_column, const capture_names = decl: switch (inst.tag) {
3256 else => unreachable,
3257 .struct_init, .struct_init_ref => {
3258 const decl = zf.zir.?.extraData(
3259 std.zig.Zir.Inst.StructInit,
3260 inst.data.pl_node.payload_index,
3261 ).data;
3262 break :decl .{ decl.src_line, decl.src_column, &.{} };
3263 },
3264 .struct_init_anon => {
3265 const decl = zf.zir.?.extraData(
3266 std.zig.Zir.Inst.StructInitAnon,
3267 inst.data.pl_node.payload_index,
3268 ).data;
3269 break :decl .{ decl.src_line, decl.src_column, &.{} };
3270 },
3271 .extended => switch (inst.data.extended.opcode) {
3272 else => unreachable,
3273 .struct_decl => {
3274 const decl = zf.zir.?.getStructDecl(src_inst.inst);
3275 break :decl .{ decl.src_line, decl.src_column, decl.capture_names };
3276 },
3277 .reify_struct => {
3278 const decl = zf.zir.?.extraData(
3279 std.zig.Zir.Inst.ReifyStruct,
3280 inst.data.extended.operand,
3281 ).data;
3282 break :decl .{ decl.src_line, decl.src_column, &.{} };
3283 },
3284 },
3285 };
3286 break :container .{
3287 .@"struct",
3288 zf,
3289 src_line,
3290 src_column,
3291 capture_names,
3292 loaded_struct.captures,
3293 loaded_struct.name,
3294 loaded_struct.name_nav,
3295 loaded_struct.namespace,
3296 };
3297 },
3298 .union_type => {
3299 const loaded_union = ip.loadUnionType(instance_val);
3300 const src_inst = loaded_union.zir_index.resolveFull(ip) orelse {
3301 try dwarf.lostTracking(di_nw);
3302 break :done;
3303 };
3304 const zf = zcu.fileByIndex(src_inst.file);
3305 const inst = zf.zir.?.instructions.get(@backingInt(src_inst.inst));
3306 const src_line, const src_column, const capture_names = decl: switch (inst.tag) {
3307 else => unreachable,
3308 .extended => switch (inst.data.extended.opcode) {
3309 else => unreachable,
3310 .union_decl => {
3311 const decl = zf.zir.?.getUnionDecl(src_inst.inst);
3312 break :decl .{ decl.src_line, decl.src_column, decl.capture_names };
3313 },
3314 .reify_union => {
3315 const decl = zf.zir.?.extraData(
3316 std.zig.Zir.Inst.ReifyUnion,
3317 inst.data.extended.operand,
3318 ).data;
3319 break :decl .{ decl.src_line, decl.src_column, &.{} };
3320 },
3321 },
3322 };
3323 break :container .{
3324 .@"union",
3325 zf,
3326 src_line,
3327 src_column,
3328 capture_names,
3329 loaded_union.captures,
3330 loaded_union.name,
3331 loaded_union.name_nav,
3332 loaded_union.namespace,
3333 };
3334 },
3335 .enum_type => {
3336 const loaded_enum = ip.loadEnumType(instance_val);
3337 const src_inst = loaded_enum.zir_index.unwrap().?.resolveFull(ip) orelse {
3338 try dwarf.lostTracking(di_nw);
3339 break :done;
3340 };
3341 const zf = zcu.fileByIndex(src_inst.file);
3342 const inst = zf.zir.?.instructions.get(@backingInt(src_inst.inst));
3343 const src_line, const src_column, const capture_names = decl: switch (inst.tag) {
3344 else => unreachable,
3345 .extended => switch (inst.data.extended.opcode) {
3346 else => unreachable,
3347 .enum_decl => {
3348 const decl = zf.zir.?.getEnumDecl(src_inst.inst);
3349 break :decl .{ decl.src_line, decl.src_column, decl.capture_names };
3350 },
3351 .reify_enum => {
3352 const decl = zf.zir.?.extraData(
3353 std.zig.Zir.Inst.ReifyEnum,
3354 inst.data.extended.operand,
3355 ).data;
3356 break :decl .{ decl.src_line, decl.src_column, &.{} };
3357 },
3358 },
3359 };
3360 break :container .{
3361 .@"enum",
3362 zf,
3363 src_line,
3364 src_column,
3365 capture_names,
3366 loaded_enum.captures,
3367 loaded_enum.name,
3368 loaded_enum.name_nav,
3369 loaded_enum.namespace,
3370 };
3371 },
3372 .opaque_type => {
3373 const loaded_opaque = ip.loadOpaqueType(instance_val);
3374 const src_inst = loaded_opaque.zir_index.resolveFull(ip) orelse {
3375 try dwarf.lostTracking(di_nw);
3376 break :done;
3377 };
3378 const zf = zcu.fileByIndex(src_inst.file);
3379 const decl = zf.zir.?.getOpaqueDecl(src_inst.inst);
3380 break :container .{
3381 .@"struct",
3382 zf,
3383 decl.src_line,
3384 decl.src_column,
3385 decl.capture_names,
3386 loaded_opaque.captures,
3387 loaded_opaque.name,
3388 loaded_opaque.name_nav,
3389 loaded_opaque.namespace,
3390 };
3391 },
3392 };
3393 if (maybe_name_nav.unwrap()) |name_ni| {
3394 const name_nav = ip.getNav(name_ni);
3395 const decl = zf.zir.?.getDeclaration(name_nav.srcInst(ip).resolve(ip).?);
3396 const parent_ni = try dwarf.getDecl(pt, ip.namespacePtr(
3397 name_nav.analysis.?.namespace,
3398 ).owner_type);
3399 try dwarf.abbrevCode(di_nw, if (captures.len > 0) switch (kind) {
3400 .@"struct" => .decl_specification_struct,
3401 .@"union" => .decl_specification_union,
3402 .@"enum" => .decl_specification_enum,
3403 } else switch (kind) {
3404 .@"struct" => .decl_specification_empty_struct,
3405 .@"union" => .decl_specification_empty_union,
3406 .@"enum" => .decl_specification_empty_enum,
3407 });
3408 try dwarf.secOffset(di_nw, parent_ni, 0);
3409 try di_w.writeInt(u32, decl.src_line + 1, dwarf.endian);
3410 try di_w.writeUleb128(decl.src_column + 1);
3411 try di_w.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
3412 try dwarf.strp(&dwarf.debug_str, di_nw, name.toSlice(ip));
3413 } else {
3414 const parent_ni = try dwarf.getDecl(pt, ip.namespacePtr(
3415 ip.namespacePtr(namespace).parent.unwrap().?,
3416 ).owner_type);
3417 try dwarf.abbrevCode(di_nw, if (captures.len > 0) switch (kind) {
3418 .@"struct" => .type_decl_specification_struct,
3419 .@"union" => .type_decl_specification_union,
3420 .@"enum" => .type_decl_specification_enum,
3421 } else switch (kind) {
3422 .@"struct" => .type_decl_specification_empty_struct,
3423 .@"union" => .type_decl_specification_empty_union,
3424 .@"enum" => .type_decl_specification_empty_enum,
3425 });
3426 try dwarf.secOffset(di_nw, parent_ni, 0);
3427 try di_w.writeInt(u32, src_line + 1, dwarf.endian);
3428 try di_w.writeUleb128(src_column + 1);
3429 try dwarf.strp(&dwarf.debug_str, di_nw, name.toSlice(ip));
3430 }
3431 for (capture_names, captures.get(ip)) |capture_name, capture| {
3432 try dwarf.abbrevCode(di_nw, .capture_specification);
3433 switch (capture.unwrap()) {
3434 .@"comptime", .runtime, .nav_val => try dwarf.strp(
3435 &dwarf.debug_str,
3436 di_nw,
3437 zf.zir.?.nullTerminatedString(capture_name),
3438 ),
3439 .nav_ref => {
3440 const capture_name_slice = try zcu.gpa.print("&{s}", .{
3441 zf.zir.?.nullTerminatedString(capture_name),
3442 });
3443 defer zcu.gpa.free(capture_name_slice);
3444 try dwarf.strp(&dwarf.debug_str, di_nw, capture_name_slice);
3445 },
3446 }
3447 }
3448 if (captures.len > 0) try di_w.writeUleb128(@backingInt(AbbrevCode.null));
3449 }
3450 try dwarf.genDebugInfoPadding(di_w, di_w.unusedCapacityLen());
3451}
3452
3453pub fn updateLineNumber(
3454 dwarf: *Dwarf,
3455 mf: *link.MappedFile,
3456 inst: InternPool.TrackedInst.Index,
3457 line: u32,
3458) void {
3459 const di = dwarf.getDeclIfExists(inst) orelse return;
3460 const decl_ni = di.get(dwarf).debug_info_ni.unwrap().?;
3461 std.mem.writeInt(
3462 u32,
3463 decl_ni.slice(mf)[AbbrevCode.decl_size..][0..4],
3464 line + 1,
3465 dwarf.endian,
3466 );
3467}
3468
3469pub fn lostTracking(dwarf: *Dwarf, di_nw: *link.MappedFile.Node.Writer) link.EmitError!void {
3470 try dwarf.abbrevCode(di_nw, .decl_lost);
3471}
3472
3473fn refAbbrevCodeIfExists(
3474 dwarf: *Dwarf,
3475 abbrev_code: AbbrevCode,
3476) ?@typeInfo(AbbrevCode).@"enum".tag_type {
3477 assert(abbrev_code != .null);
3478 return if (dwarf.debug_abbrev.set.contains(abbrev_code)) @backingInt(abbrev_code) else null;
3479}
3480fn refAbbrevCode(
3481 dwarf: *Dwarf,
3482 mf: *link.MappedFile,
3483 abbrev_code: AbbrevCode,
3484) link.Error!@typeInfo(AbbrevCode).@"enum".tag_type {
3485 if (dwarf.refAbbrevCodeIfExists(abbrev_code)) |backing_int| {
3486 @branchHint(.likely);
3487 return backing_int;
3488 }
3489 var da_nw: link.MappedFile.Node.Writer = undefined;
3490 dwarf.debug_abbrev.ni.unwrap().?.writer(dwarf.lf.comp.gpa, mf, &da_nw);
3491 defer da_nw.deinit();
3492 dwarf.genDebugAbbrev(&da_nw, abbrev_code) catch |err| switch (err) {
3493 else => |e| return e,
3494 error.WriteFailed => return dwarf.reportWriteError(&da_nw),
3495 };
3496 dwarf.debug_abbrev.set.insert(abbrev_code);
3497 return dwarf.refAbbrevCodeIfExists(abbrev_code).?;
3498}
3499fn abbrevCode(
3500 dwarf: *Dwarf,
3501 nw: *link.MappedFile.Node.Writer,
3502 abbrev_code: AbbrevCode,
3503) link.EmitError!void {
3504 try nw.interface.writeUleb128(try dwarf.refAbbrevCode(nw.mf, abbrev_code));
3505}
3506
3507fn genDebugAbbrev(
3508 dwarf: *Dwarf,
3509 da_nw: *link.MappedFile.Node.Writer,
3510 abbrev_code: AbbrevCode,
3511) link.EmitError!void {
3512 const abbrev = AbbrevCode.abbrevs.get(abbrev_code);
3513 const da_w = &da_nw.interface;
3514 da_w.end = dwarf.debug_abbrev.end;
3515 try da_w.writeUleb128(@backingInt(abbrev_code));
3516 try da_w.writeUleb128(@backingInt(abbrev.tag));
3517 try da_w.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no);
3518 for (abbrev.attrs) |*attr| {
3519 try da_w.writeUleb128(@backingInt(switch (attr[0]) {
3520 else => |at| at,
3521 .ZIG_call_line_relative => |at| if (dwarf.lf.comp.config.incremental) at else .call_line,
3522 }));
3523 try da_w.writeUleb128(@backingInt(attr[1]));
3524 }
3525 for (0..2) |_| try da_w.writeUleb128(0);
3526 dwarf.debug_abbrev.end = da_w.end;
3527}
3528
3529pub fn secOffsetSize(dwarf: *Dwarf) usize {
3530 return switch (dwarf.format) {
3531 .@"32" => 4,
3532 .@"64" => 8,
3533 };
3534}
3535fn secOffsetPlaceholder(dwarf: *Dwarf, w: *std.Io.Writer) std.Io.Writer.Error!void {
3536 @memset(try w.writableSlice(dwarf.secOffsetSize()), undefined);
3537}
3538fn secOffset(
3539 dwarf: *Dwarf,
3540 nw: *link.MappedFile.Node.Writer,
3541 target_ni: link.MappedFile.Node.Index,
3542 addend: usize,
3543) link.EmitError!void {
3544 const offset = nw.interface.end;
3545 try dwarf.secOffsetPlaceholder(&nw.interface);
3546 if (dwarf.lf.cast(.elf2)) |elf| try elf.addNodeReloc(
3547 nw.ni,
3548 offset,
3549 target_ni,
3550 @bitCast(@as(u64, addend)),
3551 switch (dwarf.format) {
3552 .@"32" => .abs32,
3553 .@"64" => .abs64,
3554 },
3555 ) else unreachable;
3556}
3557
3558fn addrPlaceholder(dwarf: *Dwarf, w: *std.Io.Writer) std.Io.Writer.Error!void {
3559 @memset(try w.writableSlice(@backingInt(dwarf.address_size)), undefined);
3560}
3561fn addrSym(
3562 dwarf: *Dwarf,
3563 nw: *link.MappedFile.Node.Writer,
3564 target_si: link.File.SymbolId,
3565 addend: usize,
3566) link.EmitError!void {
3567 const offset = nw.interface.end;
3568 try dwarf.addrPlaceholder(&nw.interface);
3569 if (dwarf.lf.cast(.elf2)) |elf| try elf.addReloc(
3570 @bitCast(nw.ni),
3571 offset,
3572 target_si,
3573 @bitCast(@as(u64, addend)),
3574 .absAddr(elf),
3575 ) else unreachable;
3576}
3577
3578fn blockConst(
3579 dwarf: *Dwarf,
3580 pt: Zcu.PerThread,
3581 nw: *link.MappedFile.Node.Writer,
3582 val: Value,
3583) link.EmitError!void {
3584 const ty = val.typeOf(pt.zcu);
3585 const size = ty.abiSize(pt.zcu);
3586 try nw.interface.writeUleb128(size);
3587 const start = nw.interface.end;
3588 if (size > 0) try codegen.generateSymbol(
3589 dwarf.lf,
3590 pt,
3591 val,
3592 &nw.interface,
3593 .{ .atom_index = @bitCast(nw.ni) },
3594 );
3595 assert(start + size == nw.interface.end);
3596}
3597
3598fn refType(
3599 dwarf: *Dwarf,
3600 pt: Zcu.PerThread,
3601 nw: *link.MappedFile.Node.Writer,
3602 ty: Type,
3603) link.EmitError!void {
3604 return dwarf.refConst(pt, nw, ty.toValue());
3605}
3606fn refConst(
3607 dwarf: *Dwarf,
3608 pt: Zcu.PerThread,
3609 nw: *link.MappedFile.Node.Writer,
3610 val: Value,
3611) link.EmitError!void {
3612 try dwarf.secOffset(nw, Const.get(try dwarf.getConst(pt, val), dwarf).debug_info_ni.unwrap().?, 0);
3613}
3614
3615fn bigIntConstValue(
3616 dwarf: *Dwarf,
3617 di_w: *std.Io.Writer,
3618 ty: Type,
3619 big_int: std.math.big.int.Const,
3620) link.EmitError!void {
3621 const zcu = dwarf.lf.comp.zcu.?;
3622 const signedness = switch (ty.toIntern()) {
3623 .comptime_int_type => .signed,
3624 else => ty.intInfo(zcu).signedness,
3625 };
3626 const bits = @max(1, big_int.bitCountTwosCompForSignedness(signedness));
3627 if (bits <= 64) {
3628 try di_w.writeUleb128(@as(u13, switch (signedness) {
3629 .signed => DW.FORM.sdata,
3630 .unsigned => DW.FORM.udata,
3631 }));
3632 var bit: usize = 0;
3633 var carry: u1 = 1;
3634 for (try di_w.writableSlice(@divCeil(bits, 7))) |*byte| {
3635 const limb_bits = @typeInfo(std.math.big.Limb).int.bits;
3636 const limb_index = bit / limb_bits;
3637 const limb_shift: std.math.Log2Int(std.math.big.Limb) = @intCast(bit % limb_bits);
3638 const low_abs_part: u7 = @truncate(big_int.limbs[limb_index] >> limb_shift);
3639 const abs_part = if (limb_shift > limb_bits - 7 and
3640 limb_index + 1 < big_int.limbs.len)
3641 abs_part: {
3642 const high_abs_part: u7 = @truncate(big_int.limbs[limb_index + 1] << -%limb_shift);
3643 break :abs_part high_abs_part | low_abs_part;
3644 } else low_abs_part;
3645 const twos_comp_part = if (big_int.positive) abs_part else twos_comp_part: {
3646 const twos_comp_part, carry = @addWithOverflow(~abs_part, carry);
3647 break :twos_comp_part twos_comp_part;
3648 };
3649 bit += 7;
3650 byte.* = @as(u8, if (bit < bits) 0x80 else 0x00) | twos_comp_part;
3651 }
3652 } else {
3653 try di_w.writeUleb128(DW.FORM.block);
3654 const size = switch (ty.toIntern()) {
3655 .comptime_int_type => @divCeil(bits, 8),
3656 else => ty.abiSize(zcu),
3657 };
3658 try di_w.writeUleb128(size);
3659 big_int.writeTwosComplement(try di_w.writableSlice(@intCast(size)), dwarf.endian);
3660 }
3661}
3662
3663fn enumConstValue(
3664 dwarf: *Dwarf,
3665 di_w: *std.Io.Writer,
3666 loaded_enum: InternPool.LoadedEnumType,
3667 field_index: usize,
3668) link.EmitError!void {
3669 const zcu = dwarf.lf.comp.zcu.?;
3670 var big_int_space: Value.BigIntSpace = undefined;
3671 try dwarf.bigIntConstValue(
3672 di_w,
3673 .fromInterned(loaded_enum.int_tag_type),
3674 if (loaded_enum.field_values.len > 0)
3675 Value.fromInterned(loaded_enum.field_values.get(&zcu.intern_pool)[field_index])
3676 .toBigInt(&big_int_space, zcu)
3677 else
3678 std.math.big.int.Mutable.init(&big_int_space.limbs, field_index).toConst(),
3679 );
3680}
3681
3682fn exprLoc(dwarf: *Dwarf, nw: *link.MappedFile.Node.Writer, loc: Loc) link.EmitError!void {
3683 var buf: [@max(8, std.atomic.cache_line)]u8 = undefined;
3684 var dw: std.Io.Writer.Discarding = .init(&buf);
3685 try loc.write(.{ .io = &dw.writer }, dwarf);
3686
3687 try nw.interface.writeUleb128(dw.fullCount());
3688 try loc.write(.{ .mf = nw }, dwarf);
3689}
3690
3691fn strp(dwarf: *Dwarf, s: *Str, nw: *link.MappedFile.Node.Writer, str: []const u8) link.EmitError!void {
3692 const comp = dwarf.lf.comp;
3693 try dwarf.secOffset(nw, s.ni.unwrap().?, s.get(comp.gpa, nw.mf, str) catch |err| switch (err) {
3694 error.MappedFileIo => return comp.link_diags.fail("failed to write output file: {t}", .{
3695 nw.mf.io_err.?,
3696 }),
3697 else => |e| return e,
3698 });
3699}
3700
3701fn reportWriteError(dwarf: *Dwarf, nw: *const link.MappedFile.Node.Writer) link.Error {
3702 switch (nw.err.?) {
3703 else => |e| return e,
3704 error.MappedFileIo => return dwarf.lf.comp.link_diags.fail(
3705 "failed to write output file: {t}",
3706 .{nw.mf.io_err.?},
3707 ),
3708 }
3709}
3710
3711fn constPoolUser(dwarf: *Dwarf) link.ConstPool.User {
3712 return if (dwarf.lf.cast(.elf2)) |elf| .{
3713 .elf2 = elf,
3714 } else unreachable;
3715}
3716
3717fn DeclValEnum(comptime T: type) type {
3718 const decl_names = @typeInfo(T).@"struct".decl_names;
3719 @setEvalBranchQuota(10 * decl_names.len);
3720 var field_names: [decl_names.len][]const u8 = undefined;
3721 var fields_len = 0;
3722 var min_value: ?comptime_int = null;
3723 var max_value: ?comptime_int = null;
3724 for (decl_names) |decl_name| {
3725 if (std.mem.startsWith(u8, decl_name, "HP_") or
3726 std.mem.endsWith(u8, decl_name, "_user")) continue;
3727 const value = @field(T, decl_name);
3728 field_names[fields_len] = decl_name;
3729 fields_len += 1;
3730 if (min_value == null or min_value.? > value) min_value = value;
3731 if (max_value == null or max_value.? < value) max_value = value;
3732 }
3733 if (fields_len == 0) return enum {};
3734 const TagInt = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0);
3735 var field_vals: [fields_len]TagInt = undefined;
3736 for (field_names[0..fields_len], &field_vals) |name, *val| val.* = @field(T, name);
3737 return @Enum(TagInt, .exhaustive, field_names[0..fields_len], &field_vals);
3738}
3739
3740pub const AbbrevCode = enum {
3741 null,
3742 // padding codes must be one byte uleb128 values to function
3743 pad_1,
3744 pad_n,
3745 // decl, specification, and instance codes are assumed to all have the same uleb128 size
3746 decl_lost,
3747 decl_alias,
3748 decl_empty_incomplete_enum,
3749 decl_incomplete_enum,
3750 decl_empty_enum,
3751 decl_enum,
3752 type_decl_empty_incomplete_enum,
3753 type_decl_incomplete_enum,
3754 type_decl_empty_enum,
3755 type_decl_enum,
3756 decl_empty_incomplete_struct,
3757 decl_incomplete_struct,
3758 decl_empty_struct,
3759 decl_struct,
3760 type_decl_empty_incomplete_struct,
3761 type_decl_incomplete_struct,
3762 type_decl_empty_struct,
3763 type_decl_struct,
3764 decl_empty_packed_struct,
3765 decl_packed_struct,
3766 type_decl_empty_packed_struct,
3767 type_decl_packed_struct,
3768 decl_empty_incomplete_union,
3769 decl_incomplete_union,
3770 decl_empty_union,
3771 decl_union,
3772 type_decl_empty_incomplete_union,
3773 type_decl_incomplete_union,
3774 type_decl_empty_union,
3775 type_decl_union,
3776 decl_empty_packed_union,
3777 decl_packed_union,
3778 type_decl_empty_packed_union,
3779 type_decl_packed_union,
3780 decl_var,
3781 decl_const,
3782 decl_const_runtime_bits,
3783 decl_const_comptime_state,
3784 decl_const_runtime_bits_comptime_state,
3785 decl_nullary_func,
3786 decl_func,
3787 decl_nullary_func_generic,
3788 decl_func_generic,
3789 decl_extern_nullary_func,
3790 decl_extern_func,
3791 decl_specification_empty_struct,
3792 decl_specification_struct,
3793 type_decl_specification_empty_struct,
3794 type_decl_specification_struct,
3795 decl_specification_empty_enum,
3796 decl_specification_enum,
3797 type_decl_specification_empty_enum,
3798 type_decl_specification_enum,
3799 decl_specification_empty_union,
3800 decl_specification_union,
3801 type_decl_specification_empty_union,
3802 type_decl_specification_union,
3803 decl_specification_func,
3804 decl_instance_alias,
3805 decl_instance_empty_incomplete_enum,
3806 decl_instance_incomplete_enum,
3807 decl_instance_empty_enum,
3808 decl_instance_enum,
3809 decl_instance_empty_incomplete_struct,
3810 decl_instance_incomplete_struct,
3811 decl_instance_empty_struct,
3812 decl_instance_struct,
3813 decl_instance_empty_packed_struct,
3814 decl_instance_packed_struct,
3815 decl_instance_empty_incomplete_union,
3816 decl_instance_incomplete_union,
3817 decl_instance_empty_union,
3818 decl_instance_union,
3819 decl_instance_empty_packed_union,
3820 decl_instance_packed_union,
3821 decl_instance_var,
3822 decl_instance_const,
3823 decl_instance_const_runtime_bits,
3824 decl_instance_const_comptime_state,
3825 decl_instance_const_runtime_bits_comptime_state,
3826 decl_instance_nullary_func,
3827 decl_instance_func,
3828 decl_instance_nullary_func_generic,
3829 decl_instance_func_generic,
3830 decl_instance_extern_nullary_func,
3831 decl_instance_extern_func,
3832 // the rest are unrestricted other than empty variants must not be longer
3833 // than the non-empty variant, and so should appear first
3834 compile_unit,
3835 module,
3836 module_dependency,
3837 empty_file,
3838 file,
3839 access,
3840 enum_field,
3841 generated_field,
3842 field,
3843 field_default_fully_runtime,
3844 field_default_partially_comptime,
3845 field_default_fully_comptime,
3846 field_comptime,
3847 field_comptime_fully_runtime,
3848 field_comptime_partially_comptime,
3849 field_comptime_fully_comptime,
3850 packed_field,
3851 tagged_union,
3852 tagged_union_field,
3853 tagged_union_default_field,
3854 void_type,
3855 numeric_type,
3856 inferred_error_set_type,
3857 ptr_type,
3858 ptr_sentinel_type,
3859 ptr_aligned_type,
3860 ptr_aligned_sentinel_type,
3861 is_const,
3862 is_volatile,
3863 array_type,
3864 array_sentinel_type,
3865 vector_type,
3866 array_index,
3867 array_len,
3868 nullary_func_type,
3869 func_type,
3870 param,
3871 unnamed_param,
3872 is_var_args,
3873 generated_empty_enum_type,
3874 generated_enum_type,
3875 generated_empty_struct_type,
3876 generated_struct_type,
3877 generated_union_type,
3878 capture_specification,
3879 comptime_capture,
3880 comptime_capture_runtime,
3881 comptime_capture_partially_comptime,
3882 comptime_capture_fully_comptime,
3883 runtime_capture,
3884 nav_capture,
3885 builtin_extern_nullary_func,
3886 builtin_extern_func,
3887 builtin_extern_var,
3888 empty_block,
3889 block,
3890 empty_inlined_func,
3891 inlined_func,
3892 arg,
3893 unnamed_arg,
3894 comptime_arg,
3895 comptime_arg_fully_runtime,
3896 comptime_arg_partially_comptime,
3897 comptime_arg_fully_comptime,
3898 unnamed_comptime_arg,
3899 unnamed_comptime_arg_fully_runtime,
3900 unnamed_comptime_arg_partially_comptime,
3901 unnamed_comptime_arg_fully_comptime,
3902 extern_param,
3903 local_var,
3904 local_const,
3905 local_const_fully_runtime,
3906 local_const_partially_comptime,
3907 local_const_fully_comptime,
3908 undefined_comptime_value,
3909 comptime_value,
3910 location_comptime_value,
3911 aggregate_undefined_comptime_value,
3912 aggregate_comptime_value,
3913 aggregate_location_comptime_value,
3914 comptime_value_field_runtime_bits,
3915 comptime_value_field_comptime_state,
3916 comptime_value_elem_runtime_bits,
3917 comptime_value_elem_comptime_state,
3918
3919 const decl_size = uleb128Size(@backingInt(AbbrevCode.decl_instance_extern_func));
3920 comptime {
3921 assert(uleb128Size(@backingInt(AbbrevCode.pad_1)) == 1);
3922 assert(uleb128Size(@backingInt(AbbrevCode.pad_n)) == 1);
3923 assert(uleb128Size(@backingInt(AbbrevCode.decl_alias)) == decl_size);
3924 }
3925
3926 const Attr = struct {
3927 DeclValEnum(DW.AT),
3928 DeclValEnum(DW.FORM),
3929 };
3930 const decl_attrs = &[_]Attr{
3931 .{ .ZIG_parent, .ref_addr },
3932 .{ .decl_line, .data4 },
3933 .{ .decl_column, .udata },
3934 .{ .accessibility, .data1 },
3935 .{ .name, .strp },
3936 };
3937 const type_decl_attrs = &[_]Attr{
3938 .{ .ZIG_parent, .ref_addr },
3939 .{ .decl_line, .data4 },
3940 .{ .decl_column, .udata },
3941 .{ .name, .strp },
3942 };
3943 const decl_specification_attrs = decl_attrs ++ &[_]Attr{
3944 .{ .declaration, .flag_present },
3945 };
3946 const type_decl_specification_attrs = type_decl_attrs ++ &[_]Attr{
3947 .{ .declaration, .flag_present },
3948 };
3949 const decl_instance_attrs = &[_]Attr{
3950 .{ .specification, .ref_addr },
3951 };
3952
3953 const abbrevs = std.EnumArray(AbbrevCode, struct {
3954 tag: DeclValEnum(DW.TAG),
3955 children: bool = false,
3956 attrs: []const Attr = &.{},
3957 }).init(.{
3958 .null = undefined,
3959 .pad_1 = .{
3960 .tag = .ZIG_padding,
3961 },
3962 .pad_n = .{
3963 .tag = .ZIG_padding,
3964 .attrs = &.{
3965 .{ .ZIG_padding, .block },
3966 },
3967 },
3968 .decl_lost = .{
3969 .tag = .ZIG_lost_declaration,
3970 },
3971 .decl_alias = .{
3972 .tag = .imported_declaration,
3973 .attrs = decl_attrs ++ .{
3974 .{ .import, .ref_addr },
3975 },
3976 },
3977 .decl_empty_incomplete_enum = .{
3978 .tag = .enumeration_type,
3979 .attrs = decl_attrs,
3980 },
3981 .decl_incomplete_enum = .{
3982 .tag = .enumeration_type,
3983 .children = true,
3984 .attrs = decl_attrs,
3985 },
3986 .decl_empty_enum = .{
3987 .tag = .enumeration_type,
3988 .attrs = decl_attrs ++ .{
3989 .{ .type, .ref_addr },
3990 },
3991 },
3992 .decl_enum = .{
3993 .tag = .enumeration_type,
3994 .children = true,
3995 .attrs = decl_attrs ++ .{
3996 .{ .type, .ref_addr },
3997 },
3998 },
3999 .type_decl_empty_incomplete_enum = .{
4000 .tag = .enumeration_type,
4001 .attrs = type_decl_attrs,
4002 },
4003 .type_decl_incomplete_enum = .{
4004 .tag = .enumeration_type,
4005 .children = true,
4006 .attrs = type_decl_attrs,
4007 },
4008 .type_decl_empty_enum = .{
4009 .tag = .enumeration_type,
4010 .attrs = type_decl_attrs ++ .{
4011 .{ .type, .ref_addr },
4012 },
4013 },
4014 .type_decl_enum = .{
4015 .tag = .enumeration_type,
4016 .children = true,
4017 .attrs = type_decl_attrs ++ .{
4018 .{ .type, .ref_addr },
4019 },
4020 },
4021 .decl_empty_incomplete_struct = .{
4022 .tag = .structure_type,
4023 .attrs = decl_attrs,
4024 },
4025 .decl_incomplete_struct = .{
4026 .tag = .structure_type,
4027 .children = true,
4028 .attrs = decl_attrs,
4029 },
4030 .decl_empty_struct = .{
4031 .tag = .structure_type,
4032 .attrs = decl_attrs ++ .{
4033 .{ .byte_size, .udata },
4034 .{ .alignment, .udata },
4035 },
4036 },
4037 .decl_struct = .{
4038 .tag = .structure_type,
4039 .children = true,
4040 .attrs = decl_attrs ++ .{
4041 .{ .byte_size, .udata },
4042 .{ .alignment, .udata },
4043 },
4044 },
4045 .type_decl_empty_incomplete_struct = .{
4046 .tag = .structure_type,
4047 .attrs = type_decl_attrs,
4048 },
4049 .type_decl_incomplete_struct = .{
4050 .tag = .structure_type,
4051 .children = true,
4052 .attrs = type_decl_attrs,
4053 },
4054 .type_decl_empty_struct = .{
4055 .tag = .structure_type,
4056 .attrs = type_decl_attrs ++ .{
4057 .{ .byte_size, .udata },
4058 .{ .alignment, .udata },
4059 },
4060 },
4061 .type_decl_struct = .{
4062 .tag = .structure_type,
4063 .children = true,
4064 .attrs = type_decl_attrs ++ .{
4065 .{ .byte_size, .udata },
4066 .{ .alignment, .udata },
4067 },
4068 },
4069 .decl_empty_packed_struct = .{
4070 .tag = .structure_type,
4071 .attrs = decl_attrs ++ .{
4072 .{ .type, .ref_addr },
4073 },
4074 },
4075 .decl_packed_struct = .{
4076 .tag = .structure_type,
4077 .children = true,
4078 .attrs = decl_attrs ++ .{
4079 .{ .type, .ref_addr },
4080 },
4081 },
4082 .type_decl_empty_packed_struct = .{
4083 .tag = .structure_type,
4084 .attrs = type_decl_attrs ++ .{
4085 .{ .type, .ref_addr },
4086 },
4087 },
4088 .type_decl_packed_struct = .{
4089 .tag = .structure_type,
4090 .children = true,
4091 .attrs = type_decl_attrs ++ .{
4092 .{ .type, .ref_addr },
4093 },
4094 },
4095 .decl_empty_incomplete_union = .{
4096 .tag = .union_type,
4097 .attrs = decl_attrs,
4098 },
4099 .decl_incomplete_union = .{
4100 .tag = .union_type,
4101 .children = true,
4102 .attrs = decl_attrs,
4103 },
4104 .decl_empty_union = .{
4105 .tag = .union_type,
4106 .attrs = decl_attrs ++ .{
4107 .{ .byte_size, .udata },
4108 .{ .alignment, .udata },
4109 },
4110 },
4111 .decl_union = .{
4112 .tag = .union_type,
4113 .children = true,
4114 .attrs = decl_attrs ++ .{
4115 .{ .byte_size, .udata },
4116 .{ .alignment, .udata },
4117 },
4118 },
4119 .type_decl_empty_incomplete_union = .{
4120 .tag = .union_type,
4121 .attrs = type_decl_attrs,
4122 },
4123 .type_decl_incomplete_union = .{
4124 .tag = .union_type,
4125 .children = true,
4126 .attrs = type_decl_attrs,
4127 },
4128 .type_decl_empty_union = .{
4129 .tag = .union_type,
4130 .attrs = type_decl_attrs ++ .{
4131 .{ .byte_size, .udata },
4132 .{ .alignment, .udata },
4133 },
4134 },
4135 .type_decl_union = .{
4136 .tag = .union_type,
4137 .children = true,
4138 .attrs = type_decl_attrs ++ .{
4139 .{ .byte_size, .udata },
4140 .{ .alignment, .udata },
4141 },
4142 },
4143 .decl_empty_packed_union = .{
4144 .tag = .union_type,
4145 .attrs = decl_attrs ++ .{
4146 .{ .type, .ref_addr },
4147 },
4148 },
4149 .decl_packed_union = .{
4150 .tag = .union_type,
4151 .children = true,
4152 .attrs = decl_attrs ++ .{
4153 .{ .type, .ref_addr },
4154 },
4155 },
4156 .type_decl_empty_packed_union = .{
4157 .tag = .union_type,
4158 .attrs = type_decl_attrs ++ .{
4159 .{ .type, .ref_addr },
4160 },
4161 },
4162 .type_decl_packed_union = .{
4163 .tag = .union_type,
4164 .children = true,
4165 .attrs = type_decl_attrs ++ .{
4166 .{ .type, .ref_addr },
4167 },
4168 },
4169 .decl_var = .{
4170 .tag = .variable,
4171 .attrs = decl_attrs ++ .{
4172 .{ .linkage_name, .strp },
4173 .{ .type, .ref_addr },
4174 .{ .location, .exprloc },
4175 .{ .alignment, .udata },
4176 .{ .external, .flag },
4177 },
4178 },
4179 .decl_const = .{
4180 .tag = .constant,
4181 .attrs = decl_attrs ++ .{
4182 .{ .linkage_name, .strp },
4183 .{ .type, .ref_addr },
4184 .{ .alignment, .udata },
4185 .{ .external, .flag },
4186 },
4187 },
4188 .decl_const_runtime_bits = .{
4189 .tag = .constant,
4190 .attrs = decl_attrs ++ .{
4191 .{ .linkage_name, .strp },
4192 .{ .type, .ref_addr },
4193 .{ .alignment, .udata },
4194 .{ .external, .flag },
4195 .{ .const_value, .block },
4196 },
4197 },
4198 .decl_const_comptime_state = .{
4199 .tag = .constant,
4200 .attrs = decl_attrs ++ .{
4201 .{ .linkage_name, .strp },
4202 .{ .type, .ref_addr },
4203 .{ .alignment, .udata },
4204 .{ .external, .flag },
4205 .{ .ZIG_comptime_value, .ref_addr },
4206 },
4207 },
4208 .decl_const_runtime_bits_comptime_state = .{
4209 .tag = .constant,
4210 .attrs = decl_attrs ++ .{
4211 .{ .linkage_name, .strp },
4212 .{ .type, .ref_addr },
4213 .{ .alignment, .udata },
4214 .{ .external, .flag },
4215 .{ .const_value, .block },
4216 .{ .ZIG_comptime_value, .ref_addr },
4217 },
4218 },
4219 .decl_nullary_func = .{
4220 .tag = .subprogram,
4221 .attrs = decl_attrs ++ .{
4222 .{ .linkage_name, .strp },
4223 .{ .type, .ref_addr },
4224 .{ .low_pc, .addr },
4225 .{ .high_pc, .data4 },
4226 .{ .alignment, .udata },
4227 .{ .external, .flag },
4228 .{ .noreturn, .flag },
4229 },
4230 },
4231 .decl_func = .{
4232 .tag = .subprogram,
4233 .children = true,
4234 .attrs = decl_attrs ++ .{
4235 .{ .linkage_name, .strp },
4236 .{ .type, .ref_addr },
4237 .{ .low_pc, .addr },
4238 .{ .high_pc, .data4 },
4239 .{ .alignment, .udata },
4240 .{ .external, .flag },
4241 .{ .noreturn, .flag },
4242 },
4243 },
4244 .decl_nullary_func_generic = .{
4245 .tag = .subprogram,
4246 .attrs = decl_attrs ++ .{
4247 .{ .type, .ref_addr },
4248 .{ .noreturn, .flag },
4249 },
4250 },
4251 .decl_func_generic = .{
4252 .tag = .subprogram,
4253 .children = true,
4254 .attrs = decl_attrs ++ .{
4255 .{ .type, .ref_addr },
4256 },
4257 },
4258 .decl_extern_nullary_func = .{
4259 .tag = .subprogram,
4260 .attrs = decl_attrs ++ .{
4261 .{ .linkage_name, .strp },
4262 .{ .type, .ref_addr },
4263 .{ .low_pc, .addr },
4264 .{ .external, .flag_present },
4265 .{ .noreturn, .flag },
4266 },
4267 },
4268 .decl_extern_func = .{
4269 .tag = .subprogram,
4270 .children = true,
4271 .attrs = decl_attrs ++ .{
4272 .{ .linkage_name, .strp },
4273 .{ .type, .ref_addr },
4274 .{ .low_pc, .addr },
4275 .{ .external, .flag_present },
4276 .{ .noreturn, .flag },
4277 },
4278 },
4279 .decl_specification_empty_struct = .{
4280 .tag = .structure_type,
4281 .attrs = decl_specification_attrs,
4282 },
4283 .decl_specification_struct = .{
4284 .tag = .structure_type,
4285 .children = true,
4286 .attrs = decl_specification_attrs,
4287 },
4288 .type_decl_specification_empty_struct = .{
4289 .tag = .structure_type,
4290 .attrs = type_decl_specification_attrs,
4291 },
4292 .type_decl_specification_struct = .{
4293 .tag = .structure_type,
4294 .children = true,
4295 .attrs = type_decl_specification_attrs,
4296 },
4297 .decl_specification_empty_enum = .{
4298 .tag = .enumeration_type,
4299 .attrs = decl_specification_attrs,
4300 },
4301 .decl_specification_enum = .{
4302 .tag = .enumeration_type,
4303 .children = true,
4304 .attrs = decl_specification_attrs,
4305 },
4306 .type_decl_specification_empty_enum = .{
4307 .tag = .enumeration_type,
4308 .attrs = type_decl_specification_attrs,
4309 },
4310 .type_decl_specification_enum = .{
4311 .tag = .enumeration_type,
4312 .children = true,
4313 .attrs = type_decl_specification_attrs,
4314 },
4315 .decl_specification_empty_union = .{
4316 .tag = .union_type,
4317 .attrs = decl_specification_attrs,
4318 },
4319 .decl_specification_union = .{
4320 .tag = .union_type,
4321 .children = true,
4322 .attrs = decl_specification_attrs,
4323 },
4324 .type_decl_specification_empty_union = .{
4325 .tag = .union_type,
4326 .attrs = type_decl_specification_attrs,
4327 },
4328 .type_decl_specification_union = .{
4329 .tag = .union_type,
4330 .children = true,
4331 .attrs = type_decl_specification_attrs,
4332 },
4333 .decl_specification_func = .{
4334 .tag = .subprogram,
4335 .attrs = decl_specification_attrs,
4336 },
4337 .decl_instance_alias = .{
4338 .tag = .imported_declaration,
4339 .attrs = decl_instance_attrs ++ .{
4340 .{ .import, .ref_addr },
4341 },
4342 },
4343 .decl_instance_empty_incomplete_enum = .{
4344 .tag = .enumeration_type,
4345 .attrs = decl_instance_attrs,
4346 },
4347 .decl_instance_incomplete_enum = .{
4348 .tag = .enumeration_type,
4349 .children = true,
4350 .attrs = decl_instance_attrs,
4351 },
4352 .decl_instance_empty_enum = .{
4353 .tag = .enumeration_type,
4354 .attrs = decl_instance_attrs ++ .{
4355 .{ .type, .ref_addr },
4356 },
4357 },
4358 .decl_instance_enum = .{
4359 .tag = .enumeration_type,
4360 .children = true,
4361 .attrs = decl_instance_attrs ++ .{
4362 .{ .type, .ref_addr },
4363 },
4364 },
4365 .decl_instance_empty_incomplete_struct = .{
4366 .tag = .structure_type,
4367 .attrs = decl_instance_attrs,
4368 },
4369 .decl_instance_incomplete_struct = .{
4370 .tag = .structure_type,
4371 .children = true,
4372 .attrs = decl_instance_attrs,
4373 },
4374 .decl_instance_empty_struct = .{
4375 .tag = .structure_type,
4376 .attrs = decl_instance_attrs ++ .{
4377 .{ .byte_size, .udata },
4378 .{ .alignment, .udata },
4379 },
4380 },
4381 .decl_instance_struct = .{
4382 .tag = .structure_type,
4383 .children = true,
4384 .attrs = decl_instance_attrs ++ .{
4385 .{ .byte_size, .udata },
4386 .{ .alignment, .udata },
4387 },
4388 },
4389 .decl_instance_empty_packed_struct = .{
4390 .tag = .structure_type,
4391 .attrs = decl_instance_attrs ++ .{
4392 .{ .type, .ref_addr },
4393 },
4394 },
4395 .decl_instance_packed_struct = .{
4396 .tag = .structure_type,
4397 .children = true,
4398 .attrs = decl_instance_attrs ++ .{
4399 .{ .type, .ref_addr },
4400 },
4401 },
4402 .decl_instance_empty_incomplete_union = .{
4403 .tag = .union_type,
4404 .attrs = decl_instance_attrs,
4405 },
4406 .decl_instance_incomplete_union = .{
4407 .tag = .union_type,
4408 .children = true,
4409 .attrs = decl_instance_attrs,
4410 },
4411 .decl_instance_empty_union = .{
4412 .tag = .union_type,
4413 .attrs = decl_instance_attrs ++ .{
4414 .{ .byte_size, .udata },
4415 .{ .alignment, .udata },
4416 },
4417 },
4418 .decl_instance_union = .{
4419 .tag = .union_type,
4420 .children = true,
4421 .attrs = decl_instance_attrs ++ .{
4422 .{ .byte_size, .udata },
4423 .{ .alignment, .udata },
4424 },
4425 },
4426 .decl_instance_empty_packed_union = .{
4427 .tag = .union_type,
4428 .attrs = decl_instance_attrs ++ .{
4429 .{ .type, .ref_addr },
4430 },
4431 },
4432 .decl_instance_packed_union = .{
4433 .tag = .union_type,
4434 .children = true,
4435 .attrs = decl_instance_attrs ++ .{
4436 .{ .type, .ref_addr },
4437 },
4438 },
4439 .decl_instance_var = .{
4440 .tag = .variable,
4441 .attrs = decl_instance_attrs ++ .{
4442 .{ .linkage_name, .strp },
4443 .{ .type, .ref_addr },
4444 .{ .location, .exprloc },
4445 .{ .alignment, .udata },
4446 .{ .external, .flag },
4447 },
4448 },
4449 .decl_instance_const = .{
4450 .tag = .constant,
4451 .attrs = decl_instance_attrs ++ .{
4452 .{ .linkage_name, .strp },
4453 .{ .type, .ref_addr },
4454 .{ .alignment, .udata },
4455 .{ .external, .flag },
4456 },
4457 },
4458 .decl_instance_const_runtime_bits = .{
4459 .tag = .constant,
4460 .attrs = decl_instance_attrs ++ .{
4461 .{ .linkage_name, .strp },
4462 .{ .type, .ref_addr },
4463 .{ .alignment, .udata },
4464 .{ .external, .flag },
4465 .{ .const_value, .block },
4466 },
4467 },
4468 .decl_instance_const_comptime_state = .{
4469 .tag = .constant,
4470 .attrs = decl_instance_attrs ++ .{
4471 .{ .linkage_name, .strp },
4472 .{ .type, .ref_addr },
4473 .{ .alignment, .udata },
4474 .{ .external, .flag },
4475 .{ .ZIG_comptime_value, .ref_addr },
4476 },
4477 },
4478 .decl_instance_const_runtime_bits_comptime_state = .{
4479 .tag = .constant,
4480 .attrs = decl_instance_attrs ++ .{
4481 .{ .linkage_name, .strp },
4482 .{ .type, .ref_addr },
4483 .{ .alignment, .udata },
4484 .{ .external, .flag },
4485 .{ .const_value, .block },
4486 .{ .ZIG_comptime_value, .ref_addr },
4487 },
4488 },
4489 .decl_instance_nullary_func = .{
4490 .tag = .subprogram,
4491 .attrs = decl_instance_attrs ++ .{
4492 .{ .linkage_name, .strp },
4493 .{ .type, .ref_addr },
4494 .{ .low_pc, .addr },
4495 .{ .high_pc, .data4 },
4496 .{ .alignment, .udata },
4497 .{ .external, .flag },
4498 .{ .noreturn, .flag },
4499 },
4500 },
4501 .decl_instance_func = .{
4502 .tag = .subprogram,
4503 .children = true,
4504 .attrs = decl_instance_attrs ++ .{
4505 .{ .linkage_name, .strp },
4506 .{ .type, .ref_addr },
4507 .{ .low_pc, .addr },
4508 .{ .high_pc, .data4 },
4509 .{ .alignment, .udata },
4510 .{ .external, .flag },
4511 .{ .noreturn, .flag },
4512 },
4513 },
4514 .decl_instance_nullary_func_generic = .{
4515 .tag = .subprogram,
4516 .attrs = decl_instance_attrs ++ .{
4517 .{ .type, .ref_addr },
4518 },
4519 },
4520 .decl_instance_func_generic = .{
4521 .tag = .subprogram,
4522 .children = true,
4523 .attrs = decl_instance_attrs ++ .{
4524 .{ .type, .ref_addr },
4525 },
4526 },
4527 .decl_instance_extern_nullary_func = .{
4528 .tag = .subprogram,
4529 .attrs = decl_instance_attrs ++ .{
4530 .{ .linkage_name, .strp },
4531 .{ .type, .ref_addr },
4532 .{ .low_pc, .addr },
4533 .{ .external, .flag_present },
4534 .{ .noreturn, .flag },
4535 },
4536 },
4537 .decl_instance_extern_func = .{
4538 .tag = .subprogram,
4539 .children = true,
4540 .attrs = decl_instance_attrs ++ .{
4541 .{ .linkage_name, .strp },
4542 .{ .type, .ref_addr },
4543 .{ .low_pc, .addr },
4544 .{ .external, .flag_present },
4545 .{ .noreturn, .flag },
4546 },
4547 },
4548 .compile_unit = .{
4549 .tag = .compile_unit,
4550 .children = true,
4551 .attrs = &.{
4552 .{ .language, .data1 },
4553 .{ .producer, .strp },
4554 .{ .comp_dir, .line_strp },
4555 .{ .name, .line_strp },
4556 .{ .base_types, .ref_addr },
4557 .{ .stmt_list, .sec_offset },
4558 .{ .rnglists_base, .sec_offset },
4559 .{ .ranges, .rnglistx },
4560 .{ .use_UTF8, .flag_present },
4561 },
4562 },
4563 .module = .{
4564 .tag = .module,
4565 .children = true,
4566 .attrs = &.{
4567 .{ .name, .strp },
4568 .{ .ranges, .rnglistx },
4569 },
4570 },
4571 .module_dependency = .{
4572 .tag = .imported_module,
4573 .attrs = &.{
4574 .{ .name, .strp },
4575 .{ .import, .ref_addr },
4576 },
4577 },
4578 .empty_file = .{
4579 .tag = .structure_type,
4580 .attrs = &.{
4581 .{ .decl_file, .udata },
4582 .{ .name, .strp },
4583 .{ .declaration, .flag },
4584 },
4585 },
4586 .file = .{
4587 .tag = .structure_type,
4588 .children = true,
4589 .attrs = &.{
4590 .{ .decl_file, .udata },
4591 .{ .name, .strp },
4592 .{ .byte_size, .udata },
4593 .{ .alignment, .udata },
4594 },
4595 },
4596 .access = .{
4597 .tag = .member,
4598 .attrs = &.{
4599 .{ .name, .strp },
4600 },
4601 },
4602 .enum_field = .{
4603 .tag = .enumerator,
4604 .attrs = &.{
4605 .{ .const_value, .indirect },
4606 .{ .name, .strp },
4607 },
4608 },
4609 .generated_field = .{
4610 .tag = .member,
4611 .attrs = &.{
4612 .{ .name, .strp },
4613 .{ .type, .ref_addr },
4614 .{ .data_member_location, .udata },
4615 .{ .artificial, .flag_present },
4616 },
4617 },
4618 .field = .{
4619 .tag = .member,
4620 .attrs = &.{
4621 .{ .name, .strp },
4622 .{ .type, .ref_addr },
4623 .{ .data_member_location, .udata },
4624 .{ .alignment, .udata },
4625 },
4626 },
4627 .field_default_fully_runtime = .{
4628 .tag = .member,
4629 .attrs = &.{
4630 .{ .name, .strp },
4631 .{ .type, .ref_addr },
4632 .{ .data_member_location, .udata },
4633 .{ .alignment, .udata },
4634 .{ .default_value, .block },
4635 },
4636 },
4637 .field_default_partially_comptime = .{
4638 .tag = .member,
4639 .attrs = &.{
4640 .{ .name, .strp },
4641 .{ .type, .ref_addr },
4642 .{ .data_member_location, .udata },
4643 .{ .alignment, .udata },
4644 .{ .default_value, .block },
4645 .{ .ZIG_comptime_value, .ref_addr },
4646 },
4647 },
4648 .field_default_fully_comptime = .{
4649 .tag = .member,
4650 .attrs = &.{
4651 .{ .name, .strp },
4652 .{ .type, .ref_addr },
4653 .{ .data_member_location, .udata },
4654 .{ .alignment, .udata },
4655 .{ .ZIG_comptime_value, .ref_addr },
4656 },
4657 },
4658 .field_comptime = .{
4659 .tag = .member,
4660 .attrs = &.{
4661 .{ .const_expr, .flag_present },
4662 .{ .name, .strp },
4663 .{ .type, .ref_addr },
4664 },
4665 },
4666 .field_comptime_fully_runtime = .{
4667 .tag = .member,
4668 .attrs = &.{
4669 .{ .const_expr, .flag_present },
4670 .{ .name, .strp },
4671 .{ .type, .ref_addr },
4672 .{ .const_value, .block },
4673 },
4674 },
4675 .field_comptime_partially_comptime = .{
4676 .tag = .member,
4677 .attrs = &.{
4678 .{ .const_expr, .flag_present },
4679 .{ .name, .strp },
4680 .{ .type, .ref_addr },
4681 .{ .const_value, .block },
4682 .{ .ZIG_comptime_value, .ref_addr },
4683 },
4684 },
4685 .field_comptime_fully_comptime = .{
4686 .tag = .member,
4687 .attrs = &.{
4688 .{ .const_expr, .flag_present },
4689 .{ .name, .strp },
4690 .{ .type, .ref_addr },
4691 .{ .ZIG_comptime_value, .ref_addr },
4692 },
4693 },
4694 .packed_field = .{
4695 .tag = .member,
4696 .attrs = &.{
4697 .{ .name, .strp },
4698 .{ .type, .ref_addr },
4699 .{ .data_bit_offset, .udata },
4700 },
4701 },
4702 .tagged_union = .{
4703 .tag = .variant_part,
4704 .children = true,
4705 .attrs = &.{
4706 .{ .discr, .ref_addr },
4707 },
4708 },
4709 .tagged_union_field = .{
4710 .tag = .variant,
4711 .children = true,
4712 .attrs = &.{
4713 .{ .discr_value, .indirect },
4714 },
4715 },
4716 .tagged_union_default_field = .{
4717 .tag = .variant,
4718 .children = true,
4719 },
4720 .void_type = .{
4721 .tag = .unspecified_type,
4722 .attrs = &.{
4723 .{ .name, .strp },
4724 },
4725 },
4726 .numeric_type = .{
4727 .tag = .base_type,
4728 .attrs = &.{
4729 .{ .name, .strp },
4730 .{ .encoding, .data1 },
4731 .{ .bit_size, .udata },
4732 .{ .byte_size, .udata },
4733 .{ .alignment, .udata },
4734 },
4735 },
4736 .inferred_error_set_type = .{
4737 .tag = .typedef,
4738 .attrs = &.{
4739 .{ .name, .strp },
4740 .{ .type, .ref_addr },
4741 },
4742 },
4743 .ptr_type = .{
4744 .tag = .pointer_type,
4745 .attrs = &.{
4746 .{ .name, .strp },
4747 .{ .address_class, .data1 },
4748 .{ .type, .ref_addr },
4749 },
4750 },
4751 .ptr_sentinel_type = .{
4752 .tag = .pointer_type,
4753 .attrs = &.{
4754 .{ .name, .strp },
4755 .{ .ZIG_sentinel, .block },
4756 .{ .address_class, .data1 },
4757 .{ .type, .ref_addr },
4758 },
4759 },
4760 .ptr_aligned_type = .{
4761 .tag = .pointer_type,
4762 .attrs = &.{
4763 .{ .name, .strp },
4764 .{ .alignment, .udata },
4765 .{ .address_class, .data1 },
4766 .{ .type, .ref_addr },
4767 },
4768 },
4769 .ptr_aligned_sentinel_type = .{
4770 .tag = .pointer_type,
4771 .attrs = &.{
4772 .{ .name, .strp },
4773 .{ .ZIG_sentinel, .block },
4774 .{ .alignment, .udata },
4775 .{ .address_class, .data1 },
4776 .{ .type, .ref_addr },
4777 },
4778 },
4779 .is_const = .{
4780 .tag = .const_type,
4781 .attrs = &.{
4782 .{ .type, .ref_addr },
4783 },
4784 },
4785 .is_volatile = .{
4786 .tag = .volatile_type,
4787 .attrs = &.{
4788 .{ .type, .ref_addr },
4789 },
4790 },
4791 .array_type = .{
4792 .tag = .array_type,
4793 .children = true,
4794 .attrs = &.{
4795 .{ .name, .strp },
4796 .{ .type, .ref_addr },
4797 },
4798 },
4799 .array_sentinel_type = .{
4800 .tag = .array_type,
4801 .children = true,
4802 .attrs = &.{
4803 .{ .name, .strp },
4804 .{ .ZIG_sentinel, .block },
4805 .{ .type, .ref_addr },
4806 },
4807 },
4808 .vector_type = .{
4809 .tag = .array_type,
4810 .children = true,
4811 .attrs = &.{
4812 .{ .name, .strp },
4813 .{ .type, .ref_addr },
4814 .{ .GNU_vector, .flag_present },
4815 },
4816 },
4817 .array_index = .{
4818 .tag = .subrange_type,
4819 .attrs = &.{
4820 .{ .lower_bound, .udata },
4821 },
4822 },
4823 .array_len = .{
4824 .tag = .subrange_type,
4825 .attrs = &.{
4826 .{ .type, .ref_addr },
4827 .{ .count, .udata },
4828 },
4829 },
4830 .nullary_func_type = .{
4831 .tag = .subroutine_type,
4832 .attrs = &.{
4833 .{ .name, .strp },
4834 .{ .calling_convention, .data1 },
4835 .{ .type, .ref_addr },
4836 },
4837 },
4838 .func_type = .{
4839 .tag = .subroutine_type,
4840 .children = true,
4841 .attrs = &.{
4842 .{ .name, .strp },
4843 .{ .calling_convention, .data1 },
4844 .{ .type, .ref_addr },
4845 },
4846 },
4847 .param = .{
4848 .tag = .formal_parameter,
4849 .attrs = &.{
4850 .{ .name, .strp },
4851 .{ .type, .ref_addr },
4852 },
4853 },
4854 .unnamed_param = .{
4855 .tag = .formal_parameter,
4856 .attrs = &.{
4857 .{ .type, .ref_addr },
4858 },
4859 },
4860 .is_var_args = .{
4861 .tag = .unspecified_parameters,
4862 },
4863 .generated_empty_enum_type = .{
4864 .tag = .enumeration_type,
4865 .attrs = &.{
4866 .{ .name, .strp },
4867 .{ .type, .ref_addr },
4868 },
4869 },
4870 .generated_enum_type = .{
4871 .tag = .enumeration_type,
4872 .children = true,
4873 .attrs = &.{
4874 .{ .name, .strp },
4875 .{ .type, .ref_addr },
4876 },
4877 },
4878 .generated_empty_struct_type = .{
4879 .tag = .structure_type,
4880 .attrs = &.{
4881 .{ .name, .strp },
4882 .{ .declaration, .flag },
4883 },
4884 },
4885 .generated_struct_type = .{
4886 .tag = .structure_type,
4887 .children = true,
4888 .attrs = &.{
4889 .{ .name, .strp },
4890 .{ .byte_size, .udata },
4891 .{ .alignment, .udata },
4892 },
4893 },
4894 .generated_union_type = .{
4895 .tag = .union_type,
4896 .children = true,
4897 .attrs = &.{
4898 .{ .name, .strp },
4899 .{ .byte_size, .udata },
4900 .{ .alignment, .udata },
4901 },
4902 },
4903 .capture_specification = .{
4904 .tag = .template_value_parameter,
4905 .attrs = &.{
4906 .{ .name, .strp },
4907 },
4908 },
4909 .comptime_capture = .{
4910 .tag = .template_value_parameter,
4911 .attrs = &.{
4912 .{ .type, .ref_addr },
4913 },
4914 },
4915 .comptime_capture_runtime = .{
4916 .tag = .template_value_parameter,
4917 .attrs = &.{
4918 .{ .type, .ref_addr },
4919 .{ .const_value, .block },
4920 },
4921 },
4922 .comptime_capture_partially_comptime = .{
4923 .tag = .template_value_parameter,
4924 .attrs = &.{
4925 .{ .type, .ref_addr },
4926 .{ .const_value, .block },
4927 .{ .ZIG_comptime_value, .ref_addr },
4928 },
4929 },
4930 .comptime_capture_fully_comptime = .{
4931 .tag = .template_value_parameter,
4932 .attrs = &.{
4933 .{ .type, .ref_addr },
4934 .{ .ZIG_comptime_value, .ref_addr },
4935 },
4936 },
4937 .runtime_capture = .{
4938 .tag = .template_type_parameter,
4939 .attrs = &.{
4940 .{ .type, .ref_addr },
4941 },
4942 },
4943 .nav_capture = .{
4944 .tag = .template_value_parameter,
4945 .attrs = &.{
4946 .{ .location, .exprloc },
4947 },
4948 },
4949 .builtin_extern_nullary_func = .{
4950 .tag = .subprogram,
4951 .attrs = &.{
4952 .{ .ZIG_parent, .ref_addr },
4953 .{ .linkage_name, .strp },
4954 .{ .type, .ref_addr },
4955 .{ .low_pc, .addr },
4956 .{ .external, .flag_present },
4957 .{ .noreturn, .flag },
4958 },
4959 },
4960 .builtin_extern_func = .{
4961 .tag = .subprogram,
4962 .children = true,
4963 .attrs = &.{
4964 .{ .ZIG_parent, .ref_addr },
4965 .{ .linkage_name, .strp },
4966 .{ .type, .ref_addr },
4967 .{ .low_pc, .addr },
4968 .{ .external, .flag_present },
4969 .{ .noreturn, .flag },
4970 },
4971 },
4972 .builtin_extern_var = .{
4973 .tag = .variable,
4974 .attrs = &.{
4975 .{ .ZIG_parent, .ref_addr },
4976 .{ .linkage_name, .strp },
4977 .{ .type, .ref_addr },
4978 .{ .location, .exprloc },
4979 .{ .external, .flag_present },
4980 },
4981 },
4982 .empty_block = .{
4983 .tag = .lexical_block,
4984 .attrs = &.{
4985 .{ .low_pc, .addr },
4986 .{ .high_pc, .data4 },
4987 },
4988 },
4989 .block = .{
4990 .tag = .lexical_block,
4991 .children = true,
4992 .attrs = &.{
4993 .{ .low_pc, .addr },
4994 .{ .high_pc, .data4 },
4995 },
4996 },
4997 .empty_inlined_func = .{
4998 .tag = .inlined_subroutine,
4999 .attrs = &.{
5000 .{ .abstract_origin, .ref_addr },
5001 .{ .ZIG_call_line_relative, .udata },
5002 .{ .call_column, .udata },
5003 .{ .low_pc, .addr },
5004 .{ .high_pc, .data4 },
5005 },
5006 },
5007 .inlined_func = .{
5008 .tag = .inlined_subroutine,
5009 .children = true,
5010 .attrs = &.{
5011 .{ .abstract_origin, .ref_addr },
5012 .{ .ZIG_call_line_relative, .udata },
5013 .{ .call_column, .udata },
5014 .{ .low_pc, .addr },
5015 .{ .high_pc, .data4 },
5016 },
5017 },
5018 .arg = .{
5019 .tag = .formal_parameter,
5020 .attrs = &.{
5021 .{ .name, .strp },
5022 .{ .type, .ref_addr },
5023 .{ .location, .exprloc },
5024 },
5025 },
5026 .unnamed_arg = .{
5027 .tag = .formal_parameter,
5028 .attrs = &.{
5029 .{ .type, .ref_addr },
5030 .{ .location, .exprloc },
5031 },
5032 },
5033 .comptime_arg = .{
5034 .tag = .formal_parameter,
5035 .attrs = &.{
5036 .{ .const_expr, .flag_present },
5037 .{ .name, .strp },
5038 .{ .type, .ref_addr },
5039 },
5040 },
5041 .comptime_arg_fully_runtime = .{
5042 .tag = .formal_parameter,
5043 .attrs = &.{
5044 .{ .const_expr, .flag_present },
5045 .{ .name, .strp },
5046 .{ .type, .ref_addr },
5047 .{ .const_value, .block },
5048 },
5049 },
5050 .comptime_arg_partially_comptime = .{
5051 .tag = .formal_parameter,
5052 .attrs = &.{
5053 .{ .const_expr, .flag_present },
5054 .{ .name, .strp },
5055 .{ .type, .ref_addr },
5056 .{ .const_value, .block },
5057 .{ .ZIG_comptime_value, .ref_addr },
5058 },
5059 },
5060 .comptime_arg_fully_comptime = .{
5061 .tag = .formal_parameter,
5062 .attrs = &.{
5063 .{ .const_expr, .flag_present },
5064 .{ .name, .strp },
5065 .{ .type, .ref_addr },
5066 .{ .ZIG_comptime_value, .ref_addr },
5067 },
5068 },
5069 .unnamed_comptime_arg = .{
5070 .tag = .formal_parameter,
5071 .attrs = &.{
5072 .{ .const_expr, .flag_present },
5073 .{ .type, .ref_addr },
5074 },
5075 },
5076 .unnamed_comptime_arg_fully_runtime = .{
5077 .tag = .formal_parameter,
5078 .attrs = &.{
5079 .{ .const_expr, .flag_present },
5080 .{ .type, .ref_addr },
5081 .{ .const_value, .block },
5082 },
5083 },
5084 .unnamed_comptime_arg_partially_comptime = .{
5085 .tag = .formal_parameter,
5086 .attrs = &.{
5087 .{ .const_expr, .flag_present },
5088 .{ .type, .ref_addr },
5089 .{ .const_value, .block },
5090 .{ .ZIG_comptime_value, .ref_addr },
5091 },
5092 },
5093 .unnamed_comptime_arg_fully_comptime = .{
5094 .tag = .formal_parameter,
5095 .attrs = &.{
5096 .{ .const_expr, .flag_present },
5097 .{ .type, .ref_addr },
5098 .{ .ZIG_comptime_value, .ref_addr },
5099 },
5100 },
5101 .extern_param = .{
5102 .tag = .formal_parameter,
5103 .attrs = &.{
5104 .{ .type, .ref_addr },
5105 },
5106 },
5107 .local_var = .{
5108 .tag = .variable,
5109 .attrs = &.{
5110 .{ .name, .strp },
5111 .{ .type, .ref_addr },
5112 .{ .location, .exprloc },
5113 },
5114 },
5115 .local_const = .{
5116 .tag = .constant,
5117 .attrs = &.{
5118 .{ .name, .strp },
5119 .{ .type, .ref_addr },
5120 },
5121 },
5122 .local_const_fully_runtime = .{
5123 .tag = .constant,
5124 .attrs = &.{
5125 .{ .name, .strp },
5126 .{ .type, .ref_addr },
5127 .{ .const_value, .block },
5128 },
5129 },
5130 .local_const_partially_comptime = .{
5131 .tag = .constant,
5132 .attrs = &.{
5133 .{ .name, .strp },
5134 .{ .type, .ref_addr },
5135 .{ .const_value, .block },
5136 .{ .ZIG_comptime_value, .ref_addr },
5137 },
5138 },
5139 .local_const_fully_comptime = .{
5140 .tag = .constant,
5141 .attrs = &.{
5142 .{ .name, .strp },
5143 .{ .type, .ref_addr },
5144 .{ .ZIG_comptime_value, .ref_addr },
5145 },
5146 },
5147 .undefined_comptime_value = .{
5148 .tag = .ZIG_comptime_value,
5149 .attrs = &.{
5150 .{ .type, .ref_addr },
5151 },
5152 },
5153 .aggregate_undefined_comptime_value = .{
5154 .tag = .ZIG_comptime_value,
5155 .children = true,
5156 .attrs = &.{
5157 .{ .type, .ref_addr },
5158 },
5159 },
5160 .comptime_value = .{
5161 .tag = .ZIG_comptime_value,
5162 .attrs = &.{
5163 .{ .type, .ref_addr },
5164 .{ .const_value, .indirect },
5165 },
5166 },
5167 .aggregate_comptime_value = .{
5168 .tag = .ZIG_comptime_value,
5169 .children = true,
5170 .attrs = &.{
5171 .{ .type, .ref_addr },
5172 .{ .const_value, .indirect },
5173 },
5174 },
5175 .location_comptime_value = .{
5176 .tag = .ZIG_comptime_value,
5177 .attrs = &.{
5178 .{ .type, .ref_addr },
5179 .{ .location, .exprloc },
5180 },
5181 },
5182 .aggregate_location_comptime_value = .{
5183 .tag = .ZIG_comptime_value,
5184 .children = true,
5185 .attrs = &.{
5186 .{ .type, .ref_addr },
5187 .{ .location, .exprloc },
5188 },
5189 },
5190 .comptime_value_field_runtime_bits = .{
5191 .tag = .member,
5192 .attrs = &.{
5193 .{ .name, .strp },
5194 .{ .const_value, .block },
5195 },
5196 },
5197 .comptime_value_field_comptime_state = .{
5198 .tag = .member,
5199 .attrs = &.{
5200 .{ .name, .strp },
5201 .{ .ZIG_comptime_value, .ref_addr },
5202 },
5203 },
5204 .comptime_value_elem_runtime_bits = .{
5205 .tag = .member,
5206 .attrs = &.{
5207 .{ .const_value, .block },
5208 },
5209 },
5210 .comptime_value_elem_comptime_state = .{
5211 .tag = .member,
5212 .attrs = &.{
5213 .{ .ZIG_comptime_value, .ref_addr },
5214 },
5215 },
5216 });
5217};
5218
5219pub fn uleb128Size(value: anytype) u32 {
5220 var buf: [std.atomic.cache_line]u8 = undefined;
5221 var dw: std.Io.Writer.Discarding = .init(&buf);
5222 dw.writer.writeUleb128(value) catch unreachable;
5223 return @intCast(dw.fullCount());
5224}
5225
5226pub fn sleb128Size(value: anytype) u32 {
5227 var buf: [std.atomic.cache_line]u8 = undefined;
5228 var dw: std.Io.Writer.Discarding = .init(&buf);
5229 dw.writer.writeSleb128(value) catch unreachable;
5230 return @intCast(dw.fullCount());
5231}
5232
5233const assert = std.debug.assert;
5234const codegen = @import("../codegen.zig");
5235const Compilation = @import("../Compilation.zig");
5236const dev = @import("../dev.zig");
5237const DW = std.dwarf;
5238const Dwarf = @This();
5239const InternPool = @import("../InternPool.zig");
5240const link = @import("../link.zig");
5241const log = std.log.scoped(.dwarf);
5242const Module = @import("../Module.zig");
5243const std = @import("std");
5244const target_info = @import("../target.zig");
5245const Type = @import("../Type.zig");
5246const Value = @import("../Value.zig");
5247const Zcu = @import("../Zcu.zig");
src/link/Elf.zig+3-6
...@@ -1677,9 +1677,7 @@ pub fn updateContainerType(...@@ -1677,9 +1677,7 @@ pub fn updateContainerType(
1677 ty: InternPool.Index,1677 ty: InternPool.Index,
1678 success: bool,1678 success: bool,
1679) link.Error!void {1679) link.Error!void {
1680 return self.zigObjectPtr().?.updateContainerType(pt, ty, success) catch |err| switch (err) {1680 try self.zigObjectPtr().?.updateContainerType(pt, ty, success);
1681 error.OutOfMemory => |e| return e,
1682 };
1683}1681}
16841682
1685pub fn updateExports(1683pub fn updateExports(
...@@ -1690,8 +1688,8 @@ pub fn updateExports(...@@ -1690,8 +1688,8 @@ pub fn updateExports(
1690 return self.zigObjectPtr().?.updateExports(self, pt, export_indices);1688 return self.zigObjectPtr().?.updateExports(self, pt, export_indices);
1691}1689}
16921690
1693pub fn updateLineNumber(self: *Elf, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) link.Error!void {1691pub fn updateLineNumber(self: *Elf, pt: Zcu.PerThread, inst: InternPool.TrackedInst.Index, line: u32) link.Error!void {
1694 return self.zigObjectPtr().?.updateLineNumber(pt, ti_id);1692 return self.zigObjectPtr().?.updateLineNumber(pt, inst, line);
1695}1693}
16961694
1697fn checkDuplicates(self: *Elf) !void {1695fn checkDuplicates(self: *Elf) !void {
...@@ -4412,7 +4410,6 @@ const Path = std.Build.Cache.Path;...@@ -4412,7 +4410,6 @@ const Path = std.Build.Cache.Path;
4412const Stat = std.Build.Cache.File.Stat;4410const Stat = std.Build.Cache.File.Stat;
44134411
4414const codegen = @import("../codegen.zig");4412const codegen = @import("../codegen.zig");
4415const dev = @import("../dev.zig");
4416const eh_frame = @import("Elf/eh_frame.zig");4413const eh_frame = @import("Elf/eh_frame.zig");
4417const gc = @import("Elf/gc.zig");4414const gc = @import("Elf/gc.zig");
4418const musl = @import("../libs/musl.zig");4415const musl = @import("../libs/musl.zig");
src/link/Elf/Atom.zig+17-11
...@@ -945,7 +945,7 @@ const x86_64 = struct {...@@ -945,7 +945,7 @@ const x86_64 = struct {
945 code: ?[]const u8,945 code: ?[]const u8,
946 it: *RelocsIterator,946 it: *RelocsIterator,
947 ) !void {947 ) !void {
948 dev.check(.x86_64_backend);948 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
949 const t = &elf_file.base.comp.root_mod.resolved_target.result;949 const t = &elf_file.base.comp.root_mod.resolved_target.result;
950 const is_static = elf_file.base.isStatic();950 const is_static = elf_file.base.isStatic();
951 const is_dyn_lib = elf_file.isEffectivelyDynLib();951 const is_dyn_lib = elf_file.isEffectivelyDynLib();
...@@ -1059,7 +1059,7 @@ const x86_64 = struct {...@@ -1059,7 +1059,7 @@ const x86_64 = struct {
1059 it: *RelocsIterator,1059 it: *RelocsIterator,
1060 code: []u8,1060 code: []u8,
1061 ) !void {1061 ) !void {
1062 dev.check(.x86_64_backend);1062 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1063 const t = &elf_file.base.comp.root_mod.resolved_target.result;1063 const t = &elf_file.base.comp.root_mod.resolved_target.result;
1064 const diags = &elf_file.base.comp.link_diags;1064 const diags = &elf_file.base.comp.link_diags;
1065 const r_type: elf.R_X86_64 = @fromBackingInt(@intCast(rel.r_type()));1065 const r_type: elf.R_X86_64 = @fromBackingInt(@intCast(rel.r_type()));
...@@ -1200,7 +1200,7 @@ const x86_64 = struct {...@@ -1200,7 +1200,7 @@ const x86_64 = struct {
1200 args: ResolveArgs,1200 args: ResolveArgs,
1201 code: []u8,1201 code: []u8,
1202 ) !void {1202 ) !void {
1203 dev.check(.x86_64_backend);1203 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1204 const r_type: elf.R_X86_64 = @fromBackingInt(@intCast(rel.r_type()));1204 const r_type: elf.R_X86_64 = @fromBackingInt(@intCast(rel.r_type()));
12051205
1206 _, const A, const S, const GOT, _, _, const DTP = args;1206 _, const A, const S, const GOT, _, _, const DTP = args;
...@@ -1240,7 +1240,7 @@ const x86_64 = struct {...@@ -1240,7 +1240,7 @@ const x86_64 = struct {
1240 }1240 }
12411241
1242 fn relaxGotpcrelx(code: []u8, t: *const std.Target) !void {1242 fn relaxGotpcrelx(code: []u8, t: *const std.Target) !void {
1243 dev.check(.x86_64_backend);1243 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1244 const old_inst = disassemble(code) orelse return error.RelaxFailure;1244 const old_inst = disassemble(code) orelse return error.RelaxFailure;
1245 const inst: Instruction = switch (old_inst.encoding.mnemonic) {1245 const inst: Instruction = switch (old_inst.encoding.mnemonic) {
1246 .call => try .new(old_inst.prefix, .call, &.{1246 .call => try .new(old_inst.prefix, .call, &.{
...@@ -1259,7 +1259,7 @@ const x86_64 = struct {...@@ -1259,7 +1259,7 @@ const x86_64 = struct {
1259 }1259 }
12601260
1261 fn relaxRexGotpcrelx(code: []u8, t: *const std.Target) !void {1261 fn relaxRexGotpcrelx(code: []u8, t: *const std.Target) !void {
1262 dev.check(.x86_64_backend);1262 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1263 const old_inst = disassemble(code) orelse return error.RelaxFailure;1263 const old_inst = disassemble(code) orelse return error.RelaxFailure;
1264 switch (old_inst.encoding.mnemonic) {1264 switch (old_inst.encoding.mnemonic) {
1265 .mov => {1265 .mov => {
...@@ -1279,7 +1279,7 @@ const x86_64 = struct {...@@ -1279,7 +1279,7 @@ const x86_64 = struct {
1279 code: []u8,1279 code: []u8,
1280 r_offset: usize,1280 r_offset: usize,
1281 ) !void {1281 ) !void {
1282 dev.check(.x86_64_backend);1282 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1283 assert(rels.len == 2);1283 assert(rels.len == 2);
1284 const diags = &elf_file.base.comp.link_diags;1284 const diags = &elf_file.base.comp.link_diags;
1285 const rel: elf.R_X86_64 = @fromBackingInt(@intCast(rels[1].r_type()));1285 const rel: elf.R_X86_64 = @fromBackingInt(@intCast(rels[1].r_type()));
...@@ -1319,7 +1319,7 @@ const x86_64 = struct {...@@ -1319,7 +1319,7 @@ const x86_64 = struct {
1319 code: []u8,1319 code: []u8,
1320 r_offset: usize,1320 r_offset: usize,
1321 ) !void {1321 ) !void {
1322 dev.check(.x86_64_backend);1322 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1323 assert(rels.len == 2);1323 assert(rels.len == 2);
1324 const diags = &elf_file.base.comp.link_diags;1324 const diags = &elf_file.base.comp.link_diags;
1325 const rel: elf.R_X86_64 = @fromBackingInt(@intCast(rels[1].r_type()));1325 const rel: elf.R_X86_64 = @fromBackingInt(@intCast(rels[1].r_type()));
...@@ -1366,7 +1366,7 @@ const x86_64 = struct {...@@ -1366,7 +1366,7 @@ const x86_64 = struct {
1366 }1366 }
13671367
1368 fn canRelaxGotTpOff(code: []const u8, t: *const std.Target) bool {1368 fn canRelaxGotTpOff(code: []const u8, t: *const std.Target) bool {
1369 dev.check(.x86_64_backend);1369 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1370 const old_inst = disassemble(code) orelse return false;1370 const old_inst = disassemble(code) orelse return false;
1371 switch (old_inst.encoding.mnemonic) {1371 switch (old_inst.encoding.mnemonic) {
1372 .mov => {1372 .mov => {
...@@ -1384,7 +1384,7 @@ const x86_64 = struct {...@@ -1384,7 +1384,7 @@ const x86_64 = struct {
1384 }1384 }
13851385
1386 fn relaxGotTpOff(code: []u8, t: *const std.Target) void {1386 fn relaxGotTpOff(code: []u8, t: *const std.Target) void {
1387 dev.check(.x86_64_backend);1387 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1388 const old_inst = disassemble(code) orelse unreachable;1388 const old_inst = disassemble(code) orelse unreachable;
1389 switch (old_inst.encoding.mnemonic) {1389 switch (old_inst.encoding.mnemonic) {
1390 .mov => {1390 .mov => {
...@@ -1401,7 +1401,7 @@ const x86_64 = struct {...@@ -1401,7 +1401,7 @@ const x86_64 = struct {
1401 }1401 }
14021402
1403 fn relaxGotPcTlsDesc(code: []u8, target: *const std.Target) !void {1403 fn relaxGotPcTlsDesc(code: []u8, target: *const std.Target) !void {
1404 dev.check(.x86_64_backend);1404 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1405 const old_inst = disassemble(code) orelse return error.RelaxFailure;1405 const old_inst = disassemble(code) orelse return error.RelaxFailure;
1406 switch (old_inst.encoding.mnemonic) {1406 switch (old_inst.encoding.mnemonic) {
1407 .lea => {1407 .lea => {
...@@ -1425,7 +1425,7 @@ const x86_64 = struct {...@@ -1425,7 +1425,7 @@ const x86_64 = struct {
1425 code: []u8,1425 code: []u8,
1426 r_offset: usize,1426 r_offset: usize,
1427 ) !void {1427 ) !void {
1428 dev.check(.x86_64_backend);1428 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1429 assert(rels.len == 2);1429 assert(rels.len == 2);
1430 const diags = &elf_file.base.comp.link_diags;1430 const diags = &elf_file.base.comp.link_diags;
1431 const rel: elf.R_X86_64 = @fromBackingInt(@intCast(rels[1].r_type()));1431 const rel: elf.R_X86_64 = @fromBackingInt(@intCast(rels[1].r_type()));
...@@ -1492,6 +1492,7 @@ const aarch64 = struct {...@@ -1492,6 +1492,7 @@ const aarch64 = struct {
1492 ) !void {1492 ) !void {
1493 _ = code;1493 _ = code;
1494 _ = it;1494 _ = it;
1495 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
14951496
1496 const r_type: elf.R_AARCH64 = @fromBackingInt(@intCast(rel.r_type()));1497 const r_type: elf.R_AARCH64 = @fromBackingInt(@intCast(rel.r_type()));
1497 const is_dyn_lib = elf_file.isEffectivelyDynLib();1498 const is_dyn_lib = elf_file.isEffectivelyDynLib();
...@@ -1569,6 +1570,7 @@ const aarch64 = struct {...@@ -1569,6 +1570,7 @@ const aarch64 = struct {
1569 code_buffer: []u8,1570 code_buffer: []u8,
1570 ) (error{ UnexpectedRemainder, DivisionByZero } || RelocError)!void {1571 ) (error{ UnexpectedRemainder, DivisionByZero } || RelocError)!void {
1571 _ = it;1572 _ = it;
1573 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
15721574
1573 const diags = &elf_file.base.comp.link_diags;1575 const diags = &elf_file.base.comp.link_diags;
1574 const r_type: elf.R_AARCH64 = @fromBackingInt(@intCast(rel.r_type()));1576 const r_type: elf.R_AARCH64 = @fromBackingInt(@intCast(rel.r_type()));
...@@ -1742,6 +1744,7 @@ const aarch64 = struct {...@@ -1742,6 +1744,7 @@ const aarch64 = struct {
1742 args: ResolveArgs,1744 args: ResolveArgs,
1743 code: []u8,1745 code: []u8,
1744 ) !void {1746 ) !void {
1747 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
1745 const r_type: elf.R_AARCH64 = @fromBackingInt(@intCast(rel.r_type()));1748 const r_type: elf.R_AARCH64 = @fromBackingInt(@intCast(rel.r_type()));
17461749
1747 _, const A, const S, _, _, _, _ = args;1750 _, const A, const S, _, _, _, _ = args;
...@@ -1772,6 +1775,7 @@ const riscv = struct {...@@ -1772,6 +1775,7 @@ const riscv = struct {
1772 ) !void {1775 ) !void {
1773 _ = code;1776 _ = code;
1774 _ = it;1777 _ = it;
1778 dev.checkAny(&.{ .llvm_backend, .riscv64_backend });
17751779
1776 const r_type: elf.R_RISCV = @fromBackingInt(@intCast(rel.r_type()));1780 const r_type: elf.R_RISCV = @fromBackingInt(@intCast(rel.r_type()));
17771781
...@@ -1815,6 +1819,7 @@ const riscv = struct {...@@ -1815,6 +1819,7 @@ const riscv = struct {
1815 it: *RelocsIterator,1819 it: *RelocsIterator,
1816 code: []u8,1820 code: []u8,
1817 ) !void {1821 ) !void {
1822 dev.checkAny(&.{ .llvm_backend, .riscv64_backend });
1818 const diags = &elf_file.base.comp.link_diags;1823 const diags = &elf_file.base.comp.link_diags;
1819 const r_type: elf.R_RISCV = @fromBackingInt(@intCast(rel.r_type()));1824 const r_type: elf.R_RISCV = @fromBackingInt(@intCast(rel.r_type()));
1820 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;1825 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
...@@ -1951,6 +1956,7 @@ const riscv = struct {...@@ -1951,6 +1956,7 @@ const riscv = struct {
1951 args: ResolveArgs,1956 args: ResolveArgs,
1952 code: []u8,1957 code: []u8,
1953 ) !void {1958 ) !void {
1959 dev.checkAny(&.{ .llvm_backend, .riscv64_backend });
1954 const r_type: elf.R_RISCV = @fromBackingInt(@intCast(rel.r_type()));1960 const r_type: elf.R_RISCV = @fromBackingInt(@intCast(rel.r_type()));
19551961
1956 _, const A, const S, const GOT, _, _, const DTP = args;1962 _, const A, const S, const GOT, _, _, const DTP = args;
src/link/Elf/Object.zig+15-22
...@@ -1236,29 +1236,22 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index...@@ -1236,29 +1236,22 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index
12361236
1237 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {1237 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {
1238 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;1238 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
1239 var compressed_reader: Io.Reader = .fixed(data[@sizeOf(elf.Elf64_Chdr)..]);
1240 const size = std.math.cast(usize, chdr.ch_size) orelse return error.Overflow;
1241 var aw: Io.Writer.Allocating = try .initCapacity(gpa, size);
1242 defer aw.deinit();
1239 switch (chdr.ch_type) {1243 switch (chdr.ch_type) {
1240 .ZLIB => {1244 .ZLIB => {
1241 var stream: std.Io.Reader = .fixed(data[@sizeOf(elf.Elf64_Chdr)..]);1245 var decompress: std.compress.flate.Decompress = .init(&compressed_reader, .zlib, &.{});
1242 var zlib_stream: std.compress.flate.Decompress = .init(&stream, .zlib, &.{});1246 _ = try decompress.reader.streamRemaining(&aw.writer);
1243 const size = std.math.cast(usize, chdr.ch_size) orelse return error.Overflow;
1244 var aw: std.Io.Writer.Allocating = .init(gpa);
1245 try aw.ensureUnusedCapacity(size);
1246 defer aw.deinit();
1247 _ = try zlib_stream.reader.streamRemaining(&aw.writer);
1248 return aw.toOwnedSlice();
1249 },1247 },
1250 .ZSTD => {1248 .ZSTD => {
1251 var input: std.Io.Reader = .fixed(data[@sizeOf(elf.Elf64_Chdr)..]);1249 var decompress: std.compress.zstd.Decompress = .init(&compressed_reader, &.{}, .{});
1252 var stream: std.compress.zstd.Decompress = .init(&input, &.{}, .{});1250 _ = try decompress.reader.streamRemaining(&aw.writer);
1253 const size = std.math.cast(usize, chdr.ch_size) orelse return error.Overflow;
1254 var aw: std.Io.Writer.Allocating = try .initCapacity(gpa, size);
1255 defer aw.deinit();
1256 _ = try stream.reader.streamRemaining(&aw.writer);
1257
1258 return aw.toOwnedSlice();
1259 },1251 },
1260 else => @panic("TODO unhandled compression scheme"),1252 else => @panic("TODO unhandled compression scheme"),
1261 }1253 }
1254 return aw.toOwnedSlice();
1262 }1255 }
12631256
1264 return data;1257 return data;
...@@ -1492,7 +1485,7 @@ const Format = struct {...@@ -1492,7 +1485,7 @@ const Format = struct {
1492 object: *Object,1485 object: *Object,
1493 elf_file: *Elf,1486 elf_file: *Elf,
14941487
1495 fn symtab(f: Format, writer: *std.Io.Writer) std.Io.Writer.Error!void {1488 fn symtab(f: Format, writer: *Io.Writer) Io.Writer.Error!void {
1496 const object = f.object;1489 const object = f.object;
1497 const elf_file = f.elf_file;1490 const elf_file = f.elf_file;
1498 try writer.writeAll(" locals\n");1491 try writer.writeAll(" locals\n");
...@@ -1511,7 +1504,7 @@ const Format = struct {...@@ -1511,7 +1504,7 @@ const Format = struct {
1511 }1504 }
1512 }1505 }
15131506
1514 fn atoms(f: Format, writer: *std.Io.Writer) std.Io.Writer.Error!void {1507 fn atoms(f: Format, writer: *Io.Writer) Io.Writer.Error!void {
1515 const object = f.object;1508 const object = f.object;
1516 try writer.writeAll(" atoms\n");1509 try writer.writeAll(" atoms\n");
1517 for (object.atoms_indexes.items) |atom_index| {1510 for (object.atoms_indexes.items) |atom_index| {
...@@ -1520,7 +1513,7 @@ const Format = struct {...@@ -1520,7 +1513,7 @@ const Format = struct {
1520 }1513 }
1521 }1514 }
15221515
1523 fn cies(f: Format, writer: *std.Io.Writer) std.Io.Writer.Error!void {1516 fn cies(f: Format, writer: *Io.Writer) Io.Writer.Error!void {
1524 const object = f.object;1517 const object = f.object;
1525 try writer.writeAll(" cies\n");1518 try writer.writeAll(" cies\n");
1526 for (object.cies.items, 0..) |cie, i| {1519 for (object.cies.items, 0..) |cie, i| {
...@@ -1528,7 +1521,7 @@ const Format = struct {...@@ -1528,7 +1521,7 @@ const Format = struct {
1528 }1521 }
1529 }1522 }
15301523
1531 fn fdes(f: Format, writer: *std.Io.Writer) std.Io.Writer.Error!void {1524 fn fdes(f: Format, writer: *Io.Writer) Io.Writer.Error!void {
1532 const object = f.object;1525 const object = f.object;
1533 try writer.writeAll(" fdes\n");1526 try writer.writeAll(" fdes\n");
1534 for (object.fdes.items, 0..) |fde, i| {1527 for (object.fdes.items, 0..) |fde, i| {
...@@ -1536,7 +1529,7 @@ const Format = struct {...@@ -1536,7 +1529,7 @@ const Format = struct {
1536 }1529 }
1537 }1530 }
15381531
1539 fn groups(f: Format, writer: *std.Io.Writer) std.Io.Writer.Error!void {1532 fn groups(f: Format, writer: *Io.Writer) Io.Writer.Error!void {
1540 const object = f.object;1533 const object = f.object;
1541 const elf_file = f.elf_file;1534 const elf_file = f.elf_file;
1542 try writer.writeAll(" groups\n");1535 try writer.writeAll(" groups\n");
...@@ -1586,7 +1579,7 @@ pub fn fmtPath(self: Object) std.fmt.Alt(Object, formatPath) {...@@ -1586,7 +1579,7 @@ pub fn fmtPath(self: Object) std.fmt.Alt(Object, formatPath) {
1586 return .{ .data = self };1579 return .{ .data = self };
1587}1580}
15881581
1589fn formatPath(object: Object, writer: *std.Io.Writer) std.Io.Writer.Error!void {1582fn formatPath(object: Object, writer: *Io.Writer) Io.Writer.Error!void {
1590 if (object.archive) |ar| {1583 if (object.archive) |ar| {
1591 try writer.print("{f}({f})", .{ ar.path, object.path });1584 try writer.print("{f}({f})", .{ ar.path, object.path });
1592 } else {1585 } else {
src/link/Elf/Thunk.zig+2
...@@ -91,6 +91,7 @@ pub const Index = u32;...@@ -91,6 +91,7 @@ pub const Index = u32;
9191
92const aarch64 = struct {92const aarch64 = struct {
93 fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {93 fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
94 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
94 for (thunk.symbols.keys(), 0..) |ref, i| {95 for (thunk.symbols.keys(), 0..) |ref, i| {
95 const sym = elf_file.symbol(ref).?;96 const sym = elf_file.symbol(ref).?;
96 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));97 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));
...@@ -113,6 +114,7 @@ const aarch64 = struct {...@@ -113,6 +114,7 @@ const aarch64 = struct {
113};114};
114115
115const assert = std.debug.assert;116const assert = std.debug.assert;
117const dev = @import("../../dev.zig");
116const elf = std.elf;118const elf = std.elf;
117const log = std.log.scoped(.link);119const log = std.log.scoped(.link);
118const math = std.math;120const math = std.math;
src/link/Elf/ZigObject.zig+14-18
...@@ -946,14 +946,11 @@ pub fn getNavVAddr(...@@ -946,14 +946,11 @@ pub fn getNavVAddr(
946 .r_addend = reloc_info.addend,946 .r_addend = reloc_info.addend,
947 }, self);947 }, self);
948 },948 },
949 .debug_output => |debug_output| switch (debug_output) {949 .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
950 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{950 .source_off = @intCast(reloc_info.offset),
951 .source_off = @intCast(reloc_info.offset),951 .target_sym = @fromBackingInt(@intCast(this_sym_index)),
952 .target_sym = @fromBackingInt(@intCast(this_sym_index)),952 .target_off = reloc_info.addend,
953 .target_off = reloc_info.addend,953 }),
954 }),
955 .none => unreachable,
956 },
957 }954 }
958 return @intCast(vaddr);955 return @intCast(vaddr);
959}956}
...@@ -978,14 +975,11 @@ pub fn getUavVAddr(...@@ -978,14 +975,11 @@ pub fn getUavVAddr(
978 .r_addend = reloc_info.addend,975 .r_addend = reloc_info.addend,
979 }, self);976 }, self);
980 },977 },
981 .debug_output => |debug_output| switch (debug_output) {978 .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
982 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{979 .source_off = @intCast(reloc_info.offset),
983 .source_off = @intCast(reloc_info.offset),980 .target_sym = @fromBackingInt(@intCast(sym_index)),
984 .target_sym = @fromBackingInt(@intCast(sym_index)),981 .target_off = reloc_info.addend,
985 .target_off = reloc_info.addend,982 }),
986 }),
987 .none => unreachable,
988 },
989 }983 }
990 return @intCast(vaddr);984 return @intCast(vaddr);
991}985}
...@@ -1952,11 +1946,11 @@ pub fn updateExports(...@@ -1952,11 +1946,11 @@ pub fn updateExports(
1952 }1946 }
1953}1947}
19541948
1955pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) link.Error!void {1949pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index, line: u32) link.Error!void {
1956 if (self.dwarf) |*dwarf| {1950 if (self.dwarf) |*dwarf| {
1957 const comp = dwarf.bin_file.comp;1951 const comp = dwarf.bin_file.comp;
1958 const diags = &comp.link_diags;1952 const diags = &comp.link_diags;
1959 dwarf.updateLineNumber(pt.zcu, ti_id) catch |err| switch (err) {1953 dwarf.updateLineNumber(pt.zcu, ti_id, line) catch |err| switch (err) {
1960 error.OutOfMemory, error.Canceled, error.AlreadyReported => |e| return e,1954 error.OutOfMemory, error.Canceled, error.AlreadyReported => |e| return e,
1961 else => |e| return diags.fail("failed to update dwarf line numbers: {s}", .{@errorName(e)}),1955 else => |e| return diags.fail("failed to update dwarf line numbers: {s}", .{@errorName(e)}),
1962 };1956 };
...@@ -2402,6 +2396,7 @@ const TlsTable = std.array_hash_map.Auto(Atom.Index, void);...@@ -2402,6 +2396,7 @@ const TlsTable = std.array_hash_map.Auto(Atom.Index, void);
24022396
2403const x86_64 = struct {2397const x86_64 = struct {
2404 fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 {2398 fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 {
2399 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
2405 const disp = @as(i64, @intCast(target_addr)) - source_addr - 5;2400 const disp = @as(i64, @intCast(target_addr)) - source_addr - 5;
2406 var bytes = [_]u8{2401 var bytes = [_]u8{
2407 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel322402 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel32
...@@ -2417,6 +2412,7 @@ const assert = std.debug.assert;...@@ -2417,6 +2412,7 @@ const assert = std.debug.assert;
2417const build_options = @import("build_options");2412const build_options = @import("build_options");
2418const builtin = @import("builtin");2413const builtin = @import("builtin");
2419const codegen = @import("../../codegen.zig");2414const codegen = @import("../../codegen.zig");
2415const dev = @import("../../dev.zig");
2420const elf = std.elf;2416const elf = std.elf;
2421const link = @import("../../link.zig");2417const link = @import("../../link.zig");
2422const log = std.log.scoped(.link);2418const log = std.log.scoped(.link);
src/link/Elf/eh_frame.zig+4
...@@ -535,6 +535,7 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {...@@ -535,6 +535,7 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {
535535
536const x86_64 = struct {536const x86_64 = struct {
537 fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void {537 fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void {
538 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
538 const r_type: elf.R_X86_64 = @fromBackingInt(@intCast(rel.r_type()));539 const r_type: elf.R_X86_64 = @fromBackingInt(@intCast(rel.r_type()));
539 switch (r_type) {540 switch (r_type) {
540 .NONE => {},541 .NONE => {},
...@@ -549,6 +550,7 @@ const x86_64 = struct {...@@ -549,6 +550,7 @@ const x86_64 = struct {
549550
550const aarch64 = struct {551const aarch64 = struct {
551 fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void {552 fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void {
553 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
552 const r_type: elf.R_AARCH64 = @fromBackingInt(@intCast(rel.r_type()));554 const r_type: elf.R_AARCH64 = @fromBackingInt(@intCast(rel.r_type()));
553 switch (r_type) {555 switch (r_type) {
554 .NONE => {},556 .NONE => {},
...@@ -562,6 +564,7 @@ const aarch64 = struct {...@@ -562,6 +564,7 @@ const aarch64 = struct {
562564
563const riscv = struct {565const riscv = struct {
564 fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void {566 fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void {
567 dev.checkAny(&.{ .llvm_backend, .riscv64_backend });
565 const r_type: elf.R_RISCV = @fromBackingInt(@intCast(rel.r_type()));568 const r_type: elf.R_RISCV = @fromBackingInt(@intCast(rel.r_type()));
566 switch (r_type) {569 switch (r_type) {
567 .NONE => {},570 .NONE => {},
...@@ -584,6 +587,7 @@ fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void {...@@ -584,6 +587,7 @@ fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void {
584587
585const std = @import("std");588const std = @import("std");
586const assert = std.debug.assert;589const assert = std.debug.assert;
590const dev = @import("../../dev.zig");
587const elf = std.elf;591const elf = std.elf;
588const math = std.math;592const math = std.math;
589const relocs_log = std.log.scoped(.link_relocs);593const relocs_log = std.log.scoped(.link_relocs);
src/link/Elf/synthetic_sections.zig+5
...@@ -772,6 +772,7 @@ pub const PltSection = struct {...@@ -772,6 +772,7 @@ pub const PltSection = struct {
772772
773 const x86_64 = struct {773 const x86_64 = struct {
774 fn write(plt: PltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {774 fn write(plt: PltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
775 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
775 const shdrs = elf_file.sections.items(.shdr);776 const shdrs = elf_file.sections.items(.shdr);
776 const plt_addr = shdrs[elf_file.section_indexes.plt.?].sh_addr;777 const plt_addr = shdrs[elf_file.section_indexes.plt.?].sh_addr;
777 const got_plt_addr = shdrs[elf_file.section_indexes.got_plt.?].sh_addr;778 const got_plt_addr = shdrs[elf_file.section_indexes.got_plt.?].sh_addr;
...@@ -807,6 +808,7 @@ pub const PltSection = struct {...@@ -807,6 +808,7 @@ pub const PltSection = struct {
807808
808 const aarch64 = struct {809 const aarch64 = struct {
809 fn write(plt: PltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {810 fn write(plt: PltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
811 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
810 {812 {
811 const shdrs = elf_file.sections.items(.shdr);813 const shdrs = elf_file.sections.items(.shdr);
812 const plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.plt.?].sh_addr);814 const plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.plt.?].sh_addr);
...@@ -949,6 +951,7 @@ pub const PltGotSection = struct {...@@ -949,6 +951,7 @@ pub const PltGotSection = struct {
949951
950 const x86_64 = struct {952 const x86_64 = struct {
951 pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {953 pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
954 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
952 for (plt_got.symbols.items) |ref| {955 for (plt_got.symbols.items) |ref| {
953 const sym = elf_file.symbol(ref).?;956 const sym = elf_file.symbol(ref).?;
954 const target_addr = sym.gotAddress(elf_file);957 const target_addr = sym.gotAddress(elf_file);
...@@ -967,6 +970,7 @@ pub const PltGotSection = struct {...@@ -967,6 +970,7 @@ pub const PltGotSection = struct {
967970
968 const aarch64 = struct {971 const aarch64 = struct {
969 fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {972 fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
973 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
970 for (plt_got.symbols.items) |ref| {974 for (plt_got.symbols.items) |ref| {
971 const sym = elf_file.symbol(ref).?;975 const sym = elf_file.symbol(ref).?;
972 const target_addr = sym.gotAddress(elf_file);976 const target_addr = sym.gotAddress(elf_file);
...@@ -1518,6 +1522,7 @@ fn writeInt(value: anytype, elf_file: *Elf, writer: *std.Io.Writer) !void {...@@ -1518,6 +1522,7 @@ fn writeInt(value: anytype, elf_file: *Elf, writer: *std.Io.Writer) !void {
15181522
1519const assert = std.debug.assert;1523const assert = std.debug.assert;
1520const builtin = @import("builtin");1524const builtin = @import("builtin");
1525const dev = @import("../../dev.zig");
1521const elf = std.elf;1526const elf = std.elf;
1522const math = std.math;1527const math = std.math;
1523const mem = std.mem;1528const mem = std.mem;
src/link/Elf2.zig+3350-1425
...@@ -1,8 +1,5 @@...@@ -1,8 +1,5 @@
1const Elf = @This();1const Elf = @This();
22
3const builtin = @import("builtin");
4const native_endian = builtin.cpu.arch.endian();
5
6const std = @import("std");3const std = @import("std");
7const Io = std.Io;4const Io = std.Io;
8const assert = std.debug.assert;5const assert = std.debug.assert;
...@@ -10,9 +7,10 @@ const log = std.log.scoped(.link);...@@ -10,9 +7,10 @@ const log = std.log.scoped(.link);
107
11const codegen = @import("../codegen.zig");8const codegen = @import("../codegen.zig");
12const Compilation = @import("../Compilation.zig");9const Compilation = @import("../Compilation.zig");
10const Dwarf = @import("Dwarf2.zig");
13const InternPool = @import("../InternPool.zig");11const InternPool = @import("../InternPool.zig");
14const link = @import("../link.zig");12const link = @import("../link.zig");
15const MappedFile = @import("MappedFile.zig");13const MappedFile = link.MappedFile;
16const target_util = @import("../target.zig");14const target_util = @import("../target.zig");
17const tracy = @import("../tracy.zig");15const tracy = @import("../tracy.zig");
18const Type = @import("../Type.zig");16const Type = @import("../Type.zig");
...@@ -23,7 +21,18 @@ const Alignment = MappedFile.Alignment;...@@ -23,7 +21,18 @@ const Alignment = MappedFile.Alignment;
23base: link.File,21base: link.File,
24options: link.File.OpenOptions,22options: link.File.OpenOptions,
25mf: MappedFile,23mf: MappedFile,
26ni: Node.Known,24ni: struct {
25 elf: MappedFile.Node.Index,
26 ehdr: MappedFile.Node.Index,
27 shdr: MappedFile.Node.Index,
28 rodata: MappedFile.Node.Index,
29 phdr: MappedFile.Node.Index,
30 text: MappedFile.Node.Index,
31 data: MappedFile.Node.Index,
32 data_rel_ro: MappedFile.Node.Index,
33 tls: MappedFile.Node.Index.Optional,
34 gnu_eh_frame: MappedFile.Node.Index.Optional,
35},
27archive: ?Archive,36archive: ?Archive,
28nodes: std.MultiArrayList(Node),37nodes: std.MultiArrayList(Node),
29/// Does not contain an item for `SHN_UNDEF`.38/// Does not contain an item for `SHN_UNDEF`.
...@@ -43,6 +52,16 @@ shndx: struct {...@@ -43,6 +52,16 @@ shndx: struct {
43 tdata: Section.Index,52 tdata: Section.Index,
44 rela_dyn: Section.Index,53 rela_dyn: Section.Index,
45 rela_plt: Section.Index,54 rela_plt: Section.Index,
55 debug_abbrev: Section.Index,
56 eh_frame_hdr: Section.Index,
57 eh_frame: Section.Index,
58 debug_frame: Section.Index,
59 debug_info: Section.Index,
60 debug_line: Section.Index,
61 debug_line_str: Section.Index,
62 debug_rnglists: Section.Index,
63 debug_str: Section.Index,
64 debug_str_offsets: Section.Index,
46 // These sections are created only as needed, and are initially `.UNDEF`.65 // These sections are created only as needed, and are initially `.UNDEF`.
47 init_array: Section.Index,66 init_array: Section.Index,
48 fini_array: Section.Index,67 fini_array: Section.Index,
...@@ -123,6 +142,8 @@ got: std.array_hash_map.Auto(GotKey, Section.RelaIndex.Optional),...@@ -123,6 +142,8 @@ got: std.array_hash_map.Auto(GotKey, Section.RelaIndex.Optional),
123plt: std.array_hash_map.Auto(String(.strtab), void),142plt: std.array_hash_map.Auto(String(.strtab), void),
124/// The `.plt` section contains zero or more symbol relocations starting at this index.143/// The `.plt` section contains zero or more symbol relocations starting at this index.
125plt_first_symbol_reloc: SymbolReloc.Index,144plt_first_symbol_reloc: SymbolReloc.Index,
145/// The `.eh_frame_hdr` section contains zero or more symbol relocations starting at this index.
146eh_frame_hdr_first_symbol_reloc: SymbolReloc.Index,
126147
127needed: std.array_hash_map.Auto(String(.dynstr), void),148needed: std.array_hash_map.Auto(String(.dynstr), void),
128inputs: std.ArrayList(struct {149inputs: std.ArrayList(struct {
...@@ -175,6 +196,7 @@ lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {...@@ -175,6 +196,7 @@ lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {
175}),196}),
176pending_uavs: std.ArrayList(Node.UavMapIndex),197pending_uavs: std.ArrayList(Node.UavMapIndex),
177symbol_relocs: std.ArrayList(SymbolReloc),198symbol_relocs: std.ArrayList(SymbolReloc),
199node_relocs: std.ArrayList(NodeReloc),
178got_relocs: std.ArrayList(GotReloc),200got_relocs: std.ArrayList(GotReloc),
179/// Set of relocations which must be re-applied if the size of the TLS segment changes.201/// Set of relocations which must be re-applied if the size of the TLS segment changes.
180tls_size_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),202tls_size_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),
...@@ -191,16 +213,25 @@ changed_symtab_index: std.array_hash_map.Auto(String(.strtab), void),...@@ -191,16 +213,25 @@ changed_symtab_index: std.array_hash_map.Auto(String(.strtab), void),
191/// section in `flush` only when it is actually necessary. See also `nodeWantsDsoRelocation`.213/// section in `flush` only when it is actually necessary. See also `nodeWantsDsoRelocation`.
192textrel_count: u32,214textrel_count: u32,
193215
216dwarf: Dwarf,
217dwarf_shared: std.enums.EnumArray(Dwarf.SharedSection, dwarf_relocs.Shared),
218dwarf_units: []dwarf_relocs.Unit,
219dwarf_consts: std.array_hash_map.Auto(link.ConstPool.Index, dwarf_relocs.Const),
220dwarf_globals: std.ArrayList(dwarf_relocs.Global),
221dwarf_funcs: std.ArrayList(dwarf_relocs.Func),
222dwarf_decls: std.array_hash_map.Auto(Dwarf.Decl.Index, dwarf_relocs.Decl),
223
194overflowed_reloc_count: u32,224overflowed_reloc_count: u32,
195misaligned_reloc_count: u32,225misaligned_reloc_count: u32,
196226
197const_prog_node: std.Progress.Node,227const_prog_node: std.Progress.Node,
198synth_prog_node: std.Progress.Node,
199input_prog_node: std.Progress.Node,228input_prog_node: std.Progress.Node,
200229
201const Error = link.Error || error{MappedFileIo};230const Error = link.Error || error{MappedFileIo};
202231
203const Node = union(enum) {232const Node = union(enum) {
233 deleted,
234
204 /// Only used when emitting a static library.235 /// Only used when emitting a static library.
205 ///236 ///
206 /// Contains a header node which is an `.archive_header`.237 /// Contains a header node which is an `.archive_header`.
...@@ -232,8 +263,9 @@ const Node = union(enum) {...@@ -232,8 +263,9 @@ const Node = union(enum) {
232 ehdr,263 ehdr,
233 shdr,264 shdr,
234 segment: u32,265 segment: u32,
235 /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`.
236 section: Section.Index,266 section: Section.Index,
267 /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`.
268 section_manual_size: Section.Index,
237 /// May contain relocations.269 /// May contain relocations.
238 input_section: InputSection.Index,270 input_section: InputSection.Index,
239 /// Value is the name of a global which has an entry in `elf.copied_globals`, so, a global for271 /// Value is the name of a global which has an entry in `elf.copied_globals`, so, a global for
...@@ -253,6 +285,25 @@ const Node = union(enum) {...@@ -253,6 +285,25 @@ const Node = union(enum) {
253 /// May contain relocations.285 /// May contain relocations.
254 lazy_const_data: LazyMapRef.Index(.const_data),286 lazy_const_data: LazyMapRef.Index(.const_data),
255287
288 debug_shared: Dwarf.SharedSection,
289 eh_frame_footer,
290 unit_padding,
291 unit_frame: Dwarf.Unit.Index,
292 unit_frame_cie: Dwarf.Unit.Index,
293 unit_debug_info: Dwarf.Unit.Index,
294 unit_debug_info_header: Dwarf.Unit.Index,
295 unit_debug_info_footer: Dwarf.Unit.Index,
296 unit_debug_line: Dwarf.Unit.Index,
297 unit_debug_line_header: Dwarf.Unit.Index,
298 unit_debug_rnglists: Dwarf.Unit.Index,
299
300 const_debug_info: link.ConstPool.Index,
301 global_debug_info: Dwarf.Global.Index,
302 func_frame_fde: Dwarf.Func.Index,
303 func_debug_info: Dwarf.Func.Index,
304 func_debug_line: Dwarf.Func.Index,
305 decl_debug_info: Dwarf.Decl.Index,
306
256 pub const InputIndex = enum(u32) {307 pub const InputIndex = enum(u32) {
257 _,308 _,
258309
...@@ -288,7 +339,7 @@ const Node = union(enum) {...@@ -288,7 +339,7 @@ const Node = union(enum) {
288 pub const NavMapIndex = enum(u32) {339 pub const NavMapIndex = enum(u32) {
289 _,340 _,
290341
291 pub fn navIndex(nmi: NavMapIndex, elf: *const Elf) InternPool.Nav.Index {342 pub fn nav(nmi: NavMapIndex, elf: *const Elf) InternPool.Nav.Index {
292 return elf.navs.keys()[@backingInt(nmi)];343 return elf.navs.keys()[@backingInt(nmi)];
293 }344 }
294345
...@@ -363,18 +414,6 @@ const Node = union(enum) {...@@ -363,18 +414,6 @@ const Node = union(enum) {
363 }414 }
364 };415 };
365416
366 pub const Known = struct {
367 elf: MappedFile.Node.Index,
368 ehdr: MappedFile.Node.Index,
369 shdr: MappedFile.Node.Index,
370 rodata: MappedFile.Node.Index,
371 phdr: MappedFile.Node.Index,
372 text: MappedFile.Node.Index,
373 data: MappedFile.Node.Index,
374 data_rel_ro: MappedFile.Node.Index,
375 tls: MappedFile.Node.Index.Optional,
376 };
377
378 comptime {417 comptime {
379 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8);418 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8);
380 }419 }
...@@ -439,7 +478,7 @@ const Section = struct {...@@ -439,7 +478,7 @@ const Section = struct {
439 ni: MappedFile.Node.Index,478 ni: MappedFile.Node.Index,
440 /// A symbol which is exactly at the start of this section.479 /// A symbol which is exactly at the start of this section.
441 ///480 ///
442 /// If the section does not have flag `std.elf.SHF.ALLOC`, this is `.null`.481 /// When not emitting a relocatable, or for special section types, this is `.null`.
443 lsi: Symbol.LocalIndex,482 lsi: Symbol.LocalIndex,
444 rela: union {483 rela: union {
445 /// This field is active if and only if this section is *not* a `SHT_RELA` section.484 /// This field is active if and only if this section is *not* a `SHT_RELA` section.
...@@ -526,8 +565,8 @@ const Section = struct {...@@ -526,8 +565,8 @@ const Section = struct {
526 std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @fromBackingInt(reserve(sec)),565 std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @fromBackingInt(reserve(sec)),
527 };566 };
528 }567 }
529 pub fn toSection(s: Index) ?std.elf.Section {568 pub fn toSection(shndx: Index) ?std.elf.Section {
530 return switch (@backingInt(s)) {569 return switch (@backingInt(shndx)) {
531 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => |sec| @intCast(sec),570 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => |sec| @intCast(sec),
532 std.elf.SHN_LORESERVE...reserve(std.elf.SHN_LORESERVE) - 1 => null,571 std.elf.SHN_LORESERVE...reserve(std.elf.SHN_LORESERVE) - 1 => null,
533 reserve(std.elf.SHN_LORESERVE)...reserve(std.elf.SHN_HIRESERVE) => |sec| @intCast(572 reserve(std.elf.SHN_LORESERVE)...reserve(std.elf.SHN_HIRESERVE) => |sec| @intCast(
...@@ -536,28 +575,40 @@ const Section = struct {...@@ -536,28 +575,40 @@ const Section = struct {
536 };575 };
537 }576 }
538577
539 fn get(s: Index, elf: *Elf) *Section {578 fn get(shndx: Index, elf: *Elf) *Section {
540 return &elf.shdrs.items[@backingInt(s) - 1]; // overflow means you tried to get the `.UNDEF` section579 return &elf.shdrs.items[@backingInt(shndx) - 1]; // overflow means you tried to get the `.UNDEF` section
541 }580 }
542581
543 fn name(s: Index, elf: *Elf) String(.shstrtab) {582 fn name(shndx: Index, elf: *Elf) String(.shstrtab) {
544 return switch (elf.shdrPtr(s)) {583 return switch (elf.shdrPtr(shndx)) {
545 inline else => |shdr| @fromBackingInt(elf.targetLoad(&shdr.name)),584 inline else => |shdr| @fromBackingInt(elf.targetLoad(&shdr.name)),
546 };585 };
547 }586 }
548587
549 fn vaddr(s: Index, elf: *Elf) u64 {588 fn vaddr(shndx: Index, elf: *Elf) u64 {
550 return switch (elf.shdrPtr(s)) {589 return switch (elf.shdrPtr(shndx)) {
551 inline else => |shdr| elf.targetLoad(&shdr.addr),590 inline else => |shdr| elf.targetLoad(&shdr.addr),
552 };591 };
553 }592 }
554593
555 fn size(s: Index, elf: *Elf) u64 {594 fn size(shndx: Index, elf: *Elf) u64 {
556 return switch (elf.shdrPtr(s)) {595 return switch (elf.shdrPtr(shndx)) {
557 inline else => |shdr| elf.targetLoad(&shdr.size),596 inline else => |shdr| elf.targetLoad(&shdr.size),
558 };597 };
559 }598 }
560599
600 fn setSize(shndx: Index, elf: *Elf, new_size: u64) void {
601 return switch (elf.shdrPtr(shndx)) {
602 inline else => |shdr| {
603 elf.targetStore(&shdr.type, switch (new_size) {
604 0 => .NULL,
605 else => .PROGBITS,
606 });
607 elf.targetStore(&shdr.size, @intCast(new_size));
608 },
609 };
610 }
611
561 fn flags(s: Index, elf: *Elf) std.elf.SHF {612 fn flags(s: Index, elf: *Elf) std.elf.SHF {
562 return switch (elf.shdrPtr(s)) {613 return switch (elf.shdrPtr(s)) {
563 inline else => |shdr| elf.targetLoad(&shdr.flags).shf,614 inline else => |shdr| elf.targetLoad(&shdr.flags).shf,
...@@ -582,7 +633,7 @@ const Section = struct {...@@ -582,7 +633,7 @@ const Section = struct {
582 }633 }
583 const ni = shndx.get(elf).ni;634 const ni = shndx.get(elf).ni;
584 if (min_align.compare(.gt, ni.alignment(&elf.mf))) {635 if (min_align.compare(.gt, ni.alignment(&elf.mf))) {
585 try ni.realign(&elf.mf, elf.base.comp.gpa, min_align);636 try ni.realign(elf.base.comp.gpa, &elf.mf, min_align);
586 }637 }
587 switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {638 switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {
588 .elf => {},639 .elf => {},
...@@ -615,7 +666,7 @@ const Section = struct {...@@ -615,7 +666,7 @@ const Section = struct {
615 break :need_size cur_size + need_additional * ent_size;666 break :need_size cur_size + need_additional * ent_size;
616 },667 },
617 };668 };
618 try node.ensureMinimumSize(&elf.mf, elf.base.comp.gpa, need_size);669 try node.ensureMinimumSize(elf.base.comp.gpa, &elf.mf, need_size);
619 }670 }
620671
621 /// Asserts that `rela_shndx` is a `SHT_RELA` section and deletes the `ElfN.Rela` entry at672 /// Asserts that `rela_shndx` is a `SHT_RELA` section and deletes the `ElfN.Rela` entry at
...@@ -649,7 +700,7 @@ const Section = struct {...@@ -649,7 +700,7 @@ const Section = struct {
649 },700 },
650 .addend = @intCast(old_free_len + 1), // list length701 .addend = @intCast(old_free_len + 1), // list length
651 };702 };
652 if (elf.targetEndian() != native_endian) {703 if (elf.targetEndian() != std.lang.Endian.native) {
653 std.mem.byteSwapAllFields(class.ElfN().Rela, &relas[@backingInt(index)]);704 std.mem.byteSwapAllFields(class.ElfN().Rela, &relas[@backingInt(index)]);
654 }705 }
655 },706 },
...@@ -708,7 +759,7 @@ const Section = struct {...@@ -708,7 +759,7 @@ const Section = struct {
708 },759 },
709 .addend = @intCast(opts.addend),760 .addend = @intCast(opts.addend),
710 };761 };
711 if (elf.targetEndian() != native_endian) {762 if (elf.targetEndian() != std.lang.Endian.native) {
712 std.mem.byteSwapAllFields(class.ElfN().Rela, &relas[@backingInt(new_index)]);763 std.mem.byteSwapAllFields(class.ElfN().Rela, &relas[@backingInt(new_index)]);
713 }764 }
714 return new_index;765 return new_index;
...@@ -786,10 +837,10 @@ const Section = struct {...@@ -786,10 +837,10 @@ const Section = struct {
786 }837 }
787 }838 }
788839
789 /// Asserts that `rela_shndx` is a `SHT_RELA` section, and asserts that `index` refers to an840 /// Asserts that `rela_shndx` is a `SHT_RELA` section and updates the `addend` field of the
790 /// `R_*_RELATIVE` relocation inside of it; then, updates that relocation's addend (which is841 /// `ElfN.Rela` entry at the given index. Asserts that `index` is not in the free-list (i.e.
791 /// an address in this DSO without the runtime load offset applied) to the given value.842 /// it is not deleted).
792 fn relaSetRelativeOffset(rela_shndx: Index, elf: *Elf, index: RelaIndex, new_addend: u64) void {843 fn relaSetAddend(rela_shndx: Index, elf: *Elf, index: RelaIndex, new_addend: u64) void {
793 switch (elf.shdrPtr(rela_shndx)) {844 switch (elf.shdrPtr(rela_shndx)) {
794 inline else => |shdr, class| {845 inline else => |shdr, class| {
795 assert(elf.targetLoad(&shdr.type) == .RELA);846 assert(elf.targetLoad(&shdr.type) == .RELA);
...@@ -807,44 +858,322 @@ const Section = struct {...@@ -807,44 +858,322 @@ const Section = struct {
807 },858 },
808 }859 }
809 }860 }
861
862 fn debugFrameFormat(shndx: Index, elf: *Elf) ?Dwarf.Frame.Format {
863 if (shndx == elf.shndx.eh_frame) return .eh_frame;
864 if (shndx == elf.shndx.debug_frame) return .debug_frame;
865 return null;
866 }
810 };867 };
811};868};
869fn debugFrameFooterSize(elf: *Elf, frame_format: Dwarf.Frame.Format) usize {
870 return switch (frame_format) {
871 .eh_frame => switch (elf.ehdrType()) {
872 .REL => 0,
873 .EXEC, .DYN => 4,
874 },
875 .debug_frame => 0,
876 };
877}
812878
813/// Identifies a single entry in the GOT.879const dwarf_relocs = struct {
814const GotKey = union(enum) {880 const Shared = struct {
815 /// The entry is a reserved word, initialized to zero. `initHeaders` will add as many of these881 first_target_reloc: NodeReloc.Index,
816 /// as the target machine ABI requires.882 };
817 ///883 const Unit = struct {
818 /// This `u32` value exists to allow reserving multiple words with distinct keys.884 frame_cie_first_target_reloc: NodeReloc.Index,
819 reserved: u32,885 debug_info_header_first_target_reloc: NodeReloc.Index,
886 debug_info_header_first_node_reloc: NodeReloc.Index,
887 debug_line_header_first_target_reloc: NodeReloc.Index,
888 debug_line_header_first_node_reloc: NodeReloc.Index,
889 debug_rnglists_first_target_reloc: NodeReloc.Index,
890 debug_rnglists_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),
891 };
892 const Const = struct {
893 debug_info_first_target_reloc: NodeReloc.Index,
894 debug_info_first_symbol_reloc: SymbolReloc.Index,
895 debug_info_first_node_reloc: NodeReloc.Index,
896 };
897 const Global = struct {
898 debug_info_first_target_reloc: NodeReloc.Index,
899 debug_info_first_symbol_reloc: SymbolReloc.Index,
900 debug_info_first_node_reloc: NodeReloc.Index,
901 };
902 const Func = struct {
903 frame_fde_first_symbol_reloc: SymbolReloc.Index,
904 frame_fde_first_node_reloc: NodeReloc.Index,
905 debug_info_first_target_reloc: NodeReloc.Index,
906 debug_info_first_symbol_reloc: SymbolReloc.Index,
907 debug_info_first_node_reloc: NodeReloc.Index,
908 debug_line_first_symbol_reloc: SymbolReloc.Index,
909 debug_line_first_node_reloc: NodeReloc.Index,
910 };
911 const Decl = struct {
912 debug_info_first_target_reloc: NodeReloc.Index,
913 debug_info_first_node_reloc: NodeReloc.Index,
914 };
915};
820916
821 /// Value is the address of the given symbol.917pub const MachineRelocType = union {
822 symbol: Symbol.Id,918 AARCH64: std.elf.R_AARCH64,
919 LARCH: std.elf.R_LARCH,
920 PPC64: std.elf.R_PPC64,
921 RISCV: std.elf.R_RISCV,
922 SPARC: std.elf.R_SPARC,
923 X86_64: std.elf.R_X86_64,
823924
824 /// Value is the signed offset of the given symbol from the TLS pointer.925 pub const Format = struct {
825 tpoff: Symbol.Id,926 rt: MachineRelocType,
927 elf: *const Elf,
826928
827 /// Value is the TLS module ID of the DSO we are creating.929 pub fn format(f: Format, w: *Io.Writer) Io.Writer.Error!void {
828 ///930 switch (f.elf.ehdrMachine()) {
829 /// Used for the first of the two GOT entries generated by a TLSLD relocation.931 .AARCH64 => try w.print("R_AARCH64_{t}", .{f.rt.AARCH64}),
830 tlsld0,932 .LOONGARCH => try w.print("R_LARCH_{t}", .{f.rt.LARCH}),
831 /// Value is always 0.933 .PPC64 => try w.print("R_PPC64_{t}", .{f.rt.PPC64}),
832 ///934 .RISCV => try w.print("R_RISCV_{t}", .{f.rt.RISCV}),
833 /// Used for the second of the two GOT entries generated by a TLSLD relocation.935 .SPARCV9 => try w.print("R_SPARC_{t}", .{f.rt.SPARC}),
834 tlsld1,936 .X86_64 => try w.print("R_X86_64_{t}", .{f.rt.X86_64}),
937 }
938 }
939 };
835940
836 /// Value is the TLS module ID for the given STT_TLS symbol.941 pub fn fmt(rt: MachineRelocType, elf: *const Elf) Format {
837 ///942 return .{ .rt = rt, .elf = elf };
838 /// Used for the first of the two GOT entries generated by a TLSGD relocation.943 }
839 tlsgd0: Symbol.Id,944
840 /// Value is the offset of the given STT_TLS symbol from the base of the per-module TLS area.945 pub fn none(elf: *const Elf) MachineRelocType {
841 ///946 return switch (elf.ehdrMachine()) {
842 /// Used for the second of the two GOT entries generated by a TLSGD relocation.947 .AARCH64 => .{ .AARCH64 = .NONE },
843 tlsgd1: Symbol.Id,948 .LOONGARCH => .{ .LARCH = .NONE },
949 .PPC64 => .{ .PPC64 = .NONE },
950 .RISCV => .{ .RISCV = .NONE },
951 .SPARCV9 => .{ .SPARC = .NONE },
952 .X86_64 => .{ .X86_64 = .NONE },
953 };
954 }
955 pub fn copy(elf: *const Elf) MachineRelocType {
956 return switch (elf.ehdrMachine()) {
957 .AARCH64 => .{ .AARCH64 = .COPY },
958 .LOONGARCH => .{ .LARCH = .COPY },
959 .PPC64 => .{ .PPC64 = .COPY },
960 .RISCV => .{ .RISCV = .COPY },
961 .SPARCV9 => .{ .SPARC = .COPY },
962 .X86_64 => .{ .X86_64 = .COPY },
963 };
964 }
965 pub fn relative(elf: *const Elf) MachineRelocType {
966 return switch (elf.ehdrMachine()) {
967 .AARCH64 => .{ .AARCH64 = .RELATIVE },
968 .LOONGARCH => .{ .LARCH = .RELATIVE },
969 .PPC64 => .{ .PPC64 = .RELATIVE },
970 .RISCV => .{ .RISCV = .RELATIVE },
971 .SPARCV9 => .{ .SPARC = .RELATIVE },
972 .X86_64 => .{ .X86_64 = .RELATIVE },
973 };
974 }
975 pub fn jumpSlot(elf: *const Elf) MachineRelocType {
976 return switch (elf.ehdrMachine()) {
977 .AARCH64 => .{ .AARCH64 = .JUMP_SLOT },
978 .LOONGARCH => .{ .LARCH = .JUMP_SLOT },
979 .PPC64 => .{ .PPC64 = .JMP_SLOT },
980 .RISCV => .{ .RISCV = .JUMP_SLOT },
981 .SPARCV9 => .{ .SPARC = .JMP_SLOT },
982 .X86_64 => .{ .X86_64 = .JUMP_SLOT },
983 };
984 }
985 pub fn globDat(elf: *const Elf) MachineRelocType {
986 return switch (elf.ehdrMachine()) {
987 .AARCH64 => .{ .AARCH64 = .GLOB_DAT },
988 .LOONGARCH => .{ .LARCH = switch (elf.identClass()) {
989 .NONE, _ => unreachable,
990 .@"32" => .@"32",
991 .@"64" => .@"64",
992 } },
993 .PPC64 => .{ .PPC64 = .GLOB_DAT },
994 .RISCV => .{ .RISCV = switch (elf.identClass()) {
995 .NONE, _ => unreachable,
996 .@"32" => .@"32",
997 .@"64" => .@"64",
998 } },
999 .SPARCV9 => .{ .SPARC = .GLOB_DAT },
1000 .X86_64 => .{ .X86_64 = .GLOB_DAT },
1001 };
1002 }
1003 pub fn dtpMod(elf: *const Elf) MachineRelocType {
1004 return switch (elf.ehdrMachine()) {
1005 .AARCH64 => .{ .AARCH64 = switch (elf.identClass()) {
1006 .NONE, _ => unreachable,
1007 .@"32" => .P32_TLS_DTPMOD,
1008 .@"64" => .TLS_DTPMOD,
1009 } },
1010 .LOONGARCH => .{ .LARCH = switch (elf.identClass()) {
1011 .NONE, _ => unreachable,
1012 .@"32" => .TLS_DTPMOD32,
1013 .@"64" => .TLS_DTPMOD64,
1014 } },
1015 .PPC64 => .{ .PPC64 = .DTPMOD64 },
1016 .RISCV => .{ .RISCV = switch (elf.identClass()) {
1017 .NONE, _ => unreachable,
1018 .@"32" => .TLS_DTPMOD32,
1019 .@"64" => .TLS_DTPMOD64,
1020 } },
1021 .SPARCV9 => .{ .SPARC = switch (elf.identClass()) {
1022 .NONE, _ => unreachable,
1023 .@"32" => .TLS_DTPMOD32,
1024 .@"64" => .TLS_DTPMOD64,
1025 } },
1026 .X86_64 => .{ .X86_64 = .DTPMOD64 },
1027 };
1028 }
1029 pub fn dtpOff(elf: *const Elf) MachineRelocType {
1030 return switch (elf.ehdrMachine()) {
1031 .AARCH64 => .{ .AARCH64 = switch (elf.identClass()) {
1032 .NONE, _ => unreachable,
1033 .@"32" => .P32_TLS_DTPREL,
1034 .@"64" => .TLS_DTPREL,
1035 } },
1036 .LOONGARCH => .{ .LARCH = switch (elf.identClass()) {
1037 .NONE, _ => unreachable,
1038 .@"32" => .TLS_DTPREL32,
1039 .@"64" => .TLS_DTPREL64,
1040 } },
1041 .PPC64 => .{ .PPC64 = .DTPREL64 },
1042 .RISCV => .{ .RISCV = switch (elf.identClass()) {
1043 .NONE, _ => unreachable,
1044 .@"32" => .TLS_DTPREL32,
1045 .@"64" => .TLS_DTPREL64,
1046 } },
1047 .SPARCV9 => .{ .SPARC = switch (elf.identClass()) {
1048 .NONE, _ => unreachable,
1049 .@"32" => .TLS_DTPOFF32,
1050 .@"64" => .TLS_DTPOFF64,
1051 } },
1052 .X86_64 => .{ .X86_64 = .DTPOFF64 },
1053 };
1054 }
1055 pub fn tpOff(elf: *const Elf) MachineRelocType {
1056 return switch (elf.ehdrMachine()) {
1057 .AARCH64 => .{ .AARCH64 = switch (elf.identClass()) {
1058 .NONE, _ => unreachable,
1059 .@"32" => .P32_TLS_TPREL,
1060 .@"64" => .TLS_TPREL,
1061 } },
1062 .LOONGARCH => .{ .LARCH = switch (elf.identClass()) {
1063 .NONE, _ => unreachable,
1064 .@"32" => .TLS_TPREL32,
1065 .@"64" => .TLS_TPREL64,
1066 } },
1067 .PPC64 => .{ .PPC64 = .TPREL64 },
1068 .RISCV => .{ .RISCV = switch (elf.identClass()) {
1069 .NONE, _ => unreachable,
1070 .@"32" => .TLS_TPREL32,
1071 .@"64" => .TLS_TPREL64,
1072 } },
1073 .SPARCV9 => .{ .SPARC = switch (elf.identClass()) {
1074 .NONE, _ => unreachable,
1075 .@"32" => .TLS_TPOFF32,
1076 .@"64" => .TLS_TPOFF64,
1077 } },
1078 .X86_64 => .{ .X86_64 = .TPOFF64 },
1079 };
1080 }
1081 pub fn absAddr(elf: *const Elf) MachineRelocType {
1082 return switch (elf.identClass()) {
1083 .NONE, _ => unreachable,
1084 .@"32" => .abs32(elf),
1085 .@"64" => .abs64(elf),
1086 };
1087 }
1088 pub fn abs32(elf: *const Elf) MachineRelocType {
1089 return switch (elf.ehdrMachine()) {
1090 .AARCH64 => .{ .AARCH64 = .P32_ABS32 },
1091 .LOONGARCH => .{ .LARCH = .@"32" },
1092 .PPC64 => .{ .PPC64 = .ADDR32 },
1093 .RISCV => .{ .RISCV = .@"32" },
1094 .SPARCV9 => .{ .SPARC = .@"32" },
1095 .X86_64 => .{ .X86_64 = .@"32" },
1096 };
1097 }
1098 pub fn abs64(elf: *const Elf) MachineRelocType {
1099 return switch (elf.ehdrMachine()) {
1100 .AARCH64 => .{ .AARCH64 = .ABS64 },
1101 .LOONGARCH => .{ .LARCH = .@"64" },
1102 .PPC64 => .{ .PPC64 = .ADDR64 },
1103 .RISCV => .{ .RISCV = .@"64" },
1104 .SPARCV9 => .{ .SPARC = .@"64" },
1105 .X86_64 => .{ .X86_64 = .@"64" },
1106 };
1107 }
1108 pub fn rel32(elf: *const Elf) MachineRelocType {
1109 return switch (elf.ehdrMachine()) {
1110 .AARCH64 => .{ .AARCH64 = .PREL32 },
1111 .LOONGARCH => .{ .LARCH = .@"32_PCREL" },
1112 .PPC64 => .{ .PPC64 = .REL32 },
1113 .RISCV => .{ .RISCV = .@"32_PCREL" },
1114 .SPARCV9 => .{ .SPARC = .DISP32 },
1115 .X86_64 => .{ .X86_64 = .PC32 },
1116 };
1117 }
1118 pub fn rel64(elf: *const Elf) MachineRelocType {
1119 return switch (elf.ehdrMachine()) {
1120 .AARCH64 => .{ .AARCH64 = .PREL64 },
1121 .LOONGARCH => unreachable,
1122 .PPC64 => .{ .PPC64 = .REL64 },
1123 .RISCV => unreachable,
1124 .SPARCV9 => .{ .SPARC = .DISP64 },
1125 .X86_64 => .{ .X86_64 = .PC64 },
1126 };
1127 }
1128 pub fn size32(elf: *const Elf) ?MachineRelocType {
1129 return switch (elf.ehdrMachine()) {
1130 .AARCH64,
1131 .LOONGARCH,
1132 .PPC64,
1133 .RISCV,
1134 => null,
1135
1136 .SPARCV9 => .{ .SPARC = .SIZE32 },
1137 .X86_64 => .{ .X86_64 = .SIZE32 },
1138 };
1139 }
1140 pub fn size64(elf: *const Elf) ?MachineRelocType {
1141 return switch (elf.ehdrMachine()) {
1142 .AARCH64,
1143 .LOONGARCH,
1144 .PPC64,
1145 .RISCV,
1146 => null,
1147
1148 .SPARCV9 => .{ .SPARC = .SIZE64 },
1149 .X86_64 => .{ .X86_64 = .SIZE64 },
1150 };
1151 }
1152
1153 pub fn wrap(int: u32, elf: *const Elf) MachineRelocType {
1154 return switch (elf.ehdrMachine()) {
1155 .AARCH64 => .{ .AARCH64 = @fromBackingInt(int) },
1156 .LOONGARCH => .{ .LARCH = @fromBackingInt(int) },
1157 .PPC64 => .{ .PPC64 = @fromBackingInt(int) },
1158 .RISCV => .{ .RISCV = @fromBackingInt(int) },
1159 .SPARCV9 => .{ .SPARC = @fromBackingInt(int) },
1160 .X86_64 => .{ .X86_64 = @fromBackingInt(int) },
1161 };
1162 }
1163 pub fn unwrap(rt: MachineRelocType, elf: *const Elf) u32 {
1164 return switch (elf.ehdrMachine()) {
1165 .AARCH64 => @backingInt(rt.AARCH64),
1166 .LOONGARCH => @backingInt(rt.LARCH),
1167 .PPC64 => @backingInt(rt.PPC64),
1168 .RISCV => @backingInt(rt.RISCV),
1169 .SPARCV9 => @backingInt(rt.SPARC),
1170 .X86_64 => @backingInt(rt.X86_64),
1171 };
1172 }
844};1173};
8451174
846/// A relocation targeting a particular GOT entry.1175/// A relocation targeting an arbitrary symbol with a fixed addend.
847const GotReloc = struct {1176const SymbolReloc = struct {
848 /// The node containing this relocation. Possible values are:1177 /// The node containing this relocation. Possible values are:
849 /// * An input section1178 /// * An input section
850 /// * A section1179 /// * A section
...@@ -853,137 +1182,488 @@ const GotReloc = struct {...@@ -853,137 +1182,488 @@ const GotReloc = struct {
853 node: MappedFile.Node.Index.Optional,1182 node: MappedFile.Node.Index.Optional,
854 /// The offset of the relocation inside of `node`.1183 /// The offset of the relocation inside of `node`.
855 offset: u64,1184 offset: u64,
856 target: GotKey,1185 /// A symbol used to compute the relocated value. Precise meaning depends on `@"type"`.
1186 target: Symbol.Id,
1187 /// A signed constant used to compute the relocated value. Precise meaning depends on `@"type"`.
857 addend: i64,1188 addend: i64,
858 type: GotReloc.Type,1189 /// Specifies how to apply the relocation.
859 result: enum(u8) { ok, overflowed, misaligned },1190 ///
8601191 /// When emitting a relocatable, this field is `undefined`.
861 /// `GotReloc.Type` has the same structure as `SymbolReloc.Type`, just with different `Target`1192 type: SymbolReloc.Type,
862 /// and `Special` enums---consult doc comments on `SymbolReloc.Type` for an overview.1193 /// Forms a linked list of all symbol relocations with the same `target`. This list exists so
1194 /// that all relocations targeting a particular symbol can be re-applied if that symbol moves.
1195 /// Doubly-linked so that relocations can be removed.
1196 next: SymbolReloc.Index,
1197 /// Back-reference in a doubly-linked list---see `next`.
1198 prev: SymbolReloc.Index,
1199 /// If this relocation has a corresponding output relocation, this is its index within the
1200 /// appropriate SHT_RELA section (see `relaSection`). If there is no output relocation
1201 /// corresponding to this relocation, this is `.none`.
1202 ///
1203 /// If we are producing a relocatable, this field is always populated, because all relocations
1204 /// are emitted as output relocations.
1205 ///
1206 /// If we are producing a DSO, this field is populated if this relocation requires a runtime
1207 /// relocation entry. The entry will be removed if we discover a definition which allows us to
1208 /// statically resolve the relocation.
1209 rela_index: Section.RelaIndex.Optional,
1210 result: enum(u8) { ok, overflowed, misaligned },
1211
1212 /// Determines the section in which this relocation will be placed if it is outstanding.
1213 ///
1214 /// When producing a relocatable (ET_REL), the relocation section is `Section.rela.shndx` for
1215 /// the section of `node`, and this function asserts that the aforementioned `rela.shndx` field
1216 /// is populated.
1217 ///
1218 /// When producing a DSO, the relocation section is always `.rela.dyn`. It is not `.rela.plt`
1219 /// because relocations in the GOTPLT are handled specially, without `SymbolReloc` entries.
1220 fn relaSection(sr: *const SymbolReloc, elf: *Elf) Section.Index {
1221 const shndx = switch (elf.ehdrType()) {
1222 .REL => elf.getNodeShndx(sr.node.unwrap().?).get(elf).rela.shndx,
1223 .EXEC, .DYN => elf.shndx.rela_dyn,
1224 };
1225 assert(shndx != .UNDEF);
1226 return shndx;
1227 }
1228
1229 /// Instead of using the ELF relocation enums, we have our own internal representation for
1230 /// relocation types. This representation is more compact (requiring only 16 bits), and allows
1231 /// sharing a lot of relocation handling between multiple relocs and target architectures.
1232 ///
1233 /// A relocation type can be "simple" or "special".
1234 ///
1235 /// "Simple" relocations are designed to cover the majority of cases. They can represent most
1236 /// relocations which either write 8-bit, 16-bit, 32-bit, or 64-bit integers, or which write one
1237 /// contiguous bit-field within such an integer (e.g. an instruction operand). For more details,
1238 /// see `Simple`.
1239 ///
1240 /// "Special" relocations handle anything which does not fit into the above category, such as
1241 /// relocations which write multiple sequences of bits or which need to do unusual arithmetic on
1242 /// a symbol value. The representation is simply a big enum containing all of these exceptional
1243 /// cases---see `Special`. This representation is in use when `Type.target == .special`.
863 const Type = packed struct(u16) {1244 const Type = packed struct(u16) {
864 fn simple(target: Target, action: Simple) GotReloc.Type {1245 /// Helper function for constructing a "simple" relocation type. This mainly exists to
1246 /// improve readability in the relocation lowering logic in `addRelocAssumeCapacity`.
1247 fn simple(target: Target, action: Simple) SymbolReloc.Type {
865 assert(target != .special);1248 assert(target != .special);
866 return .{ .target = target, .action = .{ .simple = action } };1249 return .{ .target = target, .action = .{ .simple = action } };
867 }1250 }
8681251
869 fn special(s: Special) GotReloc.Type {1252 /// Helper function for constructing a "special" relocation type. This mainly exists to
1253 /// improve readability in the relocation lowering logic in `addRelocAssumeCapacity`.
1254 fn special(s: Special) SymbolReloc.Type {
870 return .{ .target = .special, .action = .{ .special = s } };1255 return .{ .target = .special, .action = .{ .special = s } };
871 }1256 }
8721257
1258 /// See doc comment on `Target`.
873 target: Target,1259 target: Target,
1260 /// If `target == .special`, the `special` field is used.
1261 ///
1262 /// Otherwise, the `.simple` field is used.
874 action: packed union {1263 action: packed union {
875 simple: Simple,1264 simple: Simple,
876 special: Special,1265 special: Special,
877 },1266 },
8781267
879 /// Like `SymbolReloc.Target`, but for GOT relocations. There are fewer tags because there1268 /// If a relocation is "special", indicates that using the value `.@"special"`.
880 /// are fewer different kinds of GOT relocation.1269 ///
1270 /// Otherwise (for "simple" relocations), `Target` indicates the first step in computing the
1271 /// relocation---whether we care about the target symbol's absolute address, its PC-relative
1272 /// address, its PLT entry, etc.
881 const Target = enum(u3) {1273 const Target = enum(u3) {
882 /// This is a "special" relocation whose specific type is in the `action.special` field.1274 /// This is a "special" relocation whose specific type is in the `action.special` field.
883 special,1275 special,
8841276
885 /// Absolute address of the GOT entry.1277 /// Absolute value of the target symbol.
886 abs,1278 abs,
887 /// Offset from the relocation itself to the GOT entry ("PC-relative").1279 /// Offset from the relocation itself to the target symbol ("PC-relative").
888 rel,1280 rel,
889 /// Offset from the base of the GOT to the GOT entry.1281 /// Address of the target symbol's PLT entry.
890 offset,1282 ///
1283 /// If the target symbol does not have a PLT entry, equivalent to `.abs`.
1284 pltabs,
1285 /// Offset from the relocation itself to the target symbol's PLT entry ("PC-relative").
1286 ///
1287 /// If the target symbol does not have a PLT entry, equivalent to `.rel`.
1288 pltrel,
1289 /// Offset of the target TLS symbol from the base of this DSO's own TLS region.
1290 dtpoff,
1291 /// Offset of the target TLS symbol from the raw thread pointer.
1292 tpoff,
1293 /// Size of the target symbol.
1294 size,
891 };1295 };
8921296
893 const Simple = SymbolReloc.Type.Simple;1297 /// For a "simple" relocation, after the initial value is computed according to `Target`, a
8941298 /// `Simple` value communicates how to shift, truncate, and store that value into memory.
895 /// Like `SymbolReloc.Special`, but for GOT relocations.1299 const Simple = packed struct(u13) {
896 const Special = enum(u13) {1300 /// The field being written to, represented as a sequence of bits in a backing integer
897 larch_pcala_hi20,1301 /// of 8, 16, 32, or 64 bits.
898 larch_pcala64_lo20,1302 ///
899 larch_pcala64_hi12,1303 /// The `.@"8"`, `.@"16"`, `.@"32"`, and `.@"64"` fields simply write to all bits of the
1304 /// backing integer; i.e. the existing value is entirely overwritten.
1305 ///
1306 /// Other fields are named like "B[H:L]", where "B" is the backing integer type, and
1307 /// "H" and "L" are the indices of the highest and lowest bits in the bit field (in
1308 /// other words, an inclusive bit range). This notation was chosen because it seems to
1309 /// be one of the more common ways that bit relocations are written in ABIs.
1310 ///
1311 /// e.g. 8[6:3] writes the relocated value to this 4-bit field in an 8-bit integer:
1312 ///
1313 /// MSB ___ ### ### ### ### ___ ___ ___ LSB
1314 /// 7 6 5 4 3 2 1 0
1315 /// bit index
1316 ///
1317 /// This enum is not intended to be able to represent every possible bit field in the
1318 /// backing integer types. Instead, to keep `SymbolReloc.Type` compact, fields are added
1319 /// to this enum only as needed. If the enum ever becomes full, some lesser-used tags
1320 /// can have their handling moved into `Special` to free up space.
1321 dest: enum(u6) {
1322 @"8",
1323 @"16",
1324 @"32",
1325 @"64",
9001326
901 sparc_op_lox10,1327 @"32[4:0]",
902 sparc_op_hix22,1328 @"32[5:0]",
1329 @"32[6:0]",
1330 @"32[9:0]",
1331 @"32[10:0]",
1332 @"32[11:0]",
1333 @"32[12:0]",
1334 @"32[21:0]",
1335 @"32[21:10]",
1336 @"32[24:5]",
1337 @"32[25:10]",
1338 @"32[29:0]",
9031339
904 fn applyInner(1340 /// Returns `true` iff `dest` writes a full address for the target.
905 s: Special,1341 ///
906 elf: *Elf,1342 /// i.e. checks for `.@"32"` on 32-bit targets; for `.@"64"` on 64-bit targets.
907 got_vaddr: u64,1343 fn isAddr(dest: @This(), elf: *const Elf) bool {
908 got_offset: u64,1344 return switch (elf.identClass()) {
909 addend: u64,1345 .NONE, _ => unreachable,
910 dest_vaddr: u64,1346 .@"32" => dest == .@"32",
911 dest_slice: []u8,1347 .@"64" => dest == .@"64",
912 ) error{ RelocationMisaligned, RelocationOverflow }!void {1348 };
913 switch (s) {
914 .larch_pcala_hi20 => {
915 const val = got_vaddr +% got_offset +% addend;
916 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
917 elf.targetStore(inst, .{
918 .b0_4 = elf.targetLoad(inst).b0_4,
919 .j20 = link.loongarch.pcalaHi20(val, dest_vaddr),
920 .b25_31 = elf.targetLoad(inst).b25_31,
921 });
922 },
923 .larch_pcala64_lo20 => {
924 const val = got_vaddr +% got_offset +% addend;
925 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
926 elf.targetStore(inst, .{
927 .b0_4 = elf.targetLoad(inst).b0_4,
928 .j20 = link.loongarch.pcala64Lo20(val, dest_vaddr),
929 .b25_31 = elf.targetLoad(inst).b25_31,
930 });
931 },
932 .larch_pcala64_hi12 => {
933 const val = got_vaddr +% got_offset +% addend;
934 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);
935 elf.targetStore(inst, .{
936 .b0_9 = elf.targetLoad(inst).b0_9,
937 .k12 = link.loongarch.pcala64Hi12(val, dest_vaddr),
938 .b22_31 = elf.targetLoad(inst).b22_31,
939 });
940 },
941 .sparc_op_lox10 => {
942 const dest_ptr: *align(1) packed struct(u32) {
943 imm13: u13,
944 b13_31: u19,
945 } = @ptrCast(dest_slice);
946 elf.targetStore(dest_ptr, .{
947 .imm13 = @as(u10, @truncate(got_offset)),
948 .b13_31 = elf.targetLoad(dest_ptr).b13_31,
949 });
950 },
951 .sparc_op_hix22 => {
952 const dest_ptr: *align(1) packed struct(u32) {
953 imm22: u22,
954 b22_31: u10,
955 } = @ptrCast(dest_slice);
956 elf.targetStore(dest_ptr, .{
957 .imm22 = @truncate(got_offset >> 10),
958 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
959 });
960 },
961 }1349 }
962 }1350 },
963 };
964 };
9651351
966 const Index = enum(u32) {1352 /// After the relocation value is shifted (see `shift`), it is truncated to the size of
967 none = std.math.maxInt(u32),1353 /// the bit field (see `dest`). This field specifies whether the linker will check for,
968 _,1354 /// and error in the case of, truncated bits (in other words, relocation overflow).
1355 cast: enum(u2) {
1356 /// Do not perform any check when truncating unused bits.
1357 trunc,
1358 /// Error if the truncated value cannot be zero-extended back to the original value,
1359 /// i.e. if the truncated value is different when interpreted as unsigned.
1360 unsigned,
1361 /// Error if the truncated value cannot be sign-extended back to the original value.
1362 /// i.e. if the truncated value is different when interpreted as signed.
1363 signed,
1364 },
9691365
970 fn get(index: GotReloc.Index, elf: *Elf) *GotReloc {1366 /// The relocation value (computed based on the `Target`) gets shifted to the right by
971 return &elf.got_relocs.items[@backingInt(index)];1367 /// this amount. By default, the shifted-out bits can be anything, but tags ending in
972 }1368 /// "_exact" introduce a check that the shifted-out bits are all zeroes (an error is
973 };1369 /// emitted if not), similar to the behavior of `@shrExact`.
1370 shift: enum(u5) {
1371 @"0",
1372 @"2_exact",
1373 @"10",
1374 @"12",
1375 @"22",
1376 @"32",
1377 @"52",
1378 },
9741379
975 fn apply(reloc: *GotReloc, elf: *Elf) void {1380 /// Given a value (computed based on the `Target`), applies the shift and truncation
976 assert(elf.ehdrType() != .REL);1381 /// operations specified by `s`, then writes the result to the start of `dest_slice` as
977 const node = reloc.node.unwrap() orelse {1382 /// specified by `s.dest`.
978 return; // deleted1383 fn write(
979 };1384 s: Simple,
980 if (node.hasMoved(&elf.mf) or elf.shndx.got.get(elf).ni.hasMoved(&elf.mf)) {1385 val: u64,
981 // There's no point applying the relocation now, because it will be re-applied by1386 dest_slice: []u8,
982 // `flushMoved` at some point anyway.1387 target_endian: std.lang.Endian,
983 return;1388 ) error{ RelocationMisaligned, RelocationOverflow }!void {
984 }1389 const shift: u6, const shift_exact: bool = switch (s.shift) {
985 switch (reloc.result) {1390 .@"0" => .{ 0, false },
986 .ok => {},1391 .@"2_exact" => .{ 2, true },
1392 .@"10" => .{ 10, false },
1393 .@"12" => .{ 12, false },
1394 .@"22" => .{ 22, false },
1395 .@"32" => .{ 32, false },
1396 .@"52" => .{ 52, false },
1397 };
1398
1399 if (shift_exact and (val >> shift) << shift != val) {
1400 return error.RelocationMisaligned;
1401 }
1402
1403 const dest_word_bits: u8, const dest_high_bit: u6, const dest_low_bit: u6 = switch (s.dest) {
1404 // zig fmt: off
1405 .@"8" => .{ 8, 7, 0 },
1406 .@"16" => .{ 16, 15, 0 },
1407 .@"32" => .{ 32, 31, 0 },
1408 .@"64" => .{ 64, 63, 0 },
1409 .@"32[4:0]" => .{ 32, 4, 0 },
1410 .@"32[5:0]" => .{ 32, 5, 0 },
1411 .@"32[6:0]" => .{ 32, 6, 0 },
1412 .@"32[9:0]" => .{ 32, 9, 0 },
1413 .@"32[10:0]" => .{ 32, 10, 0 },
1414 .@"32[11:0]" => .{ 32, 11, 0 },
1415 .@"32[12:0]" => .{ 32, 12, 0 },
1416 .@"32[21:0]" => .{ 32, 21, 0 },
1417 .@"32[21:10]" => .{ 32, 21, 10 },
1418 .@"32[24:5]" => .{ 32, 24, 5 },
1419 .@"32[25:10]" => .{ 32, 25, 10 },
1420 .@"32[29:0]" => .{ 32, 29, 0 },
1421 // zig fmt: on
1422 };
1423
1424 // The number of bits we are truncating from the full 64-bit relocation value.
1425 const trunc_bits: u6 = 63 - dest_high_bit + dest_low_bit;
1426
1427 // When we shift, whether we do an arithmetic or logical shift depends on what cast
1428 // behavior we are going to use. If we'll be doing a signed int cast, we must shift
1429 // in sign bits so that we don't incorrectly cause a failure, and vice versa for an
1430 // unsigned int cast. Either is fine when truncating (here we pick logical shift).
1431 const shifted_val: u64 = switch (s.cast) {
1432 .trunc => val >> shift,
1433 inline else => |cast| shifted: {
1434 const ShiftInt = if (cast == .signed) i64 else u64;
1435 const x: ShiftInt = @bitCast(val);
1436 const shifted: ShiftInt = x >> shift;
1437
1438 if ((shifted << trunc_bits) >> trunc_bits != shifted) {
1439 return error.RelocationOverflow;
1440 }
1441
1442 break :shifted @bitCast(shifted);
1443 },
1444 };
1445
1446 // Create a bit-mask for the field being populated, e.g. 8[3:1] -> 0b00001110
1447 const field_mask = (~@as(u64, 0) >> trunc_bits) << dest_low_bit;
1448
1449 // Shift and mask the value to be in the correct bits, leaving the others zeroed.
1450 const masked_field: u64 = (shifted_val << dest_low_bit) & field_mask;
1451
1452 // Now we just need to actually apply the relocation by loading a word, replacing
1453 // the field bits with those in `masked_field`, and storing the result back.
1454 switch (dest_word_bits) {
1455 inline 8, 16, 32, 64 => |bits| {
1456 const word_slice = dest_slice[0..@divExact(bits, 8)];
1457 const Int = @Int(.unsigned, bits);
1458 const old: u64 = std.mem.readInt(Int, word_slice, target_endian);
1459 const new: u64 = (old & ~field_mask) | masked_field;
1460 std.mem.writeInt(Int, word_slice, @intCast(new), target_endian);
1461 },
1462 else => unreachable,
1463 }
1464 }
1465 };
1466
1467 /// Enum representing "special" relocation types, i.e. those which cannot be represented
1468 /// just with `Target` and `Simple`. These relocations have completely custom handling in
1469 /// the `Special.applyInner` function.
1470 const Special = enum(u13) {
1471 larch_pcala_hi20,
1472 larch_pcala64_lo20,
1473 larch_pcala64_hi12,
1474 larch_b21,
1475 larch_b26,
1476 larch_call36,
1477
1478 sparc_le_hix22,
1479
1480 fn applyInner(
1481 s: Special,
1482 elf: *Elf,
1483 target: Symbol.Id,
1484 addend: u64,
1485 dest_vaddr: u64,
1486 dest_slice: []u8,
1487 ) error{ RelocationMisaligned, RelocationOverflow }!void {
1488 switch (s) {
1489 .larch_pcala_hi20 => {
1490 const val = target.value(elf) +% addend;
1491 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1492 elf.targetStore(inst, .{
1493 .b0_4 = elf.targetLoad(inst).b0_4,
1494 .j20 = link.loongarch.pcalaHi20(val, dest_vaddr),
1495 .b25_31 = elf.targetLoad(inst).b25_31,
1496 });
1497 },
1498 .larch_pcala64_lo20 => {
1499 const val = target.value(elf) +% addend;
1500 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1501 elf.targetStore(inst, .{
1502 .b0_4 = elf.targetLoad(inst).b0_4,
1503 .j20 = link.loongarch.pcala64Lo20(val, dest_vaddr),
1504 .b25_31 = elf.targetLoad(inst).b25_31,
1505 });
1506 },
1507 .larch_pcala64_hi12 => {
1508 const val = target.value(elf) +% addend;
1509 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);
1510 elf.targetStore(inst, .{
1511 .b0_9 = elf.targetLoad(inst).b0_9,
1512 .k12 = link.loongarch.pcala64Hi12(val, dest_vaddr),
1513 .b22_31 = elf.targetLoad(inst).b22_31,
1514 });
1515 },
1516 .larch_b21, .larch_b26, .larch_call36 => {
1517 const target_vaddr: u64 = elf.pltEntryTargetAddr(target) orelse target.value(elf);
1518 const jump_offset: i64 = @bitCast(target_vaddr +% addend -% dest_vaddr);
1519 if ((jump_offset >> 2) << 2 != jump_offset) {
1520 return error.RelocationMisaligned;
1521 }
1522 const shifted_jump_offset: i64 = @shrExact(jump_offset, 2);
1523 switch (s) {
1524 .larch_b21 => {
1525 if ((shifted_jump_offset << (64 - 21)) >> (64 - 21) != shifted_jump_offset) {
1526 return error.RelocationOverflow;
1527 }
1528 const truncated: i21 = @intCast(shifted_jump_offset);
1529 const parts: packed struct { lo16: u16, hi5: u5 } = @bitCast(truncated);
1530 const inst: *align(1) link.loongarch.D5K16 = @ptrCast(dest_slice[0..4]);
1531 elf.targetStore(inst, .{
1532 .d5 = parts.hi5,
1533 .b5_9 = elf.targetLoad(inst).b5_9,
1534 .k16 = parts.lo16,
1535 .b26_31 = elf.targetLoad(inst).b26_31,
1536 });
1537 },
1538 .larch_b26 => {
1539 if ((shifted_jump_offset << (64 - 26)) >> (64 - 26) != shifted_jump_offset) {
1540 return error.RelocationOverflow;
1541 }
1542 const truncated: i26 = @intCast(shifted_jump_offset);
1543 const parts: packed struct { lo16: u16, hi10: u10 } = @bitCast(truncated);
1544 const inst: *align(1) link.loongarch.D10K16 = @ptrCast(dest_slice[0..4]);
1545 elf.targetStore(inst, .{
1546 .d10 = parts.hi10,
1547 .k16 = parts.lo16,
1548 .b26_31 = elf.targetLoad(inst).b26_31,
1549 });
1550 },
1551 .larch_call36 => {
1552 // The allowed range of destination addresses here is non-trivial:
1553 // [PC - 128 GiB - 0x20_000, PC + 128 GiB - 0x20_000 - 4]
1554 const gib = 1024 * 1024 * 1024;
1555 if (jump_offset < -128 * gib - 0x20_000 or
1556 jump_offset > 128 * gib - 0x20_000 - 4)
1557 {
1558 return error.RelocationOverflow;
1559 }
1560 // The values we write into the instructions are a little weird too:
1561 const hi: i20 = @intCast((shifted_jump_offset +% 0x8000) >> 16);
1562 const lo: i16 = @truncate(shifted_jump_offset);
1563
1564 const inst0: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1565 const inst1: *align(1) link.loongarch.K16 = @ptrCast(dest_slice[4..8]);
1566
1567 const old0 = elf.targetLoad(inst0);
1568 elf.targetStore(inst0, .{ .b0_4 = old0.b0_4, .j20 = @bitCast(hi), .b25_31 = old0.b25_31 });
1569
1570 const old1 = elf.targetLoad(inst1);
1571 elf.targetStore(inst1, .{ .b0_9 = old1.b0_9, .k16 = @bitCast(lo), .b26_31 = old1.b26_31 });
1572 },
1573 else => unreachable,
1574 }
1575 },
1576 .sparc_le_hix22 => {
1577 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
1578 const tls_size: u64 = switch (elf.phdrSlice()) {
1579 inline else => |phdr| tls_size: {
1580 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
1581 break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz);
1582 },
1583 };
1584 const dest_ptr: *align(1) packed struct(u32) {
1585 imm22: u22,
1586 b22_31: u10,
1587 } = @ptrCast(dest_slice);
1588 elf.targetStore(dest_ptr, .{
1589 .imm22 = @truncate(~(target.value(elf) +% addend -% tls_size) >> 10),
1590 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
1591 });
1592 },
1593 }
1594 }
1595 };
1596
1597 fn dependsOnTlsSize(t: SymbolReloc.Type, elf: *const Elf) bool {
1598 return switch (elf.targetTlsVariant()) {
1599 // In TLS variant I, the executable's TLS block starts at a fixed offset from the
1600 // thread pointer, so everything is fine...
1601 .I_original, .I_modified => false,
1602 // ...but in variant II, the executable's TLS block *ends* at a fixed offset from
1603 // the thread pointer, so the offset from the thread pointer to the *start* of the
1604 // TLS block depends on the size of the block, and we need that offset to resolve
1605 // 'tpoff' relocations.
1606 .II => switch (t.target) {
1607 .abs,
1608 .rel,
1609 .pltabs,
1610 .pltrel,
1611 .dtpoff,
1612 .size,
1613 => false,
1614
1615 .tpoff => true,
1616
1617 .special => switch (t.action.special) {
1618 .sparc_le_hix22,
1619 => true,
1620
1621 .larch_pcala_hi20,
1622 .larch_pcala64_lo20,
1623 .larch_pcala64_hi12,
1624 .larch_b21,
1625 .larch_b26,
1626 .larch_call36,
1627 => false,
1628 },
1629 },
1630 };
1631 }
1632 };
1633
1634 const Index = enum(u32) {
1635 none = std.math.maxInt(u32),
1636 _,
1637
1638 fn get(index: SymbolReloc.Index, elf: *Elf) *SymbolReloc {
1639 return &elf.symbol_relocs.items[@backingInt(index)];
1640 }
1641 };
1642
1643 fn flushMovedNode(reloc: *SymbolReloc, elf: *Elf, node_vaddr: u64) void {
1644 if (reloc.rela_index.unwrap()) |rela_index| {
1645 // The node has moved, so the offset of the relocation within the section might have
1646 // changed, so update the `offset` field of the `ElfN.Rela` entry.
1647 reloc.relaSection(elf).relaSetOffset(elf, rela_index, node_vaddr + reloc.offset);
1648 }
1649 // This is not just the inverse of the above condition, because if `reloc` is relative
1650 // to the base of this DSO, then `rela_index` is an `R_*_RELATIVE` relocation, but we
1651 // still need to call `SymbolReloc.apply` to update that relocation's addend.
1652 if (elf.ehdrType() != .REL) {
1653 reloc.apply(elf);
1654 }
1655 }
1656
1657 fn apply(reloc: *SymbolReloc, elf: *Elf) void {
1658 assert(elf.ehdrType() != .REL);
1659 const node = reloc.node.unwrap() orelse return; // deleted
1660 if (node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) {
1661 // There's no point applying the relocation now, because it will be re-applied by
1662 // `flushMoved` at some point anyway.
1663 return;
1664 }
1665 switch (reloc.result) {
1666 .ok => {},
987 .overflowed => elf.overflowed_reloc_count -= 1,1667 .overflowed => elf.overflowed_reloc_count -= 1,
988 .misaligned => elf.misaligned_reloc_count -= 1,1668 .misaligned => elf.misaligned_reloc_count -= 1,
989 }1669 }
...@@ -999,543 +1679,361 @@ const GotReloc = struct {...@@ -999,543 +1679,361 @@ const GotReloc = struct {
999 reloc.result = .misaligned;1679 reloc.result = .misaligned;
1000 elf.misaligned_reloc_count += 1;1680 elf.misaligned_reloc_count += 1;
1001 },1681 },
1002 }1682 }
1003 }
1004 fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
1005 const node = reloc.node.unwrap().?;
1006 const dest_vaddr = elf.getNodeVAddr(node) + reloc.offset;
1007 const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..];
1008
1009 const got_vaddr = elf.shndx.got.vaddr(elf);
1010 const got_index: u64 = elf.got.getIndex(reloc.target).?;
1011 const got_offset: u64 = switch (elf.identClass()) {
1012 .NONE, _ => unreachable,
1013 inline else => |class| @sizeOf(class.ElfN().Addr) * got_index,
1014 };
1015 const addend: u64 = @bitCast(reloc.addend);
1016
1017 const target_val: u64 = switch (reloc.type.target) {
1018 .abs => got_vaddr +% got_offset +% addend,
1019 .rel => got_vaddr +% got_offset +% addend -% dest_vaddr,
1020 .offset => got_offset +% addend,
1021 .special => return reloc.type.action.special.applyInner(
1022 elf,
1023 got_vaddr,
1024 got_offset,
1025 addend,
1026 dest_vaddr,
1027 dest_slice,
1028 ),
1029 };
1030 try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian());
1031 }
1032
1033 fn delete(reloc: *GotReloc, elf: *Elf) void {
1034 switch (reloc.result) {
1035 .ok => {},
1036 .overflowed => elf.overflowed_reloc_count -= 1,
1037 .misaligned => elf.misaligned_reloc_count -= 1,
1038 }
1039 reloc.* = .{
1040 .node = .none,
1041 .offset = undefined,
1042 .target = undefined,
1043 .addend = undefined,
1044 .type = undefined,
1045 .result = undefined,
1046 };
1047 }
1048};
1049
1050pub const MachineRelocType = union {
1051 AARCH64: std.elf.R_AARCH64,
1052 LARCH: std.elf.R_LARCH,
1053 PPC64: std.elf.R_PPC64,
1054 RISCV: std.elf.R_RISCV,
1055 SPARC: std.elf.R_SPARC,
1056 X86_64: std.elf.R_X86_64,
1057
1058 pub const Format = struct {
1059 rt: MachineRelocType,
1060 elf: *const Elf,
1061
1062 pub fn format(f: Format, w: *Io.Writer) Io.Writer.Error!void {
1063 switch (f.elf.ehdrMachine()) {
1064 .AARCH64 => try w.print("R_AARCH64_{t}", .{f.rt.AARCH64}),
1065 .LOONGARCH => try w.print("R_LARCH_{t}", .{f.rt.LARCH}),
1066 .PPC64 => try w.print("R_PPC64_{t}", .{f.rt.PPC64}),
1067 .RISCV => try w.print("R_RISCV_{t}", .{f.rt.RISCV}),
1068 .SPARCV9 => try w.print("R_SPARC_{t}", .{f.rt.SPARC}),
1069 .X86_64 => try w.print("R_X86_64_{t}", .{f.rt.X86_64}),
1070 }
1071 }
1072 };
1073
1074 pub fn fmt(rt: MachineRelocType, elf: *const Elf) Format {
1075 return .{ .rt = rt, .elf = elf };
1076 }
1077
1078 pub fn none(elf: *const Elf) MachineRelocType {
1079 return switch (elf.ehdrMachine()) {
1080 .AARCH64 => .{ .AARCH64 = .NONE },
1081 .LOONGARCH => .{ .LARCH = .NONE },
1082 .PPC64 => .{ .PPC64 = .NONE },
1083 .RISCV => .{ .RISCV = .NONE },
1084 .SPARCV9 => .{ .SPARC = .NONE },
1085 .X86_64 => .{ .X86_64 = .NONE },
1086 };
1087 }
1088 pub fn copy(elf: *const Elf) MachineRelocType {
1089 return switch (elf.ehdrMachine()) {
1090 .AARCH64 => .{ .AARCH64 = .COPY },
1091 .LOONGARCH => .{ .LARCH = .COPY },
1092 .PPC64 => .{ .PPC64 = .COPY },
1093 .RISCV => .{ .RISCV = .COPY },
1094 .SPARCV9 => .{ .SPARC = .COPY },
1095 .X86_64 => .{ .X86_64 = .COPY },
1096 };
1097 }
1098 pub fn relative(elf: *const Elf) MachineRelocType {
1099 return switch (elf.ehdrMachine()) {
1100 .AARCH64 => .{ .AARCH64 = .RELATIVE },
1101 .LOONGARCH => .{ .LARCH = .RELATIVE },
1102 .PPC64 => .{ .PPC64 = .RELATIVE },
1103 .RISCV => .{ .RISCV = .RELATIVE },
1104 .SPARCV9 => .{ .SPARC = .RELATIVE },
1105 .X86_64 => .{ .X86_64 = .RELATIVE },
1106 };
1107 }
1108 pub fn jumpSlot(elf: *const Elf) MachineRelocType {
1109 return switch (elf.ehdrMachine()) {
1110 .AARCH64 => .{ .AARCH64 = .JUMP_SLOT },
1111 .LOONGARCH => .{ .LARCH = .JUMP_SLOT },
1112 .PPC64 => .{ .PPC64 = .JMP_SLOT },
1113 .RISCV => .{ .RISCV = .JUMP_SLOT },
1114 .SPARCV9 => .{ .SPARC = .JMP_SLOT },
1115 .X86_64 => .{ .X86_64 = .JUMP_SLOT },
1116 };
1117 }
1118 pub fn globDat(elf: *const Elf) MachineRelocType {
1119 return switch (elf.ehdrMachine()) {
1120 .AARCH64 => .{ .AARCH64 = .GLOB_DAT },
1121 .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },
1122 .PPC64 => .{ .PPC64 = .GLOB_DAT },
1123 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" },
1124 .SPARCV9 => .{ .SPARC = .GLOB_DAT },
1125 .X86_64 => .{ .X86_64 = .GLOB_DAT },
1126 };
1127 }
1128 pub fn dtpMod(elf: *const Elf) MachineRelocType {
1129 return switch (elf.ehdrMachine()) {
1130 .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .TLS_DTPMOD else .P32_TLS_DTPMOD },
1131 .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },
1132 .PPC64 => .{ .PPC64 = .DTPMOD64 },
1133 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },
1134 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },
1135 .X86_64 => .{ .X86_64 = .DTPMOD64 },
1136 };
1137 }
1138 pub fn dtpOff(elf: *const Elf) MachineRelocType {
1139 return switch (elf.ehdrMachine()) {
1140 .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .TLS_DTPREL else .P32_TLS_DTPREL },
1141 .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 },
1142 .PPC64 => .{ .PPC64 = .DTPREL64 },
1143 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 },
1144 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_DTPOFF64 else .TLS_DTPOFF32 },
1145 .X86_64 => .{ .X86_64 = .DTPOFF64 },
1146 };
1147 }
1148 pub fn tpOff(elf: *const Elf) MachineRelocType {
1149 return switch (elf.ehdrMachine()) {
1150 .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .TLS_TPREL else .P32_TLS_TPREL },
1151 .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 },
1152 .PPC64 => .{ .PPC64 = .TPREL64 },
1153 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 },
1154 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_TPOFF64 else .TLS_TPOFF32 },
1155 .X86_64 => .{ .X86_64 = .TPOFF64 },
1156 };
1157 }
1158 pub fn absAddr(elf: *const Elf) MachineRelocType {
1159 return switch (elf.ehdrMachine()) {
1160 .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .ABS64 else .P32_ABS32 },
1161 .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },
1162 .PPC64 => .{ .PPC64 = .ADDR64 },
1163 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" },
1164 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .@"64" else .@"32" },
1165 .X86_64 => .{ .X86_64 = if (elf.identClass() == .@"64") .@"64" else .@"32" },
1166 };
1167 }1683 }
1168 pub fn size32(elf: *const Elf) ?MachineRelocType {1684 fn applyInner(reloc: *const SymbolReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
1169 return switch (elf.ehdrMachine()) {1685 const node = reloc.node.unwrap().?;
1170 .AARCH64,1686 const dest_vaddr = elf.getNodeVAddr(node) + reloc.offset;
1171 .LOONGARCH,1687 const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..];
1172 .PPC64,
1173 .RISCV,
1174 => null,
11751688
1176 .SPARCV9 => .{ .SPARC = .SIZE32 },1689 const addend: u64 = @bitCast(reloc.addend);
1177 .X86_64 => .{ .X86_64 = .SIZE32 },1690 const target_val: u64 = type: switch (reloc.type.target) {
1691 .abs => reloc.target.value(elf) +% addend,
1692 .rel => reloc.target.value(elf) +% addend -% dest_vaddr,
1693 .pltabs => {
1694 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .abs;
1695 break :type plt_entry_addr +% addend;
1696 },
1697 .pltrel => {
1698 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .rel;
1699 break :type plt_entry_addr +% addend -% dest_vaddr;
1700 },
1701 .dtpoff => reloc.target.value(elf) +% addend,
1702 .tpoff => switch (elf.targetTlsVariant()) {
1703 .I_original => |tls| tls.tcb_size +% reloc.target.value(elf) +% addend,
1704 .I_modified => |tls| 0 -% tls.tp_off +% reloc.target.value(elf) +% addend,
1705 .II => {
1706 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
1707 const tls_size: u64 = switch (elf.phdrSlice()) {
1708 inline else => |phdr| tls_size: {
1709 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
1710 break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz);
1711 },
1712 };
1713 break :type reloc.target.value(elf) +% addend -% tls_size;
1714 },
1715 },
1716 .size => switch (elf.symPtr(reloc.target.index(elf))) {
1717 inline else => |sym| elf.targetLoad(&sym.size),
1718 },
1719 .special => return reloc.type.action.special.applyInner(
1720 elf,
1721 reloc.target,
1722 addend,
1723 dest_vaddr,
1724 dest_slice,
1725 ),
1178 };1726 };
1179 }
1180 pub fn size64(elf: *const Elf) ?MachineRelocType {
1181 return switch (elf.ehdrMachine()) {
1182 .AARCH64,
1183 .LOONGARCH,
1184 .PPC64,
1185 .RISCV,
1186 => null,
11871727
1188 .SPARCV9 => .{ .SPARC = .SIZE64 },1728 // Check for the `R_*_RELATIVE` case now, because it is possible only when no shift or cast
1189 .X86_64 => .{ .X86_64 = .SIZE64 },1729 // is required, meaning we can handle it now and return early.
1730 if (reloc.rela_index.unwrap()) |rela_index| switch (elf.classifySymbolValue(reloc.target)) {
1731 .static => unreachable,
1732 .dynamic => return, // the relocation happens at runtime
1733 .static_relative => {
1734 // We have emitted an R_*_RELATIVE relocation to help lower an absolute-address
1735 // relocation. The value computed above is valid, but instead of writing it to the
1736 // destination slice, we actually want to write it to the runtime relocation entry.
1737 switch (elf.identClass()) {
1738 .NONE, _ => unreachable,
1739 .@"32" => assert(reloc.type.action.simple.dest == .@"32"),
1740 .@"64" => assert(reloc.type.action.simple.dest == .@"64"),
1741 }
1742 assert(reloc.type.action.simple.cast == .unsigned);
1743 assert(reloc.type.action.simple.shift == .@"0");
1744 elf.shndx.rela_dyn.relaSetAddend(elf, rela_index, target_val);
1745 return;
1746 },
1190 };1747 };
1748
1749 try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian());
1191 }1750 }
11921751
1193 pub fn wrap(int: u32, elf: *const Elf) MachineRelocType {1752 fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void {
1194 return switch (elf.ehdrMachine()) {1753 assert(index.get(elf) == reloc);
1195 .AARCH64 => .{ .AARCH64 = @fromBackingInt(int) },1754
1196 .LOONGARCH => .{ .LARCH = @fromBackingInt(int) },1755 reloc.deleteOutputRel(elf);
1197 .PPC64 => .{ .PPC64 = @fromBackingInt(int) },1756 if (reloc.type.dependsOnTlsSize(elf)) {
1198 .RISCV => .{ .RISCV = @fromBackingInt(int) },1757 assert(elf.tls_size_symbol_relocs.swapRemove(index));
1199 .SPARCV9 => .{ .SPARC = @fromBackingInt(int) },1758 }
1200 .X86_64 => .{ .X86_64 = @fromBackingInt(int) },1759
1201 };1760 switch (reloc.prev) {
1761 .none => {
1762 const first_target_reloc = &reloc.target.index(elf).ptr(elf).first_target_reloc;
1763 assert(first_target_reloc.* == index);
1764 first_target_reloc.* = reloc.next;
1765 },
1766 else => |prev| prev.get(elf).next = reloc.next,
1767 }
1768 switch (reloc.next) {
1769 .none => {},
1770 else => |next| next.get(elf).prev = reloc.prev,
1771 }
1772 switch (reloc.result) {
1773 .ok => {},
1774 .overflowed => elf.overflowed_reloc_count -= 1,
1775 .misaligned => elf.misaligned_reloc_count -= 1,
1776 }
1777
1778 reloc.* = undefined;
1779 reloc.node = .none;
1202 }1780 }
1203 pub fn unwrap(rt: MachineRelocType, elf: *const Elf) u32 {1781
1204 return switch (elf.ehdrMachine()) {1782 /// If `reloc.rela_index` is populated, reset it to `.none` and delete the relocation, updating
1205 .AARCH64 => @backingInt(rt.AARCH64),1783 /// `elf.textrel_count` if necessary.
1206 .LOONGARCH => @backingInt(rt.LARCH),1784 fn deleteOutputRel(reloc: *SymbolReloc, elf: *Elf) void {
1207 .PPC64 => @backingInt(rt.PPC64),1785 const rela_index = reloc.rela_index.unwrap() orelse return;
1208 .RISCV => @backingInt(rt.RISCV),1786 reloc.relaSection(elf).relaDeleteOne(elf, rela_index);
1209 .SPARCV9 => @backingInt(rt.SPARC),1787 switch (elf.ehdrType()) {
1210 .X86_64 => @backingInt(rt.X86_64),1788 .REL => {},
1211 };1789 .EXEC, .DYN => switch (elf.nodeWantsDsoRelocation(reloc.node.unwrap().?)) {
1790 .no => unreachable, // there *was* a dynamic relocation!
1791 .yes => {},
1792 .yes_textrel => elf.textrel_count -= 1,
1793 },
1794 }
1795 reloc.rela_index = .none;
1212 }1796 }
1213};1797};
12141798
1215/// A relocation targeting an arbitrary symbol with a fixed addend.1799/// A relocation targeting an arbitrary node (within a section) with a fixed addend.
1216const SymbolReloc = struct {1800/// This represents a symbol reloc against the section symbol containing the node
1217 /// The node containing this relocation. Possible values are:1801/// with a variable addend that changes when the target node moves.
1218 /// * An input section1802const NodeReloc = struct {
1219 /// * A section1803 node: MappedFile.Node.Index.Optional,
1220 /// * A NAV, UAV, or lazy code/data
1221 node: MappedFile.Node.Index,
1222 /// The offset of the relocation inside of `node`.
1223 offset: u64,1804 offset: u64,
1224 /// A symbol used to compute the relocated value. Precise meaning depends on `@"type"`.1805 target: MappedFile.Node.Index,
1225 target: Symbol.Id,
1226 /// A signed constant used to compute the relocated value. Precise meaning depends on `@"type"`.
1227 addend: i64,1806 addend: i64,
1228 /// Specifies how to apply the relocation.1807 type: NodeReloc.Type,
1229 ///1808 next: NodeReloc.Index,
1230 /// When emitting a relocatable, this field is `undefined`.1809 prev: NodeReloc.Index,
1231 type: SymbolReloc.Type,
1232 /// Forms a linked list of all symbol relocations with the same `target`. This list exists so
1233 /// that all relocations targeting a particular symbol can be re-applied if that symbol moves.
1234 /// Doubly-linked so that relocations can be removed.
1235 next: SymbolReloc.Index,
1236 /// Back-reference in a doubly-linked list---see `next`.
1237 prev: SymbolReloc.Index,
1238 /// If this relocation has a corresponding output relocation, this is its index within the
1239 /// appropriate SHT_RELA section (see `relaSection`). If there is no output relocation
1240 /// corresponding to this relocation, this is `.none`.
1241 ///
1242 /// If we are producing a relocatable, this field is always populated, because all relocations
1243 /// are emitted as output relocations.
1244 ///
1245 /// If we are producing a DSO, this field is populated if this relocation requires a runtime
1246 /// relocation entry. The entry will be removed if we discover a definition which allows us to
1247 /// statically resolve the relocation.
1248 rela_index: Section.RelaIndex.Optional,1810 rela_index: Section.RelaIndex.Optional,
1249 result: enum(u8) { ok, overflowed, misaligned },1811 result: enum(u8) { ok, overflowed, misaligned },
12501812
1251 /// Determines the section in which this relocation will be placed if it is outstanding.1813 const Type = enum { abs32, abs64 };
1252 ///
1253 /// When producing a relocatable (ET_REL), the relocation section is `Section.rela.shndx` for
1254 /// the section of `node`, and this function asserts that the aforementioned `rela.shndx` field
1255 /// is populated.
1256 ///
1257 /// When producing a DSO, the relocation section is always `.rela.dyn`. It is not `.rela.plt`
1258 /// because relocations in the GOTPLT are handled specially, without `SymbolReloc` entries.
1259 fn relaSection(sr: *const SymbolReloc, elf: *Elf) Section.Index {
1260 const shndx = switch (elf.ehdrType()) {
1261 .REL => elf.getNodeShndx(sr.node).get(elf).rela.shndx,
1262 .EXEC, .DYN => elf.shndx.rela_dyn,
1263 };
1264 assert(shndx != .UNDEF);
1265 return shndx;
1266 }
12671814
1268 const Index = enum(u32) {1815 const Index = enum(u32) {
1269 none = std.math.maxInt(u32),1816 none = std.math.maxInt(u32),
1270 _,1817 _,
12711818
1272 fn get(index: SymbolReloc.Index, elf: *Elf) *SymbolReloc {1819 fn get(index: NodeReloc.Index, elf: *Elf) *NodeReloc {
1273 return &elf.symbol_relocs.items[@backingInt(index)];1820 return &elf.node_relocs.items[@backingInt(index)];
1274 }1821 }
1275 };1822 };
1276
1277 /// Instead of using the ELF relocation enums, we have our own internal representation for
1278 /// relocation types. This representation is more compact (requiring only 16 bits), and allows
1279 /// sharing a lot of relocation handling between multiple relocs and target architectures.
1280 ///
1281 /// A relocation type can be "simple" or "special".
1282 ///
1283 /// "Simple" relocations are designed to cover the majority of cases. They can represent most
1284 /// relocations which either write 8-bit, 16-bit, 32-bit, or 64-bit integers, or which write one
1285 /// contiguous bit-field within such an integer (e.g. an instruction operand). For more details,
1286 /// see `Simple`.
1287 ///
1288 /// "Special" relocations handle anything which does not fit into the above category, such as
1289 /// relocations which write multiple sequences of bits or which need to do unusual arithmetic on
1290 /// a symbol value. The representation is simply a big enum containing all of these exceptional
1291 /// cases---see `Special`. This representation is in use when `Type.target == .special`.
1292 const Type = packed struct(u16) {
1293 /// Helper function for constructing a "simple" relocation type. This mainly exists to
1294 /// improve readability in the relocation lowering logic in `addRelocAssumeCapacity`.
1295 fn simple(target: Target, action: Simple) SymbolReloc.Type {
1296 assert(target != .special);
1297 return .{ .target = target, .action = .{ .simple = action } };
1298 }
1299
1300 /// Helper function for constructing a "special" relocation type. This mainly exists to
1301 /// improve readability in the relocation lowering logic in `addRelocAssumeCapacity`.
1302 fn special(s: Special) SymbolReloc.Type {
1303 return .{ .target = .special, .action = .{ .special = s } };
1304 }
1305
1306 /// See doc comment on `Target`.
1307 target: Target,
1308 /// If `target == .special`, the `special` field is used.
1309 ///
1310 /// Otherwise, the `.simple` field is used.
1311 action: packed union {
1312 simple: Simple,
1313 special: Special,
1314 },
1315
1316 /// If a relocation is "special", indicates that using the value `.@"special"`.
1317 ///
1318 /// Otherwise (for "simple" relocations), `Target` indicates the first step in computing the
1319 /// relocation---whether we care about the target symbol's absolute address, its PC-relative
1320 /// address, its PLT entry, etc.
1321 const Target = enum(u3) {
1322 /// This is a "special" relocation whose specific type is in the `action.special` field.
1323 special,
1324
1325 /// Absolute value of the target symbol.
1326 abs,
1327 /// Offset from the relocation itself to the target symbol ("PC-relative").
1328 rel,
1329 /// Address of the target symbol's PLT entry.
1330 ///
1331 /// If the target symbol does not have a PLT entry, equivalent to `.abs`.
1332 pltabs,
1333 /// Offset from the relocation itself to the target symbol's PLT entry ("PC-relative").
1334 ///
1335 /// If the target symbol does not have a PLT entry, equivalent to `.rel`.
1336 pltrel,
1337 /// Offset of the target TLS symbol from the base of this DSO's own TLS region.
1338 dtpoff,
1339 /// Offset of the target TLS symbol from the raw thread pointer.
1340 tpoff,
1341 /// Size of the target symbol.
1342 size,
1343 };
13441823
1345 /// For a "simple" relocation, after the initial value is computed according to `Target`, a1824 fn flushMovedNode(reloc: *NodeReloc, elf: *Elf, node_vaddr: u64) void {
1346 /// `Simple` value communicates how to shift, truncate, and store that value into memory.1825 if (reloc.rela_index.unwrap()) |rela_index| {
1347 const Simple = packed struct(u13) {1826 assert(elf.ehdrType() == .REL);
1348 /// The field being written to, represented as a sequence of bits in a backing integer1827 // The node has moved, so the offset of the relocation within the section might have
1349 /// of 8, 16, 32, or 64 bits.1828 // changed, so update the `offset` field of the `ElfN.Rela` entry.
1350 ///1829 elf.getNodeShndx(reloc.node.unwrap().?).get(elf).rela.shndx.relaSetOffset(elf, rela_index, node_vaddr + reloc.offset);
1351 /// The `.@"8"`, `.@"16"`, `.@"32"`, and `.@"64"` fields simply write to all bits of the1830 } else {
1352 /// backing integer; i.e. the existing value is entirely overwritten.1831 assert(elf.ehdrType() != .REL);
1353 ///1832 reloc.apply(elf);
1354 /// Other fields are named like "B[H:L]", where "B" is the backing integer type, and1833 }
1355 /// "H" and "L" are the indices of the highest and lowest bits in the bit field (in1834 }
1356 /// other words, an inclusive bit range). This notation was chosen because it seems to
1357 /// be one of the more common ways that bit relocations are written in ABIs.
1358 ///
1359 /// e.g. 8[6:3] writes the relocated value to this 4-bit field in an 8-bit integer:
1360 ///
1361 /// MSB ___ ### ### ### ### ___ ___ ___ LSB
1362 /// 7 6 5 4 3 2 1 0
1363 /// bit index
1364 ///
1365 /// This enum is not intended to be able to represent every possible bit field in the
1366 /// backing integer types. Instead, to keep `SymbolReloc.Type` compact, fields are added
1367 /// to this enum only as needed. If the enum ever becomes full, some lesser-used tags
1368 /// can have their handling moved into `Special` to free up space.
1369 dest: enum(u6) {
1370 @"8",
1371 @"16",
1372 @"32",
1373 @"64",
13741835
1375 @"32[4:0]",1836 fn flushMovedTarget(reloc: *NodeReloc, elf: *Elf, target_section_offset: u64) void {
1376 @"32[5:0]",1837 if (reloc.rela_index.unwrap()) |rela_index| {
1377 @"32[6:0]",1838 assert(elf.ehdrType() == .REL);
1378 @"32[9:0]",1839 // The target has moved, so the `addend` field of the `ElfN.Rela` entry needs to be updated.
1379 @"32[10:0]",1840 elf.getNodeShndx(reloc.node.unwrap().?).get(elf).rela.shndx.relaSetAddend(elf, rela_index, target_section_offset +% @as(u64, @bitCast(reloc.addend)));
1380 @"32[11:0]",1841 } else {
1381 @"32[12:0]",1842 assert(elf.ehdrType() != .REL);
1382 @"32[21:0]",1843 reloc.apply(elf);
1383 @"32[21:10]",1844 }
1384 @"32[24:5]",1845 }
1385 @"32[25:10]",
1386 @"32[29:0]",
13871846
1388 /// Returns `true` iff `dest` writes a full address for the target.1847 fn apply(reloc: *NodeReloc, elf: *Elf) void {
1389 ///1848 const node = reloc.node.unwrap() orelse return; // deleted
1390 /// i.e. checks for `.@"32"` on 32-bit targets; for `.@"64"` on 64-bit targets.1849 if (reloc.rela_index.unwrap()) |rela_index| {
1391 fn isAddr(dest: @This(), elf: *const Elf) bool {1850 assert(elf.ehdrType() == .REL);
1392 return switch (elf.identClass()) {1851 _ = rela_index;
1393 .NONE, _ => unreachable,1852 } else {
1394 .@"32" => dest == .@"32",1853 assert(elf.ehdrType() != .REL);
1395 .@"64" => dest == .@"64",1854 if (node.hasMoved(&elf.mf) or reloc.target.hasMoved(&elf.mf)) {
1396 };1855 // There's no point applying the relocation now, because it will be re-applied by
1397 }1856 // `flushMoved` at some point anyway.
1398 },1857 return;
1858 }
1859 switch (reloc.result) {
1860 .ok => {},
1861 .overflowed => elf.overflowed_reloc_count -= 1,
1862 .misaligned => elf.misaligned_reloc_count -= 1,
1863 }
1864 if (reloc.applyInner(elf)) {
1865 @branchHint(.likely);
1866 reloc.result = .ok;
1867 } else |err| switch (err) {
1868 error.RelocationOverflow => {
1869 reloc.result = .overflowed;
1870 elf.overflowed_reloc_count += 1;
1871 },
1872 error.RelocationMisaligned => {
1873 reloc.result = .misaligned;
1874 elf.misaligned_reloc_count += 1;
1875 },
1876 }
1877 }
1878 }
1879 fn applyInner(reloc: *const NodeReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
1880 const simple: SymbolReloc.Type.Simple = .{ .dest = switch (reloc.type) {
1881 .abs32 => .@"32",
1882 .abs64 => .@"64",
1883 }, .cast = .unsigned, .shift = .@"0" };
1884 const addend: u64 = @bitCast(reloc.addend);
1885 const target_val = elf.getNodeVAddr(reloc.target) +% addend;
1886 const dest_slice = reloc.node.unwrap().?.slice(&elf.mf)[@intCast(reloc.offset)..];
1887 try simple.write(target_val, dest_slice, elf.targetEndian());
1888 }
13991889
1400 /// After the relocation value is shifted (see `shift`), it is truncated to the size of1890 fn delete(reloc: *NodeReloc, elf: *Elf) void {
1401 /// the bit field (see `dest`). This field specifies whether the linker will check for,1891 reloc.deleteOutputRel(elf);
1402 /// and error in the case of, truncated bits (in other words, relocation overflow).
1403 cast: enum(u2) {
1404 /// Do not perform any check when truncating unused bits.
1405 trunc,
1406 /// Error if the truncated value cannot be zero-extended back to the original value,
1407 /// i.e. if the truncated value is different when interpreted as unsigned.
1408 unsigned,
1409 /// Error if the truncated value cannot be sign-extended back to the original value.
1410 /// i.e. if the truncated value is different when interpreted as signed.
1411 signed,
1412 },
14131892
1414 /// The relocation value (computed based on the `Target`) gets shifted to the right by1893 switch (reloc.prev) {
1415 /// this amount. By default, the shifted-out bits can be anything, but tags ending in1894 .none => {
1416 /// "_exact" introduce a check that the shifted-out bits are all zeroes (an error is1895 const first_target_reloc = switch (elf.getNode(reloc.target)) {
1417 /// emitted if not), similar to the behavior of `@shrExact`.1896 else => unreachable,
1418 shift: enum(u5) {1897 .debug_shared => |ss| &elf.dwarf_shared.getPtr(ss).first_target_reloc,
1419 @"0",1898 .unit_frame_cie => |ui| &elf.dwarf_units[@backingInt(ui)].frame_cie_first_target_reloc,
1420 @"2_exact",1899 .unit_debug_info_header => |ui| &elf.dwarf_units[@backingInt(ui)].debug_info_header_first_target_reloc,
1421 @"10",1900 .unit_debug_line_header => |ui| &elf.dwarf_units[@backingInt(ui)].debug_line_header_first_target_reloc,
1422 @"12",1901 .unit_debug_rnglists => |ui| &elf.dwarf_units[@backingInt(ui)].debug_rnglists_first_target_reloc,
1423 @"22",1902 .const_debug_info => |cpi| &elf.dwarf_consts.getPtr(cpi).?.debug_info_first_target_reloc,
1424 @"32",1903 .global_debug_info => |gi| &elf.dwarf_globals.items[@backingInt(gi)].debug_info_first_target_reloc,
1425 @"52",1904 .func_debug_info => |fi| &elf.dwarf_funcs.items[@backingInt(fi)].debug_info_first_target_reloc,
1905 .decl_debug_info => |di| &elf.dwarf_decls.getPtr(di).?.debug_info_first_target_reloc,
1906 };
1907 first_target_reloc.* = reloc.next;
1426 },1908 },
1909 else => |prev| prev.get(elf).next = reloc.next,
1910 }
1911 switch (reloc.next) {
1912 .none => {},
1913 else => |next| next.get(elf).prev = reloc.prev,
1914 }
1915 switch (reloc.result) {
1916 .ok => {},
1917 .overflowed => elf.overflowed_reloc_count -= 1,
1918 .misaligned => elf.misaligned_reloc_count -= 1,
1919 }
14271920
1428 /// Given a value (computed based on the `Target`), applies the shift and truncation1921 reloc.* = undefined;
1429 /// operations specified by `s`, then writes the result to the start of `dest_slice` as1922 reloc.node = .none;
1430 /// specified by `s.dest`.1923 }
1431 fn write(
1432 s: Simple,
1433 val: u64,
1434 dest_slice: []u8,
1435 target_endian: std.lang.Endian,
1436 ) error{ RelocationMisaligned, RelocationOverflow }!void {
1437 const shift: u6, const shift_exact: bool = switch (s.shift) {
1438 .@"0" => .{ 0, false },
1439 .@"2_exact" => .{ 2, true },
1440 .@"10" => .{ 10, false },
1441 .@"12" => .{ 12, false },
1442 .@"22" => .{ 22, false },
1443 .@"32" => .{ 32, false },
1444 .@"52" => .{ 52, false },
1445 };
14461924
1447 if (shift_exact and (val >> shift) << shift != val) {1925 /// If `reloc.rela_index` is populated, reset it to `.none` and delete the relocation.
1448 return error.RelocationMisaligned;1926 fn deleteOutputRel(reloc: *NodeReloc, elf: *Elf) void {
1449 }1927 const rela_index = reloc.rela_index.unwrap() orelse return;
1928 assert(elf.ehdrType() == .REL);
1929 elf.getNodeShndx(reloc.node.unwrap().?).get(elf).rela.shndx.relaDeleteOne(elf, rela_index);
1930 reloc.rela_index = .none;
1931 }
1932};
14501933
1451 const dest_word_bits: u8, const dest_high_bit: u6, const dest_low_bit: u6 = switch (s.dest) {1934/// Identifies a single entry in the GOT.
1452 // zig fmt: off1935const GotKey = union(enum) {
1453 .@"8" => .{ 8, 7, 0 },1936 /// The entry is a reserved word, initialized to zero. `initHeaders` will add as many of these
1454 .@"16" => .{ 16, 15, 0 },1937 /// as the target machine ABI requires.
1455 .@"32" => .{ 32, 31, 0 },1938 ///
1456 .@"64" => .{ 64, 63, 0 },1939 /// This `u32` value exists to allow reserving multiple words with distinct keys.
1457 .@"32[4:0]" => .{ 32, 4, 0 },1940 reserved: u32,
1458 .@"32[5:0]" => .{ 32, 5, 0 },
1459 .@"32[6:0]" => .{ 32, 6, 0 },
1460 .@"32[9:0]" => .{ 32, 9, 0 },
1461 .@"32[10:0]" => .{ 32, 10, 0 },
1462 .@"32[11:0]" => .{ 32, 11, 0 },
1463 .@"32[12:0]" => .{ 32, 12, 0 },
1464 .@"32[21:0]" => .{ 32, 21, 0 },
1465 .@"32[21:10]" => .{ 32, 21, 10 },
1466 .@"32[24:5]" => .{ 32, 24, 5 },
1467 .@"32[25:10]" => .{ 32, 25, 10 },
1468 .@"32[29:0]" => .{ 32, 29, 0 },
1469 // zig fmt: on
1470 };
14711941
1472 // The number of bits we are truncating from the full 64-bit relocation value.1942 /// Value is the address of the given symbol.
1473 const trunc_bits: u6 = 63 - dest_high_bit + dest_low_bit;1943 symbol: Symbol.Id,
14741944
1475 // When we shift, whether we do an arithmetic or logical shift depends on what cast1945 /// Value is the signed offset of the given symbol from the TLS pointer.
1476 // behavior we are going to use. If we'll be doing a signed int cast, we must shift1946 tpoff: Symbol.Id,
1477 // in sign bits so that we don't incorrectly cause a failure, and vice versa for an
1478 // unsigned int cast. Either is fine when truncating (here we pick logical shift).
1479 const shifted_val: u64 = switch (s.cast) {
1480 .trunc => val >> shift,
1481 inline else => |cast| shifted: {
1482 const ShiftInt = if (cast == .signed) i64 else u64;
1483 const x: ShiftInt = @bitCast(val);
1484 const shifted: ShiftInt = x >> shift;
14851947
1486 if ((shifted << trunc_bits) >> trunc_bits != shifted) {1948 /// Value is the TLS module ID of the DSO we are creating.
1487 return error.RelocationOverflow;1949 ///
1488 }1950 /// Used for the first of the two GOT entries generated by a TLSLD relocation.
1951 tlsld0,
1952 /// Value is always 0.
1953 ///
1954 /// Used for the second of the two GOT entries generated by a TLSLD relocation.
1955 tlsld1,
14891956
1490 break :shifted @bitCast(shifted);1957 /// Value is the TLS module ID for the given STT_TLS symbol.
1491 },1958 ///
1492 };1959 /// Used for the first of the two GOT entries generated by a TLSGD relocation.
1960 tlsgd0: Symbol.Id,
1961 /// Value is the offset of the given STT_TLS symbol from the base of the per-module TLS area.
1962 ///
1963 /// Used for the second of the two GOT entries generated by a TLSGD relocation.
1964 tlsgd1: Symbol.Id,
1965};
14931966
1494 // Create a bit-mask for the field being populated, e.g. 8[3:1] -> 0b000011101967/// A relocation targeting a particular GOT entry.
1495 const field_mask = (~@as(u64, 0) >> trunc_bits) << dest_low_bit;1968const GotReloc = struct {
1969 /// The node containing this relocation. Possible values are:
1970 /// * An input section
1971 /// * A section
1972 /// * A NAV, UAV, or lazy code/data
1973 /// * `.none`, if this relocation was deleted (in which case it should be ignored)
1974 node: MappedFile.Node.Index.Optional,
1975 /// The offset of the relocation inside of `node`.
1976 offset: u64,
1977 target: GotKey,
1978 addend: i64,
1979 type: GotReloc.Type,
1980 result: enum(u8) { ok, overflowed, misaligned },
14961981
1497 // Shift and mask the value to be in the correct bits, leaving the others zeroed.1982 /// `GotReloc.Type` has the same structure as `SymbolReloc.Type`, just with different `Target`
1498 const masked_field: u64 = (shifted_val << dest_low_bit) & field_mask;1983 /// and `Special` enums---consult doc comments on `SymbolReloc.Type` for an overview.
1984 const Type = packed struct(u16) {
1985 fn simple(target: Target, action: Simple) GotReloc.Type {
1986 assert(target != .special);
1987 return .{ .target = target, .action = .{ .simple = action } };
1988 }
14991989
1500 // Now we just need to actually apply the relocation by loading a word, replacing1990 fn special(s: Special) GotReloc.Type {
1501 // the field bits with those in `masked_field`, and storing the result back.1991 return .{ .target = .special, .action = .{ .special = s } };
1502 switch (dest_word_bits) {1992 }
1503 inline 8, 16, 32, 64 => |bits| {1993
1504 const word_slice = dest_slice[0..@divExact(bits, 8)];1994 target: Target,
1505 const Int = @Int(.unsigned, bits);1995 action: packed union {
1506 const old: u64 = std.mem.readInt(Int, word_slice, target_endian);1996 simple: Simple,
1507 const new: u64 = (old & ~field_mask) | masked_field;1997 special: Special,
1508 std.mem.writeInt(Int, word_slice, @intCast(new), target_endian);1998 },
1509 },1999
1510 else => unreachable,2000 /// Like `SymbolReloc.Target`, but for GOT relocations. There are fewer tags because there
1511 }2001 /// are fewer different kinds of GOT relocation.
1512 }2002 const Target = enum(u3) {
2003 /// This is a "special" relocation whose specific type is in the `action.special` field.
2004 special,
2005
2006 /// Absolute address of the GOT entry.
2007 abs,
2008 /// Offset from the relocation itself to the GOT entry ("PC-relative").
2009 rel,
2010 /// Offset from the base of the GOT to the GOT entry.
2011 offset,
1513 };2012 };
15142013
1515 /// Enum representing "special" relocation types, i.e. those which cannot be represented2014 const Simple = SymbolReloc.Type.Simple;
1516 /// just with `Target` and `Simple`. These relocations have completely custom handling in2015
1517 /// the `Special.applyInner` function.2016 /// Like `SymbolReloc.Special`, but for GOT relocations.
1518 const Special = enum(u13) {2017 const Special = enum(u13) {
1519 larch_pcala_hi20,2018 larch_pcala_hi20,
1520 larch_pcala64_lo20,2019 larch_pcala64_lo20,
1521 larch_pcala64_hi12,2020 larch_pcala64_hi12,
1522 larch_b21,
1523 larch_b26,
1524 larch_call36,
15252021
1526 sparc_le_hix22,2022 sparc_op_lox10,
2023 sparc_op_hix22,
15272024
1528 fn applyInner(2025 fn applyInner(
1529 s: Special,2026 s: Special,
1530 elf: *Elf,2027 elf: *Elf,
1531 target: Symbol.Id,2028 got_vaddr: u64,
2029 got_offset: u64,
1532 addend: u64,2030 addend: u64,
1533 dest_vaddr: u64,2031 dest_vaddr: u64,
1534 dest_slice: []u8,2032 dest_slice: []u8,
1535 ) error{ RelocationMisaligned, RelocationOverflow }!void {2033 ) error{ RelocationMisaligned, RelocationOverflow }!void {
1536 switch (s) {2034 switch (s) {
1537 .larch_pcala_hi20 => {2035 .larch_pcala_hi20 => {
1538 const val = target.value(elf) +% addend;2036 const val = got_vaddr +% got_offset +% addend;
1539 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);2037 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1540 elf.targetStore(inst, .{2038 elf.targetStore(inst, .{
1541 .b0_4 = elf.targetLoad(inst).b0_4,2039 .b0_4 = elf.targetLoad(inst).b0_4,
...@@ -1544,7 +2042,7 @@ const SymbolReloc = struct {...@@ -1544,7 +2042,7 @@ const SymbolReloc = struct {
1544 });2042 });
1545 },2043 },
1546 .larch_pcala64_lo20 => {2044 .larch_pcala64_lo20 => {
1547 const val = target.value(elf) +% addend;2045 const val = got_vaddr +% got_offset +% addend;
1548 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);2046 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1549 elf.targetStore(inst, .{2047 elf.targetStore(inst, .{
1550 .b0_4 = elf.targetLoad(inst).b0_4,2048 .b0_4 = elf.targetLoad(inst).b0_4,
...@@ -1553,7 +2051,7 @@ const SymbolReloc = struct {...@@ -1553,7 +2051,7 @@ const SymbolReloc = struct {
1553 });2051 });
1554 },2052 },
1555 .larch_pcala64_hi12 => {2053 .larch_pcala64_hi12 => {
1556 const val = target.value(elf) +% addend;2054 const val = got_vaddr +% got_offset +% addend;
1557 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);2055 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);
1558 elf.targetStore(inst, .{2056 elf.targetStore(inst, .{
1559 .b0_9 = elf.targetLoad(inst).b0_9,2057 .b0_9 = elf.targetLoad(inst).b0_9,
...@@ -1561,127 +2059,44 @@ const SymbolReloc = struct {...@@ -1561,127 +2059,44 @@ const SymbolReloc = struct {
1561 .b22_31 = elf.targetLoad(inst).b22_31,2059 .b22_31 = elf.targetLoad(inst).b22_31,
1562 });2060 });
1563 },2061 },
1564 .larch_b21, .larch_b26, .larch_call36 => {2062 .sparc_op_lox10 => {
1565 const target_vaddr: u64 = elf.pltEntryTargetAddr(target) orelse target.value(elf);2063 const dest_ptr: *align(1) packed struct(u32) {
1566 const jump_offset: i64 = @bitCast(target_vaddr +% addend -% dest_vaddr);2064 imm13: u13,
1567 if ((jump_offset >> 2) << 2 != jump_offset) {2065 b13_31: u19,
1568 return error.RelocationMisaligned;2066 } = @ptrCast(dest_slice);
1569 }2067 elf.targetStore(dest_ptr, .{
1570 const shifted_jump_offset: i64 = @shrExact(jump_offset, 2);2068 .imm13 = @as(u10, @truncate(got_offset)),
1571 switch (s) {2069 .b13_31 = elf.targetLoad(dest_ptr).b13_31,
1572 .larch_b21 => {2070 });
1573 if ((shifted_jump_offset << (64 - 21)) >> (64 - 21) != shifted_jump_offset) {
1574 return error.RelocationOverflow;
1575 }
1576 const truncated: i21 = @intCast(shifted_jump_offset);
1577 const parts: packed struct { lo16: u16, hi5: u5 } = @bitCast(truncated);
1578 const inst: *align(1) link.loongarch.D5K16 = @ptrCast(dest_slice[0..4]);
1579 elf.targetStore(inst, .{
1580 .d5 = parts.hi5,
1581 .b5_9 = elf.targetLoad(inst).b5_9,
1582 .k16 = parts.lo16,
1583 .b26_31 = elf.targetLoad(inst).b26_31,
1584 });
1585 },
1586 .larch_b26 => {
1587 if ((shifted_jump_offset << (64 - 26)) >> (64 - 26) != shifted_jump_offset) {
1588 return error.RelocationOverflow;
1589 }
1590 const truncated: i26 = @intCast(shifted_jump_offset);
1591 const parts: packed struct { lo16: u16, hi10: u10 } = @bitCast(truncated);
1592 const inst: *align(1) link.loongarch.D10K16 = @ptrCast(dest_slice[0..4]);
1593 elf.targetStore(inst, .{
1594 .d10 = parts.hi10,
1595 .k16 = parts.lo16,
1596 .b26_31 = elf.targetLoad(inst).b26_31,
1597 });
1598 },
1599 .larch_call36 => {
1600 // The allowed range of destination addresses here is non-trivial:
1601 // [PC - 128 GiB - 0x20_000, PC + 128 GiB - 0x20_000 - 4]
1602 const gib = 1024 * 1024 * 1024;
1603 if (jump_offset < -128 * gib - 0x20_000 or
1604 jump_offset > 128 * gib - 0x20_000 - 4)
1605 {
1606 return error.RelocationOverflow;
1607 }
1608 // The values we write into the instructions are a little weird too:
1609 const hi: i20 = @intCast((shifted_jump_offset +% 0x8000) >> 16);
1610 const lo: i16 = @truncate(shifted_jump_offset);
1611
1612 const inst0: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1613 const inst1: *align(1) link.loongarch.K16 = @ptrCast(dest_slice[4..8]);
1614
1615 const old0 = elf.targetLoad(inst0);
1616 elf.targetStore(inst0, .{ .b0_4 = old0.b0_4, .j20 = @bitCast(hi), .b25_31 = old0.b25_31 });
1617
1618 const old1 = elf.targetLoad(inst1);
1619 elf.targetStore(inst1, .{ .b0_9 = old1.b0_9, .k16 = @bitCast(lo), .b26_31 = old1.b26_31 });
1620 },
1621 else => unreachable,
1622 }
1623 },2071 },
1624 .sparc_le_hix22 => {2072 .sparc_op_hix22 => {
1625 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
1626 const tls_size: u64 = switch (elf.phdrSlice()) {
1627 inline else => |phdr| tls_size: {
1628 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
1629 break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz);
1630 },
1631 };
1632 const dest_ptr: *align(1) packed struct(u32) {2073 const dest_ptr: *align(1) packed struct(u32) {
1633 imm22: u22,2074 imm22: u22,
1634 b22_31: u10,2075 b22_31: u10,
1635 } = @ptrCast(dest_slice);2076 } = @ptrCast(dest_slice);
1636 elf.targetStore(dest_ptr, .{2077 elf.targetStore(dest_ptr, .{
1637 .imm22 = @truncate(~(target.value(elf) +% addend -% tls_size) >> 10),2078 .imm22 = @truncate(got_offset >> 10),
1638 .b22_31 = elf.targetLoad(dest_ptr).b22_31,2079 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
1639 });2080 });
1640 },2081 },
1641 }2082 }
1642 }2083 }
1643 };2084 };
2085 };
16442086
1645 fn dependsOnTlsSize(t: SymbolReloc.Type, elf: *const Elf) bool {2087 const Index = enum(u32) {
1646 return switch (elf.targetTlsVariant()) {2088 none = std.math.maxInt(u32),
1647 // In TLS variant I, the executable's TLS block starts at a fixed offset from the2089 _,
1648 // thread pointer, so everything is fine...
1649 .I_original, .I_modified => false,
1650 // ...but in variant II, the executable's TLS block *ends* at a fixed offset from
1651 // the thread pointer, so the offset from the thread pointer to the *start* of the
1652 // TLS block depends on the size of the block, and we need that offset to resolve
1653 // 'tpoff' relocations.
1654 .II => switch (t.target) {
1655 .abs,
1656 .rel,
1657 .pltabs,
1658 .pltrel,
1659 .dtpoff,
1660 .size,
1661 => false,
1662
1663 .tpoff => true,
1664
1665 .special => switch (t.action.special) {
1666 .sparc_le_hix22,
1667 => true,
16682090
1669 .larch_pcala_hi20,2091 fn get(index: GotReloc.Index, elf: *Elf) *GotReloc {
1670 .larch_pcala64_lo20,2092 return &elf.got_relocs.items[@backingInt(index)];
1671 .larch_pcala64_hi12,
1672 .larch_b21,
1673 .larch_b26,
1674 .larch_call36,
1675 => false,
1676 },
1677 },
1678 };
1679 }2093 }
1680 };2094 };
16812095
1682 fn apply(reloc: *SymbolReloc, elf: *Elf) void {2096 fn apply(reloc: *GotReloc, elf: *Elf) void {
1683 assert(elf.ehdrType() != .REL);2097 assert(elf.ehdrType() != .REL);
1684 if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) {2098 const node = reloc.node.unwrap() orelse return; // deleted
2099 if (node.hasMoved(&elf.mf) or elf.shndx.got.get(elf).ni.hasMoved(&elf.mf)) {
1685 // There's no point applying the relocation now, because it will be re-applied by2100 // There's no point applying the relocation now, because it will be re-applied by
1686 // `flushMoved` at some point anyway.2101 // `flushMoved` at some point anyway.
1687 return;2102 return;
...@@ -1705,118 +2120,99 @@ const SymbolReloc = struct {...@@ -1705,118 +2120,99 @@ const SymbolReloc = struct {
1705 },2120 },
1706 }2121 }
1707 }2122 }
1708 fn applyInner(reloc: *const SymbolReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {2123 fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
1709 const dest_vaddr = elf.getNodeVAddr(reloc.node) + reloc.offset;2124 const node = reloc.node.unwrap().?;
1710 const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..];2125 const dest_vaddr = elf.getNodeVAddr(node) + reloc.offset;
2126 const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..];
17112127
2128 const got_vaddr = elf.shndx.got.vaddr(elf);
2129 const got_index: u64 = elf.got.getIndex(reloc.target).?;
2130 const got_offset: u64 = switch (elf.identClass()) {
2131 .NONE, _ => unreachable,
2132 inline else => |class| @sizeOf(class.ElfN().Addr) * got_index,
2133 };
1712 const addend: u64 = @bitCast(reloc.addend);2134 const addend: u64 = @bitCast(reloc.addend);
1713 const target_val: u64 = type: switch (reloc.type.target) {2135
1714 .abs => reloc.target.value(elf) +% addend,2136 const target_val: u64 = switch (reloc.type.target) {
1715 .rel => reloc.target.value(elf) +% addend -% dest_vaddr,2137 .abs => got_vaddr +% got_offset +% addend,
1716 .pltabs => {2138 .rel => got_vaddr +% got_offset +% addend -% dest_vaddr,
1717 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .abs;2139 .offset => got_offset +% addend,
1718 break :type plt_entry_addr +% addend;
1719 },
1720 .pltrel => {
1721 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .rel;
1722 break :type plt_entry_addr +% addend -% dest_vaddr;
1723 },
1724 .dtpoff => reloc.target.value(elf) +% addend,
1725 .tpoff => switch (elf.targetTlsVariant()) {
1726 .I_original => |tls| tls.tcb_size +% reloc.target.value(elf) +% addend,
1727 .I_modified => |tls| 0 -% tls.tp_off +% reloc.target.value(elf) +% addend,
1728 .II => {
1729 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
1730 const tls_size: u64 = switch (elf.phdrSlice()) {
1731 inline else => |phdr| tls_size: {
1732 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
1733 break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz);
1734 },
1735 };
1736 break :type reloc.target.value(elf) +% addend -% tls_size;
1737 },
1738 },
1739 .size => switch (elf.symPtr(reloc.target.index(elf))) {
1740 inline else => |sym| elf.targetLoad(&sym.size),
1741 },
1742 .special => return reloc.type.action.special.applyInner(2140 .special => return reloc.type.action.special.applyInner(
1743 elf,2141 elf,
1744 reloc.target,2142 got_vaddr,
2143 got_offset,
1745 addend,2144 addend,
1746 dest_vaddr,2145 dest_vaddr,
1747 dest_slice,2146 dest_slice,
1748 ),2147 ),
1749 };2148 };
2149 try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian());
2150 }
17502151
1751 // Check for the `R_*_RELATIVE` case now, because it is possible only when no shift or cast2152 fn delete(reloc: *GotReloc, elf: *Elf) void {
1752 // is required, meaning we can handle it now and return early.2153 switch (reloc.result) {
1753 if (reloc.rela_index.unwrap()) |rela_index| switch (elf.classifySymbolValue(reloc.target)) {2154 .ok => {},
1754 .static => unreachable,2155 .overflowed => elf.overflowed_reloc_count -= 1,
1755 .dynamic => return, // the relocation happens at runtime2156 .misaligned => elf.misaligned_reloc_count -= 1,
1756 .static_relative => {2157 }
1757 // We have emitted an R_*_RELATIVE relocation to help lower an absolute-address2158 reloc.* = .{
1758 // relocation. The value computed above is valid, but instead of writing it to the2159 .node = .none,
1759 // destination slice, we actually want to write it to the runtime relocation entry.2160 .offset = undefined,
1760 switch (elf.identClass()) {2161 .target = undefined,
1761 .NONE, _ => unreachable,2162 .addend = undefined,
1762 .@"32" => assert(reloc.type.action.simple.dest == .@"32"),2163 .type = undefined,
1763 .@"64" => assert(reloc.type.action.simple.dest == .@"64"),2164 .result = undefined,
1764 }2165 };
1765 assert(reloc.type.action.simple.cast == .unsigned);2166 }
1766 assert(reloc.type.action.simple.shift == .@"0");2167};
1767 elf.shndx.rela_dyn.relaSetRelativeOffset(elf, rela_index, target_val);2168
1768 return;2169fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe_global }) Error!void {
1769 },2170 const gpa = elf.base.comp.gpa;
2171
2172 try elf.symtab.ensureUnusedCapacity(gpa, len);
2173
2174 // If adding locals, we may need to move one global out of the way for each local. If adding
2175 // globals, they could all get demoted to STB_LOCAL, meaning we have to move N other globals
2176 // around to keep `.dynsym` compact. Either way, the maximum is N.
2177 try elf.changed_symtab_index.ensureUnusedCapacity(gpa, len);
2178
2179 {
2180 // Ensure the symtab section's node is big enough
2181 const need_node_size: u64 = switch (elf.shdrPtr(.symtab)) {
2182 inline else => |shdr, class| elf.targetLoad(&shdr.size) + len * @sizeOf(class.ElfN().Sym),
1770 };2183 };
17712184 try Section.Index.symtab.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_node_size);
1772 try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian());
1773 }2185 }
17742186
1775 fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void {2187 switch (kind) {
1776 assert(index.get(elf) == reloc);2188 .all_local => {},
2189 .maybe_global => {
2190 try elf.globals.strong_def.ensureUnusedCapacity(gpa, len);
2191 try elf.globals.weak_def.ensureUnusedCapacity(gpa, len);
2192 try elf.globals.strong_undef.ensureUnusedCapacity(gpa, len);
2193 try elf.globals.weak_undef.ensureUnusedCapacity(gpa, len);
17772194
1778 reloc.deleteOutputRel(elf);2195 try elf.node_global_symbols.ensureUnusedCapacity(gpa, len);
1779 if (reloc.type.dependsOnTlsSize(elf)) {
1780 assert(elf.tls_size_symbol_relocs.swapRemove(index));
1781 }
17822196
1783 switch (reloc.prev) {2197 if (elf.shndx.dynsym != .UNDEF) {
1784 .none => {2198 const dynsym_cur_size: u64, const dynsym_ent_size: u32 = switch (elf.shdrPtr(elf.shndx.dynsym)) {
1785 const target_ptr = reloc.target.index(elf).ptr(elf);2199 inline else => |shdr, class| .{
1786 assert(target_ptr.first_target_reloc == index);2200 elf.targetLoad(&shdr.size),
1787 target_ptr.first_target_reloc = reloc.next;2201 @sizeOf(class.ElfN().Sym),
1788 },2202 },
1789 else => |prev| prev.get(elf).next = reloc.next,2203 };
1790 }2204 const dynsym_cur_len: u32 = @intCast(@divExact(dynsym_cur_size, dynsym_ent_size));
1791 switch (reloc.next) {
1792 .none => {},
1793 else => |next| next.get(elf).prev = reloc.prev,
1794 }
1795 switch (reloc.result) {
1796 .ok => {},
1797 .overflowed => elf.overflowed_reloc_count -= 1,
1798 .misaligned => elf.misaligned_reloc_count -= 1,
1799 }
18002205
1801 reloc.* = undefined;2206 const dynsym_need_size: u64 = (dynsym_cur_len + len) * dynsym_ent_size;
1802 }2207 try elf.shndx.dynsym.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, dynsym_need_size);
18032208
1804 /// If `reloc.rela_index` is populated, reset it to `.none` and delete the relocation, updating2209 try elf.ensureDynsymHashCapacity(dynsym_cur_len + len);
1805 /// `elf.textrel_count` if necessary.2210
1806 fn deleteOutputRel(reloc: *SymbolReloc, elf: *Elf) void {2211 try elf.ensureUnusedPltCapacity(len);
1807 const rela_index = reloc.rela_index.unwrap() orelse return;2212 }
1808 reloc.relaSection(elf).relaDeleteOne(elf, rela_index);2213 },
1809 switch (elf.ehdrType()) {
1810 .REL => {},
1811 .EXEC, .DYN => switch (elf.nodeWantsDsoRelocation(reloc.node)) {
1812 .no => unreachable, // there *was* a dynamic relocation!
1813 .yes => {},
1814 .yes_textrel => elf.textrel_count -= 1,
1815 },
1816 }
1817 reloc.rela_index = .none;
1818 }2214 }
1819};2215}
18202216
1821fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {2217fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {
1822 const gpa = elf.base.comp.gpa;2218 const gpa = elf.base.comp.gpa;
...@@ -1841,7 +2237,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {...@@ -1841,7 +2237,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {
1841 // We don't need to add any buckets, but we still need to make sure the section is large2237 // We don't need to add any buckets, but we still need to make sure the section is large
1842 // enough to fit `max_dynsym_count` chains.2238 // enough to fit `max_dynsym_count` chains.
1843 const need_size = @sizeOf(info.Header()) + (nbucket + max_dynsym_count) * 4;2239 const need_size = @sizeOf(info.Header()) + (nbucket + max_dynsym_count) * 4;
1844 try elf.shndx.hash.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_size);2240 try elf.shndx.hash.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_size);
1845 return;2241 return;
1846 }2242 }
1847 // We need more buckets, so we'll have to rebuild the hash table.2243 // We need more buckets, so we'll have to rebuild the hash table.
...@@ -1853,7 +2249,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {...@@ -1853,7 +2249,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {
18532249
1854 {2250 {
1855 const need_size = @sizeOf(info.Header()) + (new_nbucket + max_dynsym_count) * 4;2251 const need_size = @sizeOf(info.Header()) + (new_nbucket + max_dynsym_count) * 4;
1856 try elf.shndx.hash.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_size);2252 try elf.shndx.hash.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_size);
1857 }2253 }
18582254
1859 elf.mf.nodes_lock.lock();2255 elf.mf.nodes_lock.lock();
...@@ -1984,53 +2380,6 @@ fn clearDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {...@@ -1984,53 +2380,6 @@ fn clearDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {
1984 }2380 }
1985}2381}
19862382
1987fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe_global }) Error!void {
1988 const gpa = elf.base.comp.gpa;
1989
1990 try elf.symtab.ensureUnusedCapacity(gpa, len);
1991
1992 // If adding locals, we may need to move one global out of the way for each local. If adding
1993 // globals, they could all get demoted to STB_LOCAL, meaning we have to move N other globals
1994 // around to keep `.dynsym` compact. Either way, the maximum is N.
1995 try elf.changed_symtab_index.ensureUnusedCapacity(gpa, len);
1996
1997 {
1998 // Ensure the symtab section's node is big enough
1999 const need_node_size: u64 = switch (elf.shdrPtr(.symtab)) {
2000 inline else => |shdr, class| elf.targetLoad(&shdr.size) + len * @sizeOf(class.ElfN().Sym),
2001 };
2002 try Section.Index.symtab.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_node_size);
2003 }
2004
2005 switch (kind) {
2006 .all_local => {},
2007 .maybe_global => {
2008 try elf.globals.strong_def.ensureUnusedCapacity(gpa, len);
2009 try elf.globals.weak_def.ensureUnusedCapacity(gpa, len);
2010 try elf.globals.strong_undef.ensureUnusedCapacity(gpa, len);
2011 try elf.globals.weak_undef.ensureUnusedCapacity(gpa, len);
2012
2013 try elf.node_global_symbols.ensureUnusedCapacity(gpa, len);
2014
2015 if (elf.shndx.dynsym != .UNDEF) {
2016 const dynsym_cur_size: u64, const dynsym_ent_size: u32 = switch (elf.shdrPtr(elf.shndx.dynsym)) {
2017 inline else => |shdr, class| .{
2018 elf.targetLoad(&shdr.size),
2019 @sizeOf(class.ElfN().Sym),
2020 },
2021 };
2022 const dynsym_cur_len: u32 = @intCast(@divExact(dynsym_cur_size, dynsym_ent_size));
2023
2024 const dynsym_need_size: u64 = (dynsym_cur_len + len) * dynsym_ent_size;
2025 try elf.shndx.dynsym.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, dynsym_need_size);
2026
2027 try elf.ensureDynsymHashCapacity(dynsym_cur_len + len);
2028
2029 try elf.ensureUnusedPltCapacity(len);
2030 }
2031 },
2032 }
2033}
2034fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {2383fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
2035 const gpa = elf.base.comp.gpa;2384 const gpa = elf.base.comp.gpa;
20362385
...@@ -2044,19 +2393,19 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {...@@ -2044,19 +2393,19 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
2044 // Ensure the `.plt` section's node is big enough:2393 // Ensure the `.plt` section's node is big enough:
2045 {2394 {
2046 const need_size: usize = plt.entry_size * (1 + need_plt_count);2395 const need_size: usize = plt.entry_size * (1 + need_plt_count);
2047 try elf.shndx.plt.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_size);2396 try elf.shndx.plt.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_size);
2048 }2397 }
20492398
2050 // If there is a `.got.plt` section, ensure its node is big enough2399 // If there is a `.got.plt` section, ensure its node is big enough
2051 if (plt.got_plt) |got_plt| {2400 if (plt.got_plt) |got_plt| {
2052 const need_size: usize = elf.targetPtrSize() * (got_plt.header_entries + need_plt_count);2401 const need_size: usize = elf.targetPtrSize() * (got_plt.header_entries + need_plt_count);
2053 try elf.shndx.got_plt.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_size);2402 try elf.shndx.got_plt.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_size);
2054 }2403 }
20552404
2056 // If there is a `.plt.sec` section, ensure its node is big enough2405 // If there is a `.plt.sec` section, ensure its node is big enough
2057 if (plt.plt_sec) |plt_sec| {2406 if (plt.plt_sec) |plt_sec| {
2058 const need_size: usize = plt_sec.entry_size * need_plt_count;2407 const need_size: usize = plt_sec.entry_size * need_plt_count;
2059 try elf.shndx.plt_sec.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_size);2408 try elf.shndx.plt_sec.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_size);
2060 }2409 }
2061}2410}
2062/// Given an index into the PLT, returns whether that PLT entry is dead, meaning it may be reused at2411/// Given an index into the PLT, returns whether that PLT entry is dead, meaning it may be reused at
...@@ -2138,7 +2487,7 @@ fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.L...@@ -2138,7 +2487,7 @@ fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.L
2138 .other = .{ .visibility = .DEFAULT },2487 .other = .{ .visibility = .DEFAULT },
2139 .shndx = opts.shndx.toSection().?,2488 .shndx = opts.shndx.toSection().?,
2140 };2489 };
2141 if (elf.targetEndian() != native_endian) {2490 if (elf.targetEndian() != std.lang.Endian.native) {
2142 std.mem.byteSwapAllFields(class.ElfN().Sym, target_sym);2491 std.mem.byteSwapAllFields(class.ElfN().Sym, target_sym);
2143 }2492 }
21442493
...@@ -2323,7 +2672,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{...@@ -2323,7 +2672,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{
2323 .other = .{ .visibility = opts.visibility },2672 .other = .{ .visibility = opts.visibility },
2324 .shndx = opts.shndx.toSection().?,2673 .shndx = opts.shndx.toSection().?,
2325 };2674 };
2326 if (elf.targetEndian() != native_endian) {2675 if (elf.targetEndian() != std.lang.Endian.native) {
2327 std.mem.byteSwapAllFields(Sym, sym);2676 std.mem.byteSwapAllFields(Sym, sym);
2328 }2677 }
2329 },2678 },
...@@ -2359,7 +2708,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{...@@ -2359,7 +2708,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{
2359 .other = .{ .visibility = opts.visibility },2708 .other = .{ .visibility = opts.visibility },
2360 .shndx = opts.shndx.toSection().?,2709 .shndx = opts.shndx.toSection().?,
2361 };2710 };
2362 if (elf.targetEndian() != native_endian) {2711 if (elf.targetEndian() != std.lang.Endian.native) {
2363 std.mem.byteSwapAllFields(Sym, sym);2712 std.mem.byteSwapAllFields(Sym, sym);
2364 }2713 }
2365 elf.appendDynsymHashEntry(dynsym_index);2714 elf.appendDynsymHashEntry(dynsym_index);
...@@ -2869,7 +3218,8 @@ const Symbol = struct {...@@ -2869,7 +3218,8 @@ const Symbol = struct {
2869 .abs, .pltabs => {},3218 .abs, .pltabs => {},
2870 }3219 }
2871 if (!reloc.type.action.simple.dest.isAddr(elf)) continue;3220 if (!reloc.type.action.simple.dest.isAddr(elf)) continue;
2872 switch (elf.nodeWantsDsoRelocation(reloc.node)) {3221 const node = reloc.node.unwrap().?;
3222 switch (elf.nodeWantsDsoRelocation(node)) {
2873 .no => continue,3223 .no => continue,
2874 .yes_textrel => elf.textrel_count += 1,3224 .yes_textrel => elf.textrel_count += 1,
2875 .yes => {},3225 .yes => {},
...@@ -2877,7 +3227,7 @@ const Symbol = struct {...@@ -2877,7 +3227,7 @@ const Symbol = struct {
2877 // There is capacity for a relocation because we just deleted one earlier.3227 // There is capacity for a relocation because we just deleted one earlier.
2878 reloc.rela_index = elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{3228 reloc.rela_index = elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{
2879 .type = .relative(elf),3229 .type = .relative(elf),
2880 .offset = elf.getNodeVAddr(reloc.node) + reloc.offset,3230 .offset = elf.getNodeVAddr(node) + reloc.offset,
2881 .raw_sym_index = 0,3231 .raw_sym_index = 0,
2882 .addend = 0,3232 .addend = 0,
2883 }).toOptional();3233 }).toOptional();
...@@ -2982,6 +3332,7 @@ fn classifySymbolValue(elf: *Elf, sym: Symbol.Id) enum {...@@ -2982,6 +3332,7 @@ fn classifySymbolValue(elf: *Elf, sym: Symbol.Id) enum {
29823332
2983pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {3333pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {
2984 const lsi: Symbol.LocalIndex = switch (elf.getNode(Node.fromAtom(atom))) {3334 const lsi: Symbol.LocalIndex = switch (elf.getNode(Node.fromAtom(atom))) {
3335 .deleted,
2985 .archive,3336 .archive,
2986 .archive_header,3337 .archive_header,
2987 .archive_input_member,3338 .archive_input_member,
...@@ -2991,10 +3342,27 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {...@@ -2991,10 +3342,27 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {
2991 .shdr,3342 .shdr,
2992 .segment,3343 .segment,
2993 .section,3344 .section,
3345 .section_manual_size,
2994 .input_section,3346 .input_section,
2995 .copied_global,3347 .copied_global,
3348 .debug_shared,
3349 .eh_frame_footer,
3350 .unit_padding,
3351 .unit_frame,
3352 .unit_frame_cie,
3353 .unit_debug_info,
3354 .unit_debug_info_header,
3355 .unit_debug_info_footer,
3356 .unit_debug_line,
3357 .unit_debug_line_header,
3358 .unit_debug_rnglists,
3359 .const_debug_info,
3360 .global_debug_info,
3361 .func_frame_fde,
3362 .func_debug_info,
3363 .func_debug_line,
3364 .decl_debug_info,
2996 => unreachable,3365 => unreachable,
2997
2998 inline .nav,3366 inline .nav,
2999 .uav,3367 .uav,
3000 .lazy_code,3368 .lazy_code,
...@@ -3005,10 +3373,9 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {...@@ -3005,10 +3373,9 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {
3005 return s.toTypeErased();3373 return s.toTypeErased();
3006}3374}
3007pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) link.Error!link.File.SymbolId {3375pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) link.Error!link.File.SymbolId {
3008 const diags = &elf.base.comp.link_diags;
3009 return elf.lazySymbolInner(lazy) catch |err| switch (err) {3376 return elf.lazySymbolInner(lazy) catch |err| switch (err) {
3010 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3011 else => |e| return e,3377 else => |e| return e,
3378 error.MappedFileIo => return elf.base.comp.link_diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3012 };3379 };
3013}3380}
3014fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.SymbolId {3381fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.SymbolId {
...@@ -3024,13 +3391,16 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol...@@ -3024,13 +3391,16 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol
3024 .code => .{ .text, .FUNC },3391 .code => .{ .text, .FUNC },
3025 .const_data => .{ .rodata, .OBJECT },3392 .const_data => .{ .rodata, .OBJECT },
3026 };3393 };
3027 const node = try shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{});3394 const node = elf.addNodeAssumeCapacity(
3028 var name_buf: [64]u8 = undefined;3395 try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}),
3029 const name = std.mem.print(3396 switch (lazy.kind) {
3030 &name_buf,3397 .code => .{ .lazy_code = @fromBackingInt(@intCast(gop.index)) },
3031 "__lazy_{t}_{d}",3398 .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(gop.index)) },
3032 .{ lazy.kind, @backingInt(lazy.ty) },3399 },
3033 ) catch unreachable;3400 );
3401 var name_buf: [std.fmt.count("__lazy_const_data_{d}", .{std.math.maxInt(u32)})]u8 = undefined;
3402 const name = std.mem.print(&name_buf, "__lazy_{t}_{d}", .{ lazy.kind, gop.index }) catch
3403 unreachable;
3034 gop.value_ptr.* = .{3404 gop.value_ptr.* = .{
3035 .lsi = elf.addLocalSymbolAssumeCapacity(.{3405 .lsi = elf.addLocalSymbolAssumeCapacity(.{
3036 .node = .wrap(node),3406 .node = .wrap(node),
...@@ -3043,11 +3413,7 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol...@@ -3043,11 +3413,7 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol
3043 .first_symbol_reloc = .none,3413 .first_symbol_reloc = .none,
3044 .first_got_reloc = .none,3414 .first_got_reloc = .none,
3045 };3415 };
3046 elf.nodes.appendAssumeCapacity(switch (lazy.kind) {3416 elf.base.comp.link_prog_node.increaseEstimatedTotalItems(1);
3047 .code => .{ .lazy_code = @fromBackingInt(@intCast(gop.index)) },
3048 .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(gop.index)) },
3049 });
3050 elf.synth_prog_node.increaseEstimatedTotalItems(1);
3051 }3417 }
3052 const s: Symbol.Id = .local(gop.value_ptr.lsi);3418 const s: Symbol.Id = .local(gop.value_ptr.lsi);
3053 return s.toTypeErased();3419 return s.toTypeErased();
...@@ -3062,8 +3428,8 @@ pub const ExternSymbolOpts = struct {...@@ -3062,8 +3428,8 @@ pub const ExternSymbolOpts = struct {
3062pub fn externSymbol(elf: *Elf, opts: ExternSymbolOpts) link.Error!link.File.SymbolId {3428pub fn externSymbol(elf: *Elf, opts: ExternSymbolOpts) link.Error!link.File.SymbolId {
3063 const diags = &elf.base.comp.link_diags;3429 const diags = &elf.base.comp.link_diags;
3064 return (elf.externSymbolInner(opts) catch |err| switch (err) {3430 return (elf.externSymbolInner(opts) catch |err| switch (err) {
3065 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3066 else => |e| return e,3431 else => |e| return e,
3432 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3067 }).toTypeErased();3433 }).toTypeErased();
3068}3434}
3069fn externSymbolInner(elf: *Elf, opts: ExternSymbolOpts) Error!Symbol.Id {3435fn externSymbolInner(elf: *Elf, opts: ExternSymbolOpts) Error!Symbol.Id {
...@@ -3103,15 +3469,33 @@ pub fn addReloc(...@@ -3103,15 +3469,33 @@ pub fn addReloc(
3103 const node: MappedFile.Node.Index = Node.fromAtom(atom);3469 const node: MappedFile.Node.Index = Node.fromAtom(atom);
3104 const diags = &elf.base.comp.link_diags;3470 const diags = &elf.base.comp.link_diags;
3105 elf.ensureUnusedRelocCapacity(node, 1) catch |err| switch (err) {3471 elf.ensureUnusedRelocCapacity(node, 1) catch |err| switch (err) {
3106 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3107 else => |e| return e,3472 else => |e| return e,
3473 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3108 };3474 };
3109 elf.addRelocAssumeCapacity(node, offset, .fromTypeErased(target), addend, @"type") catch |err| switch (err) {3475 elf.addRelocAssumeCapacity(node, offset, .fromTypeErased(target), addend, @"type") catch |err| switch (err) {
3476 else => |e| return e,
3110 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),3477 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3111 error.UnknownRelocation => unreachable, // codegen bug3478 error.UnknownRelocation => unreachable, // codegen bug
3112 error.NonStaticRelocation => unreachable, // codegen bug3479 error.NonStaticRelocation => unreachable, // codegen bug
3113 error.UnimplementedRelocation => unreachable, // codegen bug (asking Elf2 for a relocation it does not support)3480 error.UnimplementedRelocation => unreachable, // codegen bug (asking Elf2 for a relocation it does not support)
3481 };
3482}
3483pub fn addNodeReloc(
3484 elf: *Elf,
3485 node: MappedFile.Node.Index,
3486 offset: u64,
3487 target: MappedFile.Node.Index,
3488 addend: i64,
3489 @"type": NodeReloc.Type,
3490) link.Error!void {
3491 const diags = &elf.base.comp.link_diags;
3492 elf.ensureUnusedRelocCapacity(node, 1) catch |err| switch (err) {
3493 else => |e| return e,
3494 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3495 };
3496 elf.addNodeRelocAssumeCapacity(node, offset, target, addend, @"type") catch |err| switch (err) {
3114 else => |e| return e,3497 else => |e| return e,
3498 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3115 };3499 };
3116}3500}
3117pub fn navSymbol(elf: *Elf, nav_index: InternPool.Nav.Index) link.Error!link.File.SymbolId {3501pub fn navSymbol(elf: *Elf, nav_index: InternPool.Nav.Index) link.Error!link.File.SymbolId {
...@@ -3129,8 +3513,8 @@ pub fn navSymbol(elf: *Elf, nav_index: InternPool.Nav.Index) link.Error!link.Fil...@@ -3129,8 +3513,8 @@ pub fn navSymbol(elf: *Elf, nav_index: InternPool.Nav.Index) link.Error!link.Fil
3129 });3513 });
3130 }3514 }
3131 const nmi = elf.navMapIndex(zcu, nav_index) catch |err| switch (err) {3515 const nmi = elf.navMapIndex(zcu, nav_index) catch |err| switch (err) {
3132 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3133 else => |e| return e,3516 else => |e| return e,
3517 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3134 };3518 };
3135 const s: Symbol.Id = .local(nmi.symbol(elf));3519 const s: Symbol.Id = .local(nmi.symbol(elf));
3136 return s.toTypeErased();3520 return s.toTypeErased();
...@@ -3142,8 +3526,8 @@ pub fn uavSymbol(...@@ -3142,8 +3526,8 @@ pub fn uavSymbol(
3142) link.Error!link.File.SymbolId {3526) link.Error!link.File.SymbolId {
3143 const diags = &elf.base.comp.link_diags;3527 const diags = &elf.base.comp.link_diags;
3144 const umi = elf.uavMapIndex(uav_val, uav_align) catch |err| switch (err) {3528 const umi = elf.uavMapIndex(uav_val, uav_align) catch |err| switch (err) {
3145 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3146 else => |e| return e,3529 else => |e| return e,
3530 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3147 };3531 };
3148 const s: Symbol.Id = .local(umi.symbol(elf));3532 const s: Symbol.Id = .local(umi.symbol(elf));
3149 return s.toTypeErased();3533 return s.toTypeErased();
...@@ -3166,7 +3550,11 @@ pub fn getUavVAddr(...@@ -3166,7 +3550,11 @@ pub fn getUavVAddr(
3166}3550}
3167pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target: link.File.SymbolId) link.Error!u64 {3551pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target: link.File.SymbolId) link.Error!u64 {
3168 try elf.addReloc(3552 try elf.addReloc(
3169 reloc_info.parent.atom_index,3553 switch (reloc_info.parent) {
3554 .none => unreachable,
3555 .atom_index => |atom_id| atom_id,
3556 .debug_output => |debug_output| Node.toAtom(debug_output.dwarf2.info_writer.ni),
3557 },
3170 reloc_info.offset,3558 reloc_info.offset,
3171 target,3559 target,
3172 reloc_info.addend,3560 reloc_info.addend,
...@@ -3183,8 +3571,8 @@ pub fn lowerUav(...@@ -3183,8 +3571,8 @@ pub fn lowerUav(
3183 _ = pt;3571 _ = pt;
3184 const diags = &elf.base.comp.link_diags;3572 const diags = &elf.base.comp.link_diags;
3185 const umi = elf.uavMapIndex(uav_val, uav_align) catch |err| switch (err) {3573 const umi = elf.uavMapIndex(uav_val, uav_align) catch |err| switch (err) {
3186 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3187 else => |e| return e,3574 else => |e| return e,
3575 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3188 };3576 };
3189 const s: Symbol.Id = .local(umi.symbol(elf));3577 const s: Symbol.Id = .local(umi.symbol(elf));
3190 return s.toTypeErased();3578 return s.toTypeErased();
...@@ -3283,7 +3671,7 @@ const StringTable = struct {...@@ -3283,7 +3671,7 @@ const StringTable = struct {
3283 break :size .{ old_size, new_size };3671 break :size .{ old_size, new_size };
3284 },3672 },
3285 };3673 };
3286 try ni.ensureMinimumSize(&elf.mf, gpa, new_size);3674 try ni.ensureMinimumSize(gpa, &elf.mf, new_size);
3287 const slice = ni.slice(&elf.mf)[old_size..];3675 const slice = ni.slice(&elf.mf)[old_size..];
3288 @memcpy(slice[0..key.len], key);3676 @memcpy(slice[0..key.len], key);
3289 slice[key.len] = 0;3677 slice[key.len] = 0;
...@@ -3393,6 +3781,7 @@ fn create(...@@ -3393,6 +3781,7 @@ fn create(
3393 .data = undefined,3781 .data = undefined,
3394 .data_rel_ro = undefined,3782 .data_rel_ro = undefined,
3395 .tls = .none,3783 .tls = .none,
3784 .gnu_eh_frame = .none,
3396 },3785 },
3397 .archive = null,3786 .archive = null,
3398 .nodes = .empty,3787 .nodes = .empty,
...@@ -3410,6 +3799,16 @@ fn create(...@@ -3410,6 +3799,16 @@ fn create(
3410 .tdata = .UNDEF,3799 .tdata = .UNDEF,
3411 .rela_dyn = .UNDEF,3800 .rela_dyn = .UNDEF,
3412 .rela_plt = .UNDEF,3801 .rela_plt = .UNDEF,
3802 .debug_abbrev = .UNDEF,
3803 .eh_frame_hdr = .UNDEF,
3804 .eh_frame = .UNDEF,
3805 .debug_frame = .UNDEF,
3806 .debug_info = .UNDEF,
3807 .debug_line = .UNDEF,
3808 .debug_line_str = .UNDEF,
3809 .debug_rnglists = .UNDEF,
3810 .debug_str = .UNDEF,
3811 .debug_str_offsets = .UNDEF,
3413 .init_array = .UNDEF,3812 .init_array = .UNDEF,
3414 .fini_array = .UNDEF,3813 .fini_array = .UNDEF,
3415 .preinit_array = .UNDEF,3814 .preinit_array = .UNDEF,
...@@ -3437,6 +3836,7 @@ fn create(...@@ -3437,6 +3836,7 @@ fn create(
3437 .got = .empty,3836 .got = .empty,
3438 .plt = .empty,3837 .plt = .empty,
3439 .plt_first_symbol_reloc = .none,3838 .plt_first_symbol_reloc = .none,
3839 .eh_frame_hdr_first_symbol_reloc = .none,
3440 .needed = .empty,3840 .needed = .empty,
3441 .inputs = .empty,3841 .inputs = .empty,
3442 .input_pending_index = 0,3842 .input_pending_index = 0,
...@@ -3451,15 +3851,31 @@ fn create(...@@ -3451,15 +3851,31 @@ fn create(
3451 }),3851 }),
3452 .pending_uavs = .empty,3852 .pending_uavs = .empty,
3453 .symbol_relocs = .empty,3853 .symbol_relocs = .empty,
3854 .node_relocs = .empty,
3454 .got_relocs = .empty,3855 .got_relocs = .empty,
3455 .tls_size_symbol_relocs = .empty,3856 .tls_size_symbol_relocs = .empty,
3456 .section_by_name = .empty,3857 .section_by_name = .empty,
3457 .changed_symtab_index = .empty,3858 .changed_symtab_index = .empty,
3458 .textrel_count = 0,3859 .textrel_count = 0,
3860
3861 .dwarf = .init(&elf.base, switch (comp.config.debug_format) {
3862 .strip => .@"32", // for .eh_frame
3863 .dwarf => |v| v,
3864 .code_view => unreachable,
3865 }),
3866 .dwarf_shared = comptime .initFill(.{
3867 .first_target_reloc = .none,
3868 }),
3869 .dwarf_units = &.{},
3870 .dwarf_consts = .empty,
3871 .dwarf_globals = .empty,
3872 .dwarf_funcs = .empty,
3873 .dwarf_decls = .empty,
3874
3459 .overflowed_reloc_count = 0,3875 .overflowed_reloc_count = 0,
3460 .misaligned_reloc_count = 0,3876 .misaligned_reloc_count = 0,
3877
3461 .const_prog_node = .none,3878 .const_prog_node = .none,
3462 .synth_prog_node = .none,
3463 .input_prog_node = .none,3879 .input_prog_node = .none,
3464 };3880 };
3465 errdefer elf.deinit();3881 errdefer elf.deinit();
...@@ -3498,10 +3914,20 @@ pub fn deinit(elf: *Elf) void {...@@ -3498,10 +3914,20 @@ pub fn deinit(elf: *Elf) void {
3498 for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa);3914 for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa);
3499 elf.pending_uavs.deinit(gpa);3915 elf.pending_uavs.deinit(gpa);
3500 elf.symbol_relocs.deinit(gpa);3916 elf.symbol_relocs.deinit(gpa);
3917 elf.node_relocs.deinit(gpa);
3501 elf.got_relocs.deinit(gpa);3918 elf.got_relocs.deinit(gpa);
3502 elf.tls_size_symbol_relocs.deinit(gpa);3919 elf.tls_size_symbol_relocs.deinit(gpa);
3503 elf.section_by_name.deinit(gpa);3920 elf.section_by_name.deinit(gpa);
3504 elf.changed_symtab_index.deinit(gpa);3921 elf.changed_symtab_index.deinit(gpa);
3922
3923 elf.dwarf.deinit();
3924 for (elf.dwarf_units) |*dwarf_unit| dwarf_unit.debug_rnglists_symbol_relocs.deinit(gpa);
3925 gpa.free(elf.dwarf_units);
3926 elf.dwarf_consts.deinit(gpa);
3927 elf.dwarf_globals.deinit(gpa);
3928 elf.dwarf_funcs.deinit(gpa);
3929 elf.dwarf_decls.deinit(gpa);
3930
3505 elf.* = undefined;3931 elf.* = undefined;
3506}3932}
35073933
...@@ -3518,11 +3944,17 @@ fn initHeaders(...@@ -3518,11 +3944,17 @@ fn initHeaders(
3518 const gpa = comp.gpa;3944 const gpa = comp.gpa;
35193945
3520 const is_archive = comp.config.output_mode == .Lib and comp.config.link_mode == .static;3946 const is_archive = comp.config.output_mode == .Lib and comp.config.link_mode == .static;
3521 const have_dynamic_section = switch (@"type") {3947 const have_dynamic = switch (@"type") {
3522 .REL => false,3948 .REL => false,
3523 .EXEC => comp.config.link_mode == .dynamic,3949 .EXEC => comp.config.link_mode == .dynamic,
3524 .DYN => true,3950 .DYN => true,
3525 };3951 };
3952 const have_eh_frame = machine == .X86_64 and comp.config.any_unwind_tables;
3953 const have_debug_frame = machine == .X86_64 and switch (comp.config.debug_format) {
3954 .strip => false,
3955 .dwarf => !comp.config.any_unwind_tables,
3956 .code_view => unreachable,
3957 };
3526 const addr_align: Alignment = switch (class) {3958 const addr_align: Alignment = switch (class) {
3527 .NONE, _ => unreachable,3959 .NONE, _ => unreachable,
3528 .@"32" => .@"4",3960 .@"32" => .@"4",
...@@ -3537,7 +3969,7 @@ fn initHeaders(...@@ -3537,7 +3969,7 @@ fn initHeaders(
3537 //3969 //
3538 // It can be handy to temporarily set this to `.@"1"` when working on the linker, because it3970 // It can be handy to temporarily set this to `.@"1"` when working on the linker, because it
3539 // prevents alignment bugs from being hidden by your filesystem's block alignment.3971 // prevents alignment bugs from being hidden by your filesystem's block alignment.
3540 const node_block_align: Alignment = elf.mf.flags.block_size;3972 const node_block_align = elf.mf.flags.block_size;
35413973
3542 const plt: PltInfo = .fromMachine(machine);3974 const plt: PltInfo = .fromMachine(machine);
35433975
...@@ -3552,7 +3984,7 @@ fn initHeaders(...@@ -3552,7 +3984,7 @@ fn initHeaders(
3552 shnum += 1; // .data3984 shnum += 1; // .data
3553 shnum += @intFromBool(comp.config.any_non_single_threaded); // .tdata3985 shnum += @intFromBool(comp.config.any_non_single_threaded); // .tdata
3554 shnum += 1; // .data.rel.ro3986 shnum += 1; // .data.rel.ro
3555 if (have_dynamic_section) {3987 if (have_dynamic) {
3556 shnum += 1; // .dynamic3988 shnum += 1; // .dynamic
3557 shnum += 1; // .dynstr3989 shnum += 1; // .dynstr
3558 shnum += 1; // .dynsym3990 shnum += 1; // .dynsym
...@@ -3560,6 +3992,24 @@ fn initHeaders(...@@ -3560,6 +3992,24 @@ fn initHeaders(
3560 shnum += 1; // .rela.dyn3992 shnum += 1; // .rela.dyn
3561 shnum += 1; // .rela.plt3993 shnum += 1; // .rela.plt
3562 }3994 }
3995 if (have_eh_frame) {
3996 shnum += @intFromBool(@"type" != .REL); // .eh_frame_hdr
3997 shnum += 1; // .eh_frame
3998 }
3999 switch (comp.config.debug_format) {
4000 .strip => {},
4001 .dwarf => {
4002 shnum += 1; // .debug_abbrev
4003 shnum += @intFromBool(have_debug_frame); // .debug_frame
4004 shnum += 1; // .debug_info
4005 shnum += 1; // .debug_line
4006 shnum += 1; // .debug_line_str
4007 shnum += 1; // .debug_rnglists
4008 shnum += 1; // .debug_str
4009 shnum += 1; // .debug_str_offsets
4010 },
4011 .code_view => unreachable,
4012 }
3563 if (@"type" != .REL) {4013 if (@"type" != .REL) {
3564 shnum += 1; // .got4014 shnum += 1; // .got
3565 shnum += @intFromBool(plt.got_plt != null); // .got.plt4015 shnum += @intFromBool(plt.got_plt != null); // .got.plt
...@@ -3574,14 +4024,15 @@ fn initHeaders(...@@ -3574,14 +4024,15 @@ fn initHeaders(
3574 interp: u32,4024 interp: u32,
3575 rodata: u32,4025 rodata: u32,
3576 text: u32,4026 text: u32,
3577 data: u32,
3578 /// On most targets this is `undefined`, but on machines where JUMP_SLOT relocations write4027 /// On most targets this is `undefined`, but on machines where JUMP_SLOT relocations write
3579 /// directly to the PLT, we place the PLT in its own segment in order to avoid making the4028 /// directly to the PLT, we place the PLT in its own segment in order to avoid making the
3580 /// general data segment RWX.4029 /// general data segment RWX.
3581 plt: u32,4030 plt: u32,
4031 data: u32,
3582 tls: u32,4032 tls: u32,
3583 dynamic: u32,4033 dynamic: u32,
3584 relro: u32,4034 relro: u32,
4035 gnu_eh_frame: u32,
3585 gnu_stack: u32,4036 gnu_stack: u32,
3586 }, const phnum: u32 = ph: {4037 }, const phnum: u32 = ph: {
3587 switch (@"type") {4038 switch (@"type") {
...@@ -3622,7 +4073,7 @@ fn initHeaders(...@@ -3622,7 +4073,7 @@ fn initHeaders(
3622 defer phnum += 1;4073 defer phnum += 1;
3623 break :phndx phnum;4074 break :phndx phnum;
3624 } else undefined,4075 } else undefined,
3625 .dynamic = if (have_dynamic_section) phndx: {4076 .dynamic = if (have_dynamic) phndx: {
3626 defer phnum += 1;4077 defer phnum += 1;
3627 break :phndx phnum;4078 break :phndx phnum;
3628 } else undefined,4079 } else undefined,
...@@ -3630,6 +4081,10 @@ fn initHeaders(...@@ -3630,6 +4081,10 @@ fn initHeaders(
3630 defer phnum += 1;4081 defer phnum += 1;
3631 break :phndx phnum;4082 break :phndx phnum;
3632 },4083 },
4084 .gnu_eh_frame = if (have_eh_frame) phndx: {
4085 defer phnum += 1;
4086 break :phndx phnum;
4087 } else undefined,
3633 .gnu_stack = phndx: {4088 .gnu_stack = phndx: {
3634 defer phnum += 1;4089 defer phnum += 1;
3635 break :phndx phnum;4090 break :phndx phnum;
...@@ -3643,7 +4098,8 @@ fn initHeaders(...@@ -3643,7 +4098,8 @@ fn initHeaders(
3643 const expected_nodes_len = @as(usize, if (is_archive) 3 else 0) + // .archive, .archive_header, .archive_elf_member_header4098 const expected_nodes_len = @as(usize, if (is_archive) 3 else 0) + // .archive, .archive_header, .archive_elf_member_header
3644 3 + // `.elf`, `.ehdr`, and `.shdr` nodes4099 3 + // `.elf`, `.ehdr`, and `.shdr` nodes
3645 (shnum - 1) + // -1 because the SHN_UNDEF shdr does not have a `.section` node4100 (shnum - 1) + // -1 because the SHN_UNDEF shdr does not have a `.section` node
3646 (phnum -| 1); // -1 because the GNU_STACK phdr does not have a `.segment` node4101 (phnum -| 1) + // -1 because the GNU_STACK phdr does not have a `.segment` node
4102 @intFromBool(have_eh_frame and @"type" != .REL); // eh_frame_footer
36474103
3648 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);4104 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
3649 try elf.shdrs.ensureTotalCapacity(gpa, shnum - 1); // -1 to exclude SHN_UNDEF4105 try elf.shdrs.ensureTotalCapacity(gpa, shnum - 1); // -1 to exclude SHN_UNDEF
...@@ -3652,21 +4108,21 @@ fn initHeaders(...@@ -3652,21 +4108,21 @@ fn initHeaders(
3652 try elf.symtab.ensureTotalCapacity(gpa, 1);4108 try elf.symtab.ensureTotalCapacity(gpa, 1);
36534109
3654 if (is_archive) {4110 if (is_archive) {
3655 elf.nodes.appendAssumeCapacity(.archive);4111 const archive_ni = elf.addNodeAssumeCapacity(.root, .archive);
36564112
3657 const archive_ni: MappedFile.Node.Index = .root;4113 const archive_header_ni = elf.addNodeAssumeCapacity(
36584114 try archive_ni.addOnlyHeaderChild(gpa, &elf.mf, .{
3659 const archive_header_ni = try archive_ni.addOnlyHeaderChild(&elf.mf, gpa, .{4115 // We intentionally do not set `.alignment = .@"2"` here, because the string table data
3660 // We intentionally do not set `.alignment = .@"2"` here, because the string table data4116 // in this node does not need to have an aligned length. (This node's offset is aligned
3661 // in this node does not need to have an aligned length. (This node's offset is aligned4117 // regardless by virtue of it being a header.)
3662 // regardless by virtue of it being a header.)4118 .size = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr),
3663 .size = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr),4119 // The archive header uses 'next_moved' events to resize the "//" member, so that it
3664 // The archive header uses 'next_moved' events to resize the "//" member, so that it4120 // absorbs all padding between `archive_header_ni` and the actual object file members.
3665 // absorbs all padding between `archive_header_ni` and the actual object file members.4121 .enable_next_moved = true,
3666 .enable_next_moved = true,4122 .next_moved = true,
3667 .next_moved = true,4123 }),
3668 });4124 .archive_header,
3669 elf.nodes.appendAssumeCapacity(.archive_header);4125 );
3670 const archive_header_slice = archive_header_ni.slice(&elf.mf);4126 const archive_header_slice = archive_header_ni.slice(&elf.mf);
3671 @memcpy(archive_header_slice[0..std.elf.ARMAG.len], std.elf.ARMAG);4127 @memcpy(archive_header_slice[0..std.elf.ARMAG.len], std.elf.ARMAG);
3672 const strtab_ar_hdr: *std.elf.ar_hdr = @ptrCast(archive_header_slice[std.elf.ARMAG.len..]);4128 const strtab_ar_hdr: *std.elf.ar_hdr = @ptrCast(archive_header_slice[std.elf.ARMAG.len..]);
...@@ -3680,18 +4136,19 @@ fn initHeaders(...@@ -3680,18 +4136,19 @@ fn initHeaders(
3680 .ar_fmag = std.elf.ARFMAG.*,4136 .ar_fmag = std.elf.ARFMAG.*,
3681 };4137 };
36824138
3683 elf.ni.elf = try archive_ni.addOnlyFooterChild(&elf.mf, gpa, .{4139 elf.ni.elf = elf.addNodeAssumeCapacity(try archive_ni.addOnlyFooterChild(gpa, &elf.mf, .{
3684 .alignment = node_block_align.max(.@"2"),4140 .alignment = node_block_align.max(.@"2"),
3685 .bubbles_moved = false,4141 .bubbles_moved = false,
3686 .resized = true, // ensure that this node's `ar_hdr.ar_size` is updated at least once4142 .resized = true, // ensure that this node's `ar_hdr.ar_size` is updated at least once
3687 });4143 }), .elf);
3688 elf.nodes.appendAssumeCapacity(.elf);
36894144
3690 const elf_ar_hdr_ni = try archive_ni.addFooterChildBefore(&elf.mf, gpa, .wrap(elf.ni.elf), .{4145 const elf_ar_hdr_ni = elf.addNodeAssumeCapacity(
3691 .alignment = .@"2",4146 try archive_ni.addFooterChildBefore(gpa, &elf.mf, .wrap(elf.ni.elf), .{
3692 .size = @sizeOf(std.elf.ar_hdr),4147 .alignment = .@"2",
3693 });4148 .size = @sizeOf(std.elf.ar_hdr),
3694 elf.nodes.appendAssumeCapacity(.archive_elf_member_header);4149 }),
4150 .archive_elf_member_header,
4151 );
36954152
3696 // Must be populated before we call `populateArchiveMemberName` below.4153 // Must be populated before we call `populateArchiveMemberName` below.
3697 elf.archive = .{4154 elf.archive = .{
...@@ -3717,10 +4174,7 @@ fn initHeaders(...@@ -3717,10 +4174,7 @@ fn initHeaders(
3717 defer gpa.free(zcu_member_name);4174 defer gpa.free(zcu_member_name);
3718 // After this call returns, `elf_ar_hdr` is invalidated.4175 // After this call returns, `elf_ar_hdr` is invalidated.
3719 try elf.populateArchiveMemberName(elf_ar_hdr, zcu_member_name);4176 try elf.populateArchiveMemberName(elf_ar_hdr, zcu_member_name);
3720 } else {4177 } else elf.ni.elf = elf.addNodeAssumeCapacity(.root, .elf);
3721 elf.ni.elf = .root;
3722 elf.nodes.appendAssumeCapacity(.elf);
3723 }
37244178
3725 const entsize: struct { ph: u32, sh: u32 } = switch (class) {4179 const entsize: struct { ph: u32, sh: u32 } = switch (class) {
3726 .NONE, _ => unreachable,4180 .NONE, _ => unreachable,
...@@ -3736,69 +4190,65 @@ fn initHeaders(...@@ -3736,69 +4190,65 @@ fn initHeaders(
3736 if (@"type" != .REL) {4190 if (@"type" != .REL) {
3737 // This node will contain the ehdr, which must be at the start of the ELF file, so this4191 // This node will contain the ehdr, which must be at the start of the ELF file, so this
3738 // node must itself be a header of the `.elf` node.4192 // node must itself be a header of the `.elf` node.
3739 elf.ni.rodata = try elf.ni.elf.addOnlyHeaderChild(&elf.mf, gpa, .{4193 elf.ni.rodata = elf.addNodeAssumeCapacity(try elf.ni.elf.addOnlyHeaderChild(gpa, &elf.mf, .{
3740 // Must be at least `addr_align` for `elf.ni.phdr` to be placed inside this node4194 // Must be at least `addr_align` for `elf.ni.phdr` to be placed inside this node
3741 .alignment = node_block_align.max(addr_align),4195 .alignment = node_block_align.max(addr_align),
3742 .moved = true,4196 .moved = true,
3743 .bubbles_moved = false,4197 .bubbles_moved = false,
3744 });4198 }), .{ .segment = phndx.rodata });
3745 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.rodata });
3746 elf.phdrs.items[phndx.rodata] = .wrap(elf.ni.rodata);4199 elf.phdrs.items[phndx.rodata] = .wrap(elf.ni.rodata);
37474200
3748 elf.ni.phdr = try elf.ni.rodata.addFloatingChild(&elf.mf, gpa, .{4201 elf.ni.phdr = elf.addNodeAssumeCapacity(try elf.ni.rodata.addFloatingChild(gpa, &elf.mf, .{
3749 .size = @as(u64, phnum) * entsize.ph,4202 .size = @as(u64, phnum) * entsize.ph,
3750 .alignment = addr_align, // keep in sync with `elf.ni.rodata` alignment above4203 .alignment = addr_align, // keep in sync with `elf.ni.rodata` alignment above
3751 .moved = true,4204 .moved = true,
3752 .resized = true,4205 .resized = true,
3753 .bubbles_moved = false,4206 .bubbles_moved = false,
3754 });4207 }), .{ .segment = phndx.phdr });
3755 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.phdr });
3756 elf.phdrs.items[phndx.phdr] = .wrap(elf.ni.phdr);4208 elf.phdrs.items[phndx.phdr] = .wrap(elf.ni.phdr);
37574209
3758 elf.ni.text = try elf.ni.elf.addFloatingChild(&elf.mf, gpa, .{4210 elf.ni.text = elf.addNodeAssumeCapacity(try elf.ni.elf.addFloatingChild(gpa, &elf.mf, .{
3759 .alignment = node_block_align,4211 .alignment = node_block_align,
3760 .moved = true,4212 .moved = true,
3761 .bubbles_moved = false,4213 .bubbles_moved = false,
3762 });4214 }), .{ .segment = phndx.text });
3763 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.text });
3764 elf.phdrs.items[phndx.text] = .wrap(elf.ni.text);4215 elf.phdrs.items[phndx.text] = .wrap(elf.ni.text);
37654216
3766 elf.ni.data = try elf.ni.elf.addFloatingChild(&elf.mf, gpa, .{4217 elf.ni.data = elf.addNodeAssumeCapacity(try elf.ni.elf.addFloatingChild(gpa, &elf.mf, .{
3767 // Must be at least `addr_align` for `elf.ni.data_rel_ro` to be placed inside this node4218 // Must be at least `addr_align` for `elf.ni.data_rel_ro` to be placed inside this node
3768 .alignment = node_block_align.max(addr_align),4219 .alignment = node_block_align.max(addr_align),
3769 .moved = true,4220 .moved = true,
3770 .bubbles_moved = false,4221 .bubbles_moved = false,
3771 });4222 }), .{ .segment = phndx.data });
3772 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.data });
3773 elf.phdrs.items[phndx.data] = .wrap(elf.ni.data);4223 elf.phdrs.items[phndx.data] = .wrap(elf.ni.data);
37744224
3775 if (plt.got_plt == null) {4225 if (plt.got_plt == null) elf.phdrs.items[phndx.plt] = .wrap(elf.addNodeAssumeCapacity(
3776 const plt_ni = try elf.ni.elf.addFloatingChild(&elf.mf, gpa, .{4226 try elf.ni.elf.addFloatingChild(gpa, &elf.mf, .{
3777 .alignment = node_block_align,4227 .alignment = node_block_align,
3778 .moved = true,4228 .moved = true,
3779 .bubbles_moved = false,4229 .bubbles_moved = false,
3780 });4230 }),
3781 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.plt });4231 .{ .segment = phndx.plt },
3782 elf.phdrs.items[phndx.plt] = .wrap(plt_ni);4232 ));
3783 }
37844233
3785 elf.ni.data_rel_ro = try elf.ni.data.addFloatingChild(&elf.mf, gpa, .{4234 elf.ni.data_rel_ro = elf.addNodeAssumeCapacity(try elf.ni.data.addFloatingChild(gpa, &elf.mf, .{
3786 // Must be at least `addr_align` for the `PT_DYNAMIC` node to be placed inside this one4235 // Must be at least `addr_align` for the `PT_DYNAMIC` node to be placed inside this one
3787 // later (if `have_dynamic_section`). Keep in sync with `elf.ni.data` alignment above.4236 // later (if `have_dynamic_section`). Keep in sync with `elf.ni.data` alignment above.
3788 .alignment = node_block_align.max(addr_align),4237 .alignment = node_block_align.max(addr_align),
3789 .moved = true,4238 .moved = true,
3790 .bubbles_moved = false,4239 .bubbles_moved = false,
3791 });4240 }), .{ .segment = phndx.relro });
3792 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.relro });
3793 elf.phdrs.items[phndx.relro] = .wrap(elf.ni.data_rel_ro);4241 elf.phdrs.items[phndx.relro] = .wrap(elf.ni.data_rel_ro);
37944242
3795 if (comp.config.any_non_single_threaded) {4243 if (comp.config.any_non_single_threaded) {
3796 elf.ni.tls = .wrap(try elf.ni.rodata.addFloatingChild(&elf.mf, gpa, .{4244 elf.ni.tls = .wrap(elf.addNodeAssumeCapacity(
3797 .alignment = node_block_align,4245 try elf.ni.rodata.addFloatingChild(gpa, &elf.mf, .{
3798 .moved = true,4246 .alignment = node_block_align,
3799 .bubbles_moved = false,4247 .moved = true,
3800 }));4248 .bubbles_moved = false,
3801 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.tls });4249 }),
4250 .{ .segment = phndx.tls },
4251 ));
3802 elf.phdrs.items[phndx.tls] = elf.ni.tls;4252 elf.phdrs.items[phndx.tls] = elf.ni.tls;
3803 }4253 }
38044254
...@@ -3822,11 +4272,10 @@ fn initHeaders(...@@ -3822,11 +4272,10 @@ fn initHeaders(
3822 .REL => elf.ni.elf,4272 .REL => elf.ni.elf,
3823 .DYN, .EXEC => elf.ni.rodata,4273 .DYN, .EXEC => elf.ni.rodata,
3824 };4274 };
3825 elf.ni.ehdr = try parent_ni.addOnlyHeaderChild(&elf.mf, gpa, .{4275 elf.ni.ehdr = elf.addNodeAssumeCapacity(try parent_ni.addOnlyHeaderChild(gpa, &elf.mf, .{
3826 .size = @sizeOf(ElfN.Ehdr),4276 .size = @sizeOf(ElfN.Ehdr),
3827 .alignment = addr_align,4277 .alignment = addr_align,
3828 });4278 }), .ehdr);
3829 elf.nodes.appendAssumeCapacity(.ehdr);
38304279
3831 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf)));4280 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf)));
3832 ehdr.ident = .{4281 ehdr.ident = .{
...@@ -3872,17 +4321,16 @@ fn initHeaders(...@@ -3872,17 +4321,16 @@ fn initHeaders(
3872 ehdr.shentsize = @sizeOf(ElfN.Shdr);4321 ehdr.shentsize = @sizeOf(ElfN.Shdr);
3873 ehdr.shnum = 1; // Only the SHN_UNDEF shdr initially---will be incremented by `addSection`4322 ehdr.shnum = 1; // Only the SHN_UNDEF shdr initially---will be incremented by `addSection`
3874 ehdr.shstrndx = std.elf.SHN_UNDEF;4323 ehdr.shstrndx = std.elf.SHN_UNDEF;
3875 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);4324 if (elf.targetEndian() != std.lang.Endian.native) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);
3876 },4325 },
3877 }4326 }
38784327
3879 elf.ni.shdr = try elf.ni.elf.addFloatingChild(&elf.mf, gpa, .{4328 elf.ni.shdr = elf.addNodeAssumeCapacity(try elf.ni.elf.addFloatingChild(gpa, &elf.mf, .{
3880 .size = node_block_align.forward(1 * entsize.sh), // as above, only the SHN_UNDEF initially4329 .size = 1 * entsize.sh, // as above, only the null shdr initially
3881 .alignment = addr_align.max(node_block_align),4330 .alignment = addr_align,
3882 .moved = true,4331 .moved = true,
3883 .resized = true,4332 .resized = true,
3884 });4333 }), .shdr);
3885 elf.nodes.appendAssumeCapacity(.shdr);
38864334
3887 switch (class) {4335 switch (class) {
3888 .NONE, _ => unreachable,4336 .NONE, _ => unreachable,
...@@ -3925,8 +4373,7 @@ fn initHeaders(...@@ -3925,8 +4373,7 @@ fn initHeaders(
3925 elf.ni.phdr.slice(&elf.mf)[0 .. phnum * @sizeOf(ElfN.Phdr)],4373 elf.ni.phdr.slice(&elf.mf)[0 .. phnum * @sizeOf(ElfN.Phdr)],
3926 ));4374 ));
39274375
3928 const ph_phdr = &phdr[phndx.phdr];4376 phdr[phndx.phdr] = .{
3929 ph_phdr.* = .{
3930 .type = .PHDR,4377 .type = .PHDR,
3931 .offset = 0,4378 .offset = 0,
3932 .vaddr = 0,4379 .vaddr = 0,
...@@ -3937,22 +4384,18 @@ fn initHeaders(...@@ -3937,22 +4384,18 @@ fn initHeaders(
3937 .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()),4384 .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()),
3938 };4385 };
39394386
3940 if (maybe_interp) |_| {4387 if (maybe_interp) |_| phdr[phndx.interp] = .{
3941 const ph_interp = &phdr[phndx.interp];4388 .type = .INTERP,
3942 ph_interp.* = .{4389 .offset = 0,
3943 .type = .INTERP,4390 .vaddr = 0,
3944 .offset = 0,4391 .paddr = 0,
3945 .vaddr = 0,4392 .filesz = 0,
3946 .paddr = 0,4393 .memsz = 0,
3947 .filesz = 0,4394 .flags = .{ .R = true },
3948 .memsz = 0,4395 .@"align" = 1,
3949 .flags = .{ .R = true },4396 };
3950 .@"align" = 1,
3951 };
3952 }
39534397
3954 const ph_rodata = &phdr[phndx.rodata];4398 phdr[phndx.rodata] = .{
3955 ph_rodata.* = .{
3956 .type = .NULL,4399 .type = .NULL,
3957 .offset = 0,4400 .offset = 0,
3958 .vaddr = @intCast(base_vaddr),4401 .vaddr = @intCast(base_vaddr),
...@@ -3963,8 +4406,7 @@ fn initHeaders(...@@ -3963,8 +4406,7 @@ fn initHeaders(
3963 .@"align" = @intCast(page_align.toByteUnits()),4406 .@"align" = @intCast(page_align.toByteUnits()),
3964 };4407 };
39654408
3966 const ph_text = &phdr[phndx.text];4409 phdr[phndx.text] = .{
3967 ph_text.* = .{
3968 .type = .NULL,4410 .type = .NULL,
3969 .offset = 0,4411 .offset = 0,
3970 .vaddr = @intCast(base_vaddr),4412 .vaddr = @intCast(base_vaddr),
...@@ -3975,8 +4417,7 @@ fn initHeaders(...@@ -3975,8 +4417,7 @@ fn initHeaders(
3975 .@"align" = @intCast(page_align.toByteUnits()),4417 .@"align" = @intCast(page_align.toByteUnits()),
3976 };4418 };
39774419
3978 const ph_data = &phdr[phndx.data];4420 phdr[phndx.data] = .{
3979 ph_data.* = .{
3980 .type = .NULL,4421 .type = .NULL,
3981 .offset = 0,4422 .offset = 0,
3982 .vaddr = @intCast(base_vaddr),4423 .vaddr = @intCast(base_vaddr),
...@@ -3987,50 +4428,40 @@ fn initHeaders(...@@ -3987,50 +4428,40 @@ fn initHeaders(
3987 .@"align" = @intCast(page_align.toByteUnits()),4428 .@"align" = @intCast(page_align.toByteUnits()),
3988 };4429 };
39894430
3990 if (plt.got_plt == null) {4431 if (plt.got_plt == null) phdr[phndx.plt] = .{
3991 const ph_plt = &phdr[phndx.plt];4432 .type = .NULL,
3992 ph_plt.* = .{4433 .offset = 0,
3993 .type = .NULL,4434 .vaddr = @intCast(base_vaddr),
3994 .offset = 0,4435 .paddr = @intCast(base_vaddr),
3995 .vaddr = @intCast(base_vaddr),4436 .filesz = 0,
3996 .paddr = @intCast(base_vaddr),4437 .memsz = 0,
3997 .filesz = 0,4438 .flags = .{ .R = true, .W = true, .X = true },
3998 .memsz = 0,4439 .@"align" = @intCast(page_align.toByteUnits()),
3999 .flags = .{ .R = true, .W = true, .X = true },4440 };
4000 .@"align" = @intCast(page_align.toByteUnits()),
4001 };
4002 }
40034441
4004 if (elf.ni.tls.unwrap()) |tls_segment_ni| {4442 if (elf.ni.tls.unwrap()) |tls_segment_ni| phdr[phndx.tls] = .{
4005 const ph_tls = &phdr[phndx.tls];4443 .type = .TLS,
4006 ph_tls.* = .{4444 .offset = 0,
4007 .type = .TLS,4445 .vaddr = 0,
4008 .offset = 0,4446 .paddr = 0,
4009 .vaddr = 0,4447 .filesz = 0,
4010 .paddr = 0,4448 .memsz = 0,
4011 .filesz = 0,4449 .flags = .{ .R = true },
4012 .memsz = 0,4450 .@"align" = @intCast(tls_segment_ni.alignment(&elf.mf).toByteUnits()),
4013 .flags = .{ .R = true },4451 };
4014 .@"align" = @intCast(tls_segment_ni.alignment(&elf.mf).toByteUnits()),
4015 };
4016 }
40174452
4018 if (have_dynamic_section) {4453 if (have_dynamic) phdr[phndx.dynamic] = .{
4019 const ph_dynamic = &phdr[phndx.dynamic];4454 .type = .DYNAMIC,
4020 ph_dynamic.* = .{4455 .offset = 0,
4021 .type = .DYNAMIC,4456 .vaddr = 0,
4022 .offset = 0,4457 .paddr = 0,
4023 .vaddr = 0,4458 .filesz = 0,
4024 .paddr = 0,4459 .memsz = 0,
4025 .filesz = 0,4460 .flags = .{ .R = true, .W = true },
4026 .memsz = 0,4461 .@"align" = @intCast(addr_align.toByteUnits()),
4027 .flags = .{ .R = true, .W = true },4462 };
4028 .@"align" = @intCast(addr_align.toByteUnits()),
4029 };
4030 }
40314463
4032 const ph_relro = &phdr[phndx.relro];4464 phdr[phndx.relro] = .{
4033 ph_relro.* = .{
4034 .type = .GNU_RELRO,4465 .type = .GNU_RELRO,
4035 .offset = 0,4466 .offset = 0,
4036 .vaddr = 0,4467 .vaddr = 0,
...@@ -4041,8 +4472,18 @@ fn initHeaders(...@@ -4041,8 +4472,18 @@ fn initHeaders(
4041 .@"align" = @intCast(elf.ni.data_rel_ro.alignment(&elf.mf).toByteUnits()),4472 .@"align" = @intCast(elf.ni.data_rel_ro.alignment(&elf.mf).toByteUnits()),
4042 };4473 };
40434474
4044 const ph_gnu_stack = &phdr[phndx.gnu_stack];4475 if (have_eh_frame) phdr[phndx.gnu_eh_frame] = .{
4045 ph_gnu_stack.* = .{4476 .type = .GNU_EH_FRAME,
4477 .offset = 0,
4478 .vaddr = 0,
4479 .paddr = 0,
4480 .filesz = @sizeOf(Dwarf.EhFrameHdr),
4481 .memsz = @sizeOf(Dwarf.EhFrameHdr),
4482 .flags = .{ .R = true },
4483 .@"align" = 4,
4484 };
4485
4486 phdr[phndx.gnu_stack] = .{
4046 .type = .GNU_STACK,4487 .type = .GNU_STACK,
4047 .offset = 0,4488 .offset = 0,
4048 .vaddr = 0,4489 .vaddr = 0,
...@@ -4071,7 +4512,7 @@ fn initHeaders(...@@ -4071,7 +4512,7 @@ fn initHeaders(
4071 .addralign = 0,4512 .addralign = 0,
4072 .entsize = 0,4513 .entsize = 0,
4073 };4514 };
4074 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);4515 if (target_endian != std.lang.Endian.native) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);
40754516
4076 elf.symtab.addOneAssumeCapacity().* = .{4517 elf.symtab.addOneAssumeCapacity().* = .{
4077 .node = .none,4518 .node = .none,
...@@ -4084,6 +4525,7 @@ fn initHeaders(...@@ -4084,6 +4525,7 @@ fn initHeaders(
4084 .entsize = @sizeOf(ElfN.Sym),4525 .entsize = @sizeOf(ElfN.Sym),
4085 .node_align = node_block_align,4526 .node_align = node_block_align,
4086 .info = 1, // index of first non-local symbol4527 .info = 1, // index of first non-local symbol
4528 .manual_size = true,
4087 }));4529 }));
4088 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));4530 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
4089 symtab_null.* = .{4531 symtab_null.* = .{
...@@ -4094,7 +4536,7 @@ fn initHeaders(...@@ -4094,7 +4536,7 @@ fn initHeaders(
4094 .other = .{ .visibility = .DEFAULT },4536 .other = .{ .visibility = .DEFAULT },
4095 .shndx = std.elf.SHN_UNDEF,4537 .shndx = std.elf.SHN_UNDEF,
4096 };4538 };
4097 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);4539 if (target_endian != std.lang.Endian.native) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);
40984540
4099 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));4541 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));
4100 ehdr.shstrndx = ehdr.shnum;4542 ehdr.shstrndx = ehdr.shnum;
...@@ -4105,6 +4547,7 @@ fn initHeaders(...@@ -4105,6 +4547,7 @@ fn initHeaders(
4105 .size = 1,4547 .size = 1,
4106 .entsize = 1,4548 .entsize = 1,
4107 .node_align = node_block_align,4549 .node_align = node_block_align,
4550 .manual_size = true,
4108 }));4551 }));
4109 Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0;4552 Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0;
41104553
...@@ -4117,6 +4560,7 @@ fn initHeaders(...@@ -4117,6 +4560,7 @@ fn initHeaders(
4117 .size = 1,4560 .size = 1,
4118 .entsize = 1,4561 .entsize = 1,
4119 .node_align = node_block_align,4562 .node_align = node_block_align,
4563 .manual_size = true,
4120 }));4564 }));
4121 Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0;4565 Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0;
4122 switch (elf.shdrPtr(.symtab)) {4566 switch (elf.shdrPtr(.symtab)) {
...@@ -4156,6 +4600,7 @@ fn initHeaders(...@@ -4156,6 +4600,7 @@ fn initHeaders(
4156 .flags = .{ .WRITE = true, .ALLOC = true },4600 .flags = .{ .WRITE = true, .ALLOC = true },
4157 .addralign = addr_align,4601 .addralign = addr_align,
4158 .entsize = @intCast(addr_align.toByteUnits()),4602 .entsize = @intCast(addr_align.toByteUnits()),
4603 .manual_size = true,
4159 });4604 });
4160 {4605 {
4161 const init_plt_size = plt.entry_size * plt.header_entries;4606 const init_plt_size = plt.entry_size * plt.header_entries;
...@@ -4168,6 +4613,7 @@ fn initHeaders(...@@ -4168,6 +4613,7 @@ fn initHeaders(
4168 .size = got_plt.header_entries * elf.targetPtrSize(),4613 .size = got_plt.header_entries * elf.targetPtrSize(),
4169 .addralign = addr_align,4614 .addralign = addr_align,
4170 .entsize = @intCast(addr_align.toByteUnits()),4615 .entsize = @intCast(addr_align.toByteUnits()),
4616 .manual_size = true,
4171 });4617 });
4172 elf.shndx.plt = try elf.addSection(elf.ni.text, .{4618 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
4173 .name = ".plt",4619 .name = ".plt",
...@@ -4176,6 +4622,7 @@ fn initHeaders(...@@ -4176,6 +4622,7 @@ fn initHeaders(
4176 .size = plt.@"align".forward(init_plt_size),4622 .size = plt.@"align".forward(init_plt_size),
4177 .addralign = plt.@"align",4623 .addralign = plt.@"align",
4178 .node_align = node_block_align,4624 .node_align = node_block_align,
4625 .manual_size = true,
4179 });4626 });
4180 } else {4627 } else {
4181 elf.shndx.plt = try elf.addSection(elf.phdrs.items[phndx.plt].unwrap().?, .{4628 elf.shndx.plt = try elf.addSection(elf.phdrs.items[phndx.plt].unwrap().?, .{
...@@ -4185,6 +4632,7 @@ fn initHeaders(...@@ -4185,6 +4632,7 @@ fn initHeaders(
4185 .size = plt.@"align".forward(init_plt_size),4632 .size = plt.@"align".forward(init_plt_size),
4186 .addralign = plt.@"align",4633 .addralign = plt.@"align",
4187 .node_align = node_block_align,4634 .node_align = node_block_align,
4635 .manual_size = true,
4188 });4636 });
4189 }4637 }
4190 // And the award for most annoying PLT requirement goes to SPARC, which decided that the4638 // And the award for most annoying PLT requirement goes to SPARC, which decided that the
...@@ -4203,13 +4651,15 @@ fn initHeaders(...@@ -4203,13 +4651,15 @@ fn initHeaders(
4203 .node_align = node_block_align,4651 .node_align = node_block_align,
4204 });4652 });
4205 if (maybe_interp) |interp| {4653 if (maybe_interp) |interp| {
4206 const interp_ni = try elf.ni.rodata.addFloatingChild(&elf.mf, gpa, .{4654 const interp_ni = elf.addNodeAssumeCapacity(
4207 .size = interp.len + 1,4655 try elf.ni.rodata.addFloatingChild(gpa, &elf.mf, .{
4208 .moved = true,4656 .size = interp.len + 1,
4209 .resized = true,4657 .moved = true,
4210 .bubbles_moved = false,4658 .resized = true,
4211 });4659 .bubbles_moved = false,
4212 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.interp });4660 }),
4661 .{ .segment = phndx.interp },
4662 );
4213 elf.phdrs.items[phndx.interp] = .wrap(interp_ni);4663 elf.phdrs.items[phndx.interp] = .wrap(interp_ni);
42144664
4215 const sec_interp_shndx = try elf.addSection(interp_ni, .{4665 const sec_interp_shndx = try elf.addSection(interp_ni, .{
...@@ -4222,14 +4672,16 @@ fn initHeaders(...@@ -4222,14 +4672,16 @@ fn initHeaders(
4222 @memcpy(sec_interp[0..interp.len], interp);4672 @memcpy(sec_interp[0..interp.len], interp);
4223 sec_interp[interp.len] = 0;4673 sec_interp[interp.len] = 0;
4224 }4674 }
4225 if (have_dynamic_section) {4675 if (have_dynamic) {
4226 assert(elf.ni.data_rel_ro.alignment(&elf.mf).compare(.gte, addr_align));4676 assert(elf.ni.data_rel_ro.alignment(&elf.mf).compare(.gte, addr_align));
4227 const dynamic_ni = try elf.ni.data_rel_ro.addFloatingChild(&elf.mf, gpa, .{4677 const dynamic_ni = elf.addNodeAssumeCapacity(
4228 .alignment = addr_align,4678 try elf.ni.data_rel_ro.addFloatingChild(gpa, &elf.mf, .{
4229 .moved = true,4679 .alignment = addr_align,
4230 .bubbles_moved = false,4680 .moved = true,
4231 });4681 .bubbles_moved = false,
4232 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.dynamic });4682 }),
4683 .{ .segment = phndx.dynamic },
4684 );
4233 elf.phdrs.items[phndx.dynamic] = .wrap(dynamic_ni);4685 elf.phdrs.items[phndx.dynamic] = .wrap(dynamic_ni);
42344686
4235 const dynstr_shndx = try elf.addSection(elf.ni.rodata, .{4687 const dynstr_shndx = try elf.addSection(elf.ni.rodata, .{
...@@ -4239,6 +4691,7 @@ fn initHeaders(...@@ -4239,6 +4691,7 @@ fn initHeaders(
4239 .size = 1,4691 .size = 1,
4240 .entsize = 1,4692 .entsize = 1,
4241 .node_align = node_block_align,4693 .node_align = node_block_align,
4694 .manual_size = true,
4242 });4695 });
4243 dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0;4696 dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0;
4244 elf.shndx.dynstr = dynstr_shndx;4697 elf.shndx.dynstr = dynstr_shndx;
...@@ -4257,6 +4710,7 @@ fn initHeaders(...@@ -4257,6 +4710,7 @@ fn initHeaders(
4257 .addralign = addr_align,4710 .addralign = addr_align,
4258 .entsize = @sizeOf(Sym),4711 .entsize = @sizeOf(Sym),
4259 .node_align = node_block_align,4712 .node_align = node_block_align,
4713 .manual_size = true,
4260 });4714 });
4261 const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class));4715 const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class));
4262 dynsym_null.* = .{4716 dynsym_null.* = .{
...@@ -4267,7 +4721,7 @@ fn initHeaders(...@@ -4267,7 +4721,7 @@ fn initHeaders(
4267 .other = .{ .visibility = .DEFAULT },4721 .other = .{ .visibility = .DEFAULT },
4268 .shndx = std.elf.SHN_UNDEF,4722 .shndx = std.elf.SHN_UNDEF,
4269 };4723 };
4270 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(4724 if (elf.targetEndian() != std.lang.Endian.native) std.mem.byteSwapAllFields(
4271 Sym,4725 Sym,
4272 dynsym_null,4726 dynsym_null,
4273 );4727 );
...@@ -4285,6 +4739,7 @@ fn initHeaders(...@@ -4285,6 +4739,7 @@ fn initHeaders(
4285 .addralign = addr_align,4739 .addralign = addr_align,
4286 .entsize = rela_size,4740 .entsize = rela_size,
4287 .node_align = node_block_align,4741 .node_align = node_block_align,
4742 .manual_size = true,
4288 });4743 });
4289 elf.shndx.rela_plt = try elf.addSection(elf.ni.rodata, .{4744 elf.shndx.rela_plt = try elf.addSection(elf.ni.rodata, .{
4290 .name = ".rela.plt",4745 .name = ".rela.plt",
...@@ -4295,6 +4750,7 @@ fn initHeaders(...@@ -4295,6 +4750,7 @@ fn initHeaders(
4295 .addralign = addr_align,4750 .addralign = addr_align,
4296 .entsize = rela_size,4751 .entsize = rela_size,
4297 .node_align = node_block_align,4752 .node_align = node_block_align,
4753 .manual_size = true,
4298 });4754 });
4299 elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{4755 elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{
4300 .name = ".dynamic",4756 .name = ".dynamic",
...@@ -4303,6 +4759,7 @@ fn initHeaders(...@@ -4303,6 +4759,7 @@ fn initHeaders(
4303 .link = dynstr_shndx.toSection().?,4759 .link = dynstr_shndx.toSection().?,
4304 .entsize = @intCast(addr_align.toByteUnits() * 2),4760 .entsize = @intCast(addr_align.toByteUnits() * 2),
4305 .addralign = addr_align,4761 .addralign = addr_align,
4762 .manual_size = true,
4306 });4763 });
4307 switch (elf.targetDynsymHashInfo()) {4764 switch (elf.targetDynsymHashInfo()) {
4308 inline else => |info| {4765 inline else => |info| {
...@@ -4318,6 +4775,7 @@ fn initHeaders(...@@ -4318,6 +4775,7 @@ fn initHeaders(
4318 .addralign = .fromByteUnits(@sizeOf(info.Int())),4775 .addralign = .fromByteUnits(@sizeOf(info.Int())),
4319 // initially: nbucket = 8 + nchain = 14776 // initially: nbucket = 8 + nchain = 1
4320 .size = @sizeOf(info.Header()) + @sizeOf(info.Int()) * (8 + 1),4777 .size = @sizeOf(info.Header()) + @sizeOf(info.Int()) * (8 + 1),
4778 .manual_size = true,
4321 });4779 });
4322 const hash_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf));4780 const hash_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf));
4323 const header: *info.Header() = @ptrCast(hash_slice[0..@sizeOf(info.Header())]);4781 const header: *info.Header() = @ptrCast(hash_slice[0..@sizeOf(info.Header())]);
...@@ -4386,34 +4844,78 @@ fn initHeaders(...@@ -4386,34 +4844,78 @@ fn initHeaders(
4386 elf.plt_first_symbol_reloc = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));4844 elf.plt_first_symbol_reloc = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
4387 try elf.ensureUnusedRelocCapacity(plt_ni, 3);4845 try elf.ensureUnusedRelocCapacity(plt_ni, 3);
4388 elf.addRelocAssumeCapacity(plt_ni, 0, got_plt_sym, 0, .{ .LARCH = .PCALA_HI20 }) catch |err| switch (err) {4846 elf.addRelocAssumeCapacity(plt_ni, 0, got_plt_sym, 0, .{ .LARCH = .PCALA_HI20 }) catch |err| switch (err) {
4847 else => |e| return e,
4389 error.UnknownRelocation => unreachable,4848 error.UnknownRelocation => unreachable,
4390 error.NonStaticRelocation => unreachable,4849 error.NonStaticRelocation => unreachable,
4391 error.UnimplementedRelocation => unreachable,4850 error.UnimplementedRelocation => unreachable,
4392 else => |e| return e,
4393 };4851 };
4394 elf.addRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .{ .LARCH = .PCALA_LO12 }) catch |err| switch (err) {4852 elf.addRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .{ .LARCH = .PCALA_LO12 }) catch |err| switch (err) {
4853 else => |e| return e,
4395 error.UnknownRelocation => unreachable,4854 error.UnknownRelocation => unreachable,
4396 error.NonStaticRelocation => unreachable,4855 error.NonStaticRelocation => unreachable,
4397 error.UnimplementedRelocation => unreachable,4856 error.UnimplementedRelocation => unreachable,
4398 else => |e| return e,
4399 };4857 };
4400 elf.addRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .{ .LARCH = .PCALA_LO12 }) catch |err| switch (err) {4858 elf.addRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .{ .LARCH = .PCALA_LO12 }) catch |err| switch (err) {
4859 else => |e| return e,
4401 error.UnknownRelocation => unreachable,4860 error.UnknownRelocation => unreachable,
4402 error.NonStaticRelocation => unreachable,4861 error.NonStaticRelocation => unreachable,
4403 error.UnimplementedRelocation => unreachable,4862 error.UnimplementedRelocation => unreachable,
4404 else => |e| return e,
4405 };4863 };
4406 },4864 },
4407 .SPARCV9 => {},4865 .SPARCV9 => {},
4408 }4866 }
4409 }4867 }
4868 if (have_eh_frame) {
4869 const gnu_eh_frame = elf.addNodeAssumeCapacity(
4870 try elf.ni.rodata.addFloatingChild(gpa, &elf.mf, .{
4871 .size = @sizeOf(Dwarf.EhFrameHdr),
4872 .alignment = .@"4",
4873 .moved = true,
4874 .bubbles_moved = false,
4875 }),
4876 .{ .segment = phndx.gnu_eh_frame },
4877 );
4878 elf.ni.gnu_eh_frame = .wrap(gnu_eh_frame);
4879 elf.phdrs.items[phndx.gnu_eh_frame] = elf.ni.gnu_eh_frame;
4880
4881 elf.shndx.eh_frame_hdr = try elf.addSection(gnu_eh_frame, .{
4882 .name = ".eh_frame_hdr",
4883 .type = .PROGBITS,
4884 .flags = .{ .ALLOC = true },
4885 .size = @sizeOf(Dwarf.EhFrameHdr),
4886 .addralign = .@"4",
4887 });
4888 elf.shndx.eh_frame = try elf.addSection(elf.ni.rodata, .{
4889 .name = ".eh_frame",
4890 .flags = .{ .ALLOC = true },
4891 .addralign = addr_align,
4892 .node_align = elf.mf.flags.block_size,
4893 .manual_size = true,
4894 });
4895
4896 const eh_frame_hdr_ni = elf.shndx.eh_frame_hdr.get(elf).ni;
4897 elf.eh_frame_hdr_first_symbol_reloc =
4898 @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
4899 try elf.dwarf.genEhFrameHdr(
4900 Node.toAtom(eh_frame_hdr_ni),
4901 @ptrCast(@alignCast(eh_frame_hdr_ni.slice(&elf.mf))),
4902 Symbol.Id.local(elf.shndx.eh_frame.get(elf).lsi).toTypeErased(),
4903 );
4904 _ = elf.addNodeAssumeCapacity(
4905 try elf.shndx.eh_frame.get(elf).ni.addOnlyFooterChild(gpa, &elf.mf, .{
4906 .size = addr_align.forward(4),
4907 .alignment = addr_align,
4908 }),
4909 .eh_frame_footer,
4910 );
4911 }
44104912
4411 // Populate reserved GOT words.4913 // Populate reserved GOT words.
4412 switch (machine) {4914 switch (machine) {
4413 .AARCH64, .PPC64, .RISCV => @panic(@tagName(machine)),4915 .AARCH64, .PPC64, .RISCV => @panic(@tagName(machine)),
4414 .X86_64 => {4916 .X86_64 => {
4415 try elf.got.ensureUnusedCapacity(gpa, 3);4917 try elf.got.ensureUnusedCapacity(gpa, 3);
4416 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) {4918 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic) {
4417 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },4919 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },
4418 false => .{ .reserved = 0 },4920 false => .{ .reserved = 0 },
4419 }, .none);4921 }, .none);
...@@ -4422,7 +4924,7 @@ fn initHeaders(...@@ -4422,7 +4924,7 @@ fn initHeaders(
4422 },4924 },
4423 .LOONGARCH, .SPARCV9 => {4925 .LOONGARCH, .SPARCV9 => {
4424 try elf.got.ensureUnusedCapacity(gpa, 1);4926 try elf.got.ensureUnusedCapacity(gpa, 1);
4425 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) {4927 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic) {
4426 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },4928 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },
4427 false => .{ .reserved = 0 },4929 false => .{ .reserved = 0 },
4428 }, .none);4930 }, .none);
...@@ -4567,7 +5069,7 @@ fn initHeaders(...@@ -4567,7 +5069,7 @@ fn initHeaders(
4567 }) catch |err| switch (err) {5069 }) catch |err| switch (err) {
4568 error.MultipleDefinitions => unreachable, // no inputs are processed yet5070 error.MultipleDefinitions => unreachable, // no inputs are processed yet
4569 };5071 };
4570 if (have_dynamic_section) {5072 if (have_dynamic) {
4571 _ = elf.addGlobalSymbolAssumeCapacity(.{5073 _ = elf.addGlobalSymbolAssumeCapacity(.{
4572 .node = .wrap(elf.shndx.dynamic.get(elf).ni),5074 .node = .wrap(elf.shndx.dynamic.get(elf).ni),
4573 .name = try .string(elf, "_DYNAMIC"),5075 .name = try .string(elf, "_DYNAMIC"),
...@@ -4583,13 +5085,57 @@ fn initHeaders(...@@ -4583,13 +5085,57 @@ fn initHeaders(
4583 }5085 }
4584 } else {5086 } else {
4585 assert(maybe_interp == null);5087 assert(maybe_interp == null);
4586 assert(!have_dynamic_section);5088 assert(!have_dynamic);
5089 if (have_eh_frame) elf.shndx.eh_frame = try elf.addSection(elf.ni.rodata, .{
5090 .name = ".eh_frame",
5091 .type = if (machine == .X86_64) .X86_64_UNWIND else .NULL,
5092 .flags = .{ .ALLOC = true },
5093 .addralign = addr_align,
5094 .node_align = elf.mf.flags.block_size,
5095 .manual_size = true,
5096 });
4587 }5097 }
4588 if (elf.ni.tls.unwrap()) |tls_segment_ni| elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{5098 if (elf.ni.tls.unwrap()) |tls_segment_ni| elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{
4589 .name = ".tdata",5099 .name = ".tdata",
4590 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },5100 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
4591 .node_align = node_block_align,5101 .node_align = node_block_align,
4592 });5102 });
5103 switch (comp.config.debug_format) {
5104 .strip => {},
5105 .dwarf => {
5106 elf.shndx.debug_abbrev = try elf.addSection(elf.ni.elf, .{ .name = ".debug_abbrev" });
5107 if (have_debug_frame) elf.shndx.debug_frame = try elf.addSection(elf.ni.elf, .{
5108 .name = ".debug_frame",
5109 .addralign = addr_align,
5110 .node_align = elf.mf.flags.block_size,
5111 .manual_size = true,
5112 });
5113 elf.shndx.debug_info = try elf.addSection(elf.ni.elf, .{
5114 .name = ".debug_info",
5115 .node_align = elf.mf.flags.block_size,
5116 });
5117 elf.shndx.debug_line = try elf.addSection(elf.ni.elf, .{
5118 .name = ".debug_line",
5119 .node_align = elf.mf.flags.block_size,
5120 });
5121 elf.shndx.debug_line_str = try elf.addSection(elf.ni.elf, .{
5122 .name = ".debug_line_str",
5123 .flags = .{ .MERGE = true, .STRINGS = true },
5124 });
5125 elf.shndx.debug_rnglists = try elf.addSection(elf.ni.elf, .{
5126 .name = ".debug_rnglists",
5127 .node_align = elf.mf.flags.block_size,
5128 });
5129 elf.shndx.debug_str = try elf.addSection(elf.ni.elf, .{
5130 .name = ".debug_str",
5131 .flags = .{ .MERGE = true, .STRINGS = true },
5132 });
5133 elf.shndx.debug_str_offsets = try elf.addSection(elf.ni.elf, .{
5134 .name = ".debug_str_offsets",
5135 });
5136 },
5137 .code_view => unreachable,
5138 }
45935139
4594 assert(elf.nodes.len == expected_nodes_len);5140 assert(elf.nodes.len == expected_nodes_len);
4595 assert(elf.shdrs.items.len == shnum - 1); // -1 to exclude SHN_UNDEF5141 assert(elf.shdrs.items.len == shnum - 1); // -1 to exclude SHN_UNDEF
...@@ -4599,7 +5145,7 @@ fn initHeaders(...@@ -4599,7 +5145,7 @@ fn initHeaders(
4599 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});5145 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});
4600 }5146 }
46015147
4602 if (have_dynamic_section) elf.dynamic = .{5148 if (have_dynamic) elf.dynamic = .{
4603 .flags = if (elf.options.z_now) std.elf.DF_BIND_NOW else 0,5149 .flags = if (elf.options.z_now) std.elf.DF_BIND_NOW else 0,
4604 .flags_1 = f: {5150 .flags_1 = f: {
4605 var f: u32 = 0;5151 var f: u32 = 0;
...@@ -4642,11 +5188,6 @@ fn initHeaders(...@@ -4642,11 +5188,6 @@ fn initHeaders(
4642pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void {5188pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void {
4643 prog_node.increaseEstimatedTotalItems(4);5189 prog_node.increaseEstimatedTotalItems(4);
4644 elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.items.len);5190 elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.items.len);
4645 elf.synth_prog_node = prog_node.start("Synthetics", count: {
4646 var count: usize = 0;
4647 for (&elf.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index;
4648 break :count count;
4649 });
4650 elf.mf.update_prog_node = prog_node.start("Relocations", elf.mf.updates.items.len);5191 elf.mf.update_prog_node = prog_node.start("Relocations", elf.mf.updates.items.len);
4651 elf.input_prog_node = prog_node.start("Inputs", (elf.inputs.items.len - elf.input_pending_index) +5192 elf.input_prog_node = prog_node.start("Inputs", (elf.inputs.items.len - elf.input_pending_index) +
4652 (elf.input_sections.items.len - elf.input_section_pending_index));5193 (elf.input_sections.items.len - elf.input_section_pending_index));
...@@ -4657,8 +5198,6 @@ pub fn endProgress(elf: *Elf) void {...@@ -4657,8 +5198,6 @@ pub fn endProgress(elf: *Elf) void {
4657 elf.input_prog_node = .none;5198 elf.input_prog_node = .none;
4658 elf.mf.update_prog_node.end();5199 elf.mf.update_prog_node.end();
4659 elf.mf.update_prog_node = .none;5200 elf.mf.update_prog_node = .none;
4660 elf.synth_prog_node.end();
4661 elf.synth_prog_node = .none;
4662 elf.const_prog_node.end();5201 elf.const_prog_node.end();
4663 elf.const_prog_node = .none;5202 elf.const_prog_node = .none;
4664}5203}
...@@ -4669,6 +5208,7 @@ fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {...@@ -4669,6 +5208,7 @@ fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
4669/// Asserts that `ni` is a section, input section, copied global, NAV, UAV, or lazy code/data.5208/// Asserts that `ni` is a section, input section, copied global, NAV, UAV, or lazy code/data.
4670fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index {5209fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index {
4671 return switch (elf.getNode(ni)) {5210 return switch (elf.getNode(ni)) {
5211 .deleted,
4672 .archive,5212 .archive,
4673 .archive_header,5213 .archive_header,
4674 .archive_input_member,5214 .archive_input_member,
...@@ -4678,18 +5218,43 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index {...@@ -4678,18 +5218,43 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index {
4678 .shdr,5218 .shdr,
4679 .segment,5219 .segment,
4680 => unreachable,5220 => unreachable,
4681 .section => |shndx| shndx,5221 .section, .section_manual_size => |shndx| shndx,
4682 .input_section,5222 .input_section,
4683 .copied_global,5223 .copied_global,
4684 .nav,5224 .nav,
4685 .uav,5225 .uav,
4686 .lazy_code,5226 .lazy_code,
4687 .lazy_const_data,5227 .lazy_const_data,
4688 => elf.getNode(ni.parent(&elf.mf).unwrap().?).section,5228 .debug_shared,
5229 .eh_frame_footer,
5230 .unit_padding,
5231 .unit_frame,
5232 .unit_debug_info,
5233 .unit_debug_line,
5234 .unit_debug_rnglists,
5235 => switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {
5236 else => unreachable,
5237 .section, .section_manual_size => |shndx| shndx,
5238 },
5239 .unit_frame_cie,
5240 .unit_debug_info_header,
5241 .unit_debug_info_footer,
5242 .unit_debug_line_header,
5243 .const_debug_info,
5244 .global_debug_info,
5245 .func_frame_fde,
5246 .func_debug_info,
5247 .func_debug_line,
5248 .decl_debug_info,
5249 => switch (elf.getNode(ni.parent(&elf.mf).unwrap().?.parent(&elf.mf).unwrap().?)) {
5250 else => unreachable,
5251 .section, .section_manual_size => |shndx| shndx,
5252 },
4689 };5253 };
4690}5254}
4691fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {5255fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
4692 return switch (elf.getNode(ni)) {5256 return switch (elf.getNode(ni)) {
5257 .deleted,
4693 .archive,5258 .archive,
4694 .archive_header,5259 .archive_header,
4695 .archive_input_member,5260 .archive_input_member,
...@@ -4700,17 +5265,37 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {...@@ -4700,17 +5265,37 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
4700 .segment,5265 .segment,
4701 .copied_global,5266 .copied_global,
4702 => unreachable,5267 => unreachable,
4703 .section => |shndx| shndx.vaddr(elf),5268 .section, .section_manual_size => |shndx| shndx.vaddr(elf),
4704 .input_section => |isi| isi.ptrConst(elf).vaddr,5269 .input_section => |isi| isi.ptrConst(elf).vaddr,
4705 inline .nav,5270 inline .nav,
4706 .uav,5271 .uav,
4707 .lazy_code,5272 .lazy_code,
4708 .lazy_const_data,5273 .lazy_const_data,
4709 => |i| Symbol.Id.local(i.symbol(elf)).value(elf),5274 => |i| Symbol.Id.local(i.symbol(elf)).value(elf),
5275 .debug_shared,
5276 .eh_frame_footer,
5277 .unit_padding,
5278 .unit_frame,
5279 .unit_frame_cie,
5280 .unit_debug_info,
5281 .unit_debug_info_header,
5282 .unit_debug_info_footer,
5283 .unit_debug_line,
5284 .unit_debug_line_header,
5285 .unit_debug_rnglists,
5286 .const_debug_info,
5287 .global_debug_info,
5288 .func_frame_fde,
5289 .func_debug_info,
5290 .func_debug_line,
5291 .decl_debug_info,
5292 => elf.computeNodeVAddr(ni),
4710 };5293 };
4711}5294}
4712fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {5295fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
4713 const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {5296 const parent_ni = ni.parent(&elf.mf).unwrap().?;
5297 const parent_vaddr = parent_vaddr: switch (elf.getNode(parent_ni)) {
5298 .deleted,
4714 .archive,5299 .archive,
4715 .archive_header,5300 .archive_header,
4716 .archive_input_member,5301 .archive_input_member,
...@@ -4721,14 +5306,72 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {...@@ -4721,14 +5306,72 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
4721 .segment => |phndx| switch (elf.phdrSlice()) {5306 .segment => |phndx| switch (elf.phdrSlice()) {
4722 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),5307 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),
4723 },5308 },
4724 .section => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf),5309 .section, .section_manual_size => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf),
4725 .input_section, .copied_global => unreachable,5310 .input_section, .copied_global => unreachable,
4726 inline .nav, .uav, .lazy_code, .lazy_const_data => |i| Symbol.Id.local(i.symbol(elf)).value(elf),5311 inline .nav,
5312 .uav,
5313 .lazy_code,
5314 .lazy_const_data,
5315 => |i| Symbol.Id.local(i.symbol(elf)).value(elf),
5316 .debug_shared, .eh_frame_footer, .unit_padding => unreachable,
5317 .unit_frame, .unit_debug_info, .unit_debug_line => {
5318 const section_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf);
5319 break :parent_vaddr elf.getNodeShndx(parent_ni).vaddr(elf) + section_offset;
5320 },
5321 .unit_frame_cie,
5322 .unit_debug_info_header,
5323 .unit_debug_info_footer,
5324 .unit_debug_line_header,
5325 .unit_debug_rnglists,
5326 .const_debug_info,
5327 .global_debug_info,
5328 .func_frame_fde,
5329 .func_debug_info,
5330 .func_debug_line,
5331 .decl_debug_info,
5332 => unreachable,
4727 };5333 };
4728 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);5334 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);
4729 return parent_vaddr + offset;5335 return parent_vaddr + offset;
4730}5336}
4731fn getNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 {5337fn computeNodeSectionOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 {
5338 const parent_ni = ni.parent(&elf.mf).unwrap().?;
5339 const parent_section_offset = parent_section_offset: switch (elf.getNode(parent_ni)) {
5340 .deleted,
5341 .archive,
5342 .archive_header,
5343 .archive_input_member,
5344 .archive_elf_member_header,
5345 .elf,
5346 .ehdr,
5347 .shdr,
5348 .segment,
5349 => unreachable,
5350 .section, .section_manual_size => 0,
5351 .input_section, .copied_global => unreachable,
5352 .nav, .uav, .lazy_code, .lazy_const_data => unreachable,
5353 .debug_shared, .eh_frame_footer, .unit_padding => unreachable,
5354 .unit_frame, .unit_debug_info, .unit_debug_line => {
5355 const parent_section_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf);
5356 break :parent_section_offset parent_section_offset;
5357 },
5358 .unit_frame_cie,
5359 .unit_debug_info_header,
5360 .unit_debug_info_footer,
5361 .unit_debug_line_header,
5362 .unit_debug_rnglists,
5363 .const_debug_info,
5364 .global_debug_info,
5365 .func_frame_fde,
5366 .func_debug_info,
5367 .func_debug_line,
5368 .decl_debug_info,
5369 => unreachable,
5370 };
5371 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);
5372 return parent_section_offset + offset;
5373}
5374fn computeNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 {
4732 return ni.fileLocation(&elf.mf, false).offset - elf.ni.elf.fileLocation(&elf.mf, false).offset;5375 return ni.fileLocation(&elf.mf, false).offset - elf.ni.elf.fileLocation(&elf.mf, false).offset;
4733}5376}
47345377
...@@ -4736,9 +5379,16 @@ fn getNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 {...@@ -4736,9 +5379,16 @@ fn getNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 {
4736/// sequence of relocations, so that the caller may append the node's updated relocations.5379/// sequence of relocations, so that the caller may append the node's updated relocations.
4737///5380///
4738/// Asserts that `ni` must be a node which supports relocations (see `Elf.Node`). Does not support5381/// Asserts that `ni` must be a node which supports relocations (see `Elf.Node`). Does not support
4739/// the special-case sections '.plt' and '.dynamic'.5382/// the special-case sections '.plt', '.dynamic', and '.eh_frame_hdr'.
4740fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {5383pub fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
4741 const symbol_relocs: *SymbolReloc.Index, const got_relocs: ?*GotReloc.Index = switch (elf.getNode(ni)) {5384 const opts: struct {
5385 first_symbol_reloc: ?*SymbolReloc.Index = null,
5386 skip_symbol_relocs: MappedFile.Node.Index.Optional = .none,
5387 first_node_reloc: ?*NodeReloc.Index = null,
5388 skip_node_relocs: MappedFile.Node.Index.Optional = .none,
5389 first_got_reloc: ?*GotReloc.Index = null,
5390 } = switch (elf.getNode(ni)) {
5391 .deleted,
4742 .archive,5392 .archive,
4743 .archive_header,5393 .archive_header,
4744 .archive_input_member,5394 .archive_input_member,
...@@ -4748,41 +5398,106 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {...@@ -4748,41 +5398,106 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
4748 .shdr,5398 .shdr,
4749 .segment,5399 .segment,
4750 .copied_global,5400 .copied_global,
5401 .debug_shared,
5402 .eh_frame_footer,
5403 .unit_padding,
5404 .unit_frame,
5405 .unit_frame_cie,
5406 .unit_debug_info,
5407 .unit_debug_line,
4751 => unreachable, // cannot contain relocs5408 => unreachable, // cannot contain relocs
4752 .section => unreachable, // cannot contain relocs (.plt and .dynamic unsupported)5409 .section,
5410 .section_manual_size,
5411 => unreachable, // cannot contain relocs (.plt, .dynamic, and .eh_frame_hdr unsupported)
4753 .input_section => |isi| .{5412 .input_section => |isi| .{
4754 &elf.input_sections.items[@backingInt(isi)].first_symbol_reloc,5413 .first_symbol_reloc = &elf.input_sections.items[@backingInt(isi)].first_symbol_reloc,
4755 &elf.input_sections.items[@backingInt(isi)].first_got_reloc,5414 .first_got_reloc = &elf.input_sections.items[@backingInt(isi)].first_got_reloc,
4756 },5415 },
4757 .nav => |nmi| .{5416 .nav => |nmi| .{
4758 &elf.navs.values()[@backingInt(nmi)].first_symbol_reloc,5417 .first_symbol_reloc = &elf.navs.values()[@backingInt(nmi)].first_symbol_reloc,
4759 &elf.navs.values()[@backingInt(nmi)].first_got_reloc,5418 .first_got_reloc = &elf.navs.values()[@backingInt(nmi)].first_got_reloc,
4760 },5419 },
4761 .uav => |umi| .{5420 .uav => |umi| .{
4762 &elf.uavs.values()[@backingInt(umi)].first_symbol_reloc,5421 .first_symbol_reloc = &elf.uavs.values()[@backingInt(umi)].first_symbol_reloc,
4763 null,
4764 },5422 },
4765 inline .lazy_code, .lazy_const_data => |lmi| .{5423 inline .lazy_code, .lazy_const_data => |lmi| .{
4766 &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_symbol_reloc,5424 .first_symbol_reloc = &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_symbol_reloc,
4767 &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_got_reloc,5425 .first_got_reloc = &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_got_reloc,
5426 },
5427 .unit_debug_info_header => |ui| .{
5428 .first_node_reloc = &elf.dwarf_units[@backingInt(ui)].debug_info_header_first_node_reloc,
5429 },
5430 .unit_debug_info_footer => unreachable, // cannot contain relocs
5431 .unit_debug_line_header => |ui| .{
5432 .first_node_reloc = &elf.dwarf_units[@backingInt(ui)].debug_line_header_first_node_reloc,
5433 },
5434 .unit_debug_rnglists => unreachable, // cannot contain relocs
5435 .const_debug_info => |cpi| .{
5436 .first_symbol_reloc = &elf.dwarf_consts.getPtr(cpi).?.debug_info_first_symbol_reloc,
5437 .first_node_reloc = &elf.dwarf_consts.getPtr(cpi).?.debug_info_first_node_reloc,
5438 },
5439 .global_debug_info => |gi| .{
5440 .first_symbol_reloc = &elf.dwarf_globals.items[@backingInt(gi)].debug_info_first_symbol_reloc,
5441 .first_node_reloc = &elf.dwarf_globals.items[@backingInt(gi)].debug_info_first_node_reloc,
5442 },
5443 .func_frame_fde => |fi| .{
5444 .first_symbol_reloc = &elf.dwarf_funcs.items[@backingInt(fi)].frame_fde_first_symbol_reloc,
5445 .first_node_reloc = &elf.dwarf_funcs.items[@backingInt(fi)].frame_fde_first_node_reloc,
5446 },
5447 .func_debug_info => |fi| .{
5448 .first_symbol_reloc = &elf.dwarf_funcs.items[@backingInt(fi)].debug_info_first_symbol_reloc,
5449 .skip_symbol_relocs = if (elf.navs.getPtr(fi.nav(&elf.dwarf))) |nav|
5450 nav.lsi.index().ptr(elf).node
5451 else
5452 .none,
5453 .first_node_reloc = &elf.dwarf_funcs.items[@backingInt(fi)].debug_info_first_node_reloc,
5454 .skip_node_relocs = fi.get(&elf.dwarf).debug_line_ni,
5455 },
5456 .func_debug_line => |fi| .{
5457 .first_symbol_reloc = &elf.dwarf_funcs.items[@backingInt(fi)].debug_line_first_symbol_reloc,
5458 .first_node_reloc = &elf.dwarf_funcs.items[@backingInt(fi)].debug_line_first_node_reloc,
5459 .skip_node_relocs = fi.get(&elf.dwarf).debug_info_ni,
5460 },
5461 .decl_debug_info => |di| .{
5462 .first_node_reloc = &elf.dwarf_decls.getPtr(di).?.debug_info_first_node_reloc,
4768 },5463 },
4769 };5464 };
47705465
4771 if (symbol_relocs.* != .none) {5466 if (opts.first_symbol_reloc) |ptr| {
4772 for (5467 if (ptr.* != .none) {
4773 elf.symbol_relocs.items[@backingInt(symbol_relocs.*)..],5468 for (elf.symbol_relocs.items[@backingInt(ptr.*)..], @backingInt(ptr.*)..) |*reloc, index| {
4774 @backingInt(symbol_relocs.*)..,5469 if (reloc.node != ni.toOptional()) {
4775 ) |*reloc, index| {5470 if (reloc.node == .none) continue;
4776 if (reloc.node != ni) break;5471 if (reloc.node == opts.skip_symbol_relocs) continue;
4777 reloc.delete(elf, @fromBackingInt(@intCast(index)));5472 break;
5473 }
5474 reloc.delete(elf, @fromBackingInt(@intCast(index)));
5475 }
5476 }
5477 ptr.* = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
5478 }
5479
5480 if (opts.first_node_reloc) |ptr| {
5481 if (ptr.* != .none) {
5482 for (elf.node_relocs.items[@backingInt(ptr.*)..]) |*reloc| {
5483 if (reloc.node != ni.toOptional()) {
5484 if (reloc.node == .none) continue;
5485 if (reloc.node == opts.skip_node_relocs) continue;
5486 break;
5487 }
5488 reloc.delete(elf);
5489 }
4778 }5490 }
5491 ptr.* = @fromBackingInt(@intCast(elf.node_relocs.items.len));
4779 }5492 }
4780 symbol_relocs.* = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
47815493
4782 if (got_relocs) |ptr| {5494 if (opts.first_got_reloc) |ptr| {
4783 if (ptr.* != .none) {5495 if (ptr.* != .none) {
4784 for (elf.got_relocs.items[@backingInt(ptr.*)..]) |*reloc| {5496 for (elf.got_relocs.items[@backingInt(ptr.*)..]) |*reloc| {
4785 if (reloc.node != ni.toOptional()) break;5497 if (reloc.node != ni.toOptional()) {
5498 if (reloc.node == .none) continue;
5499 break;
5500 }
4786 reloc.delete(elf);5501 reloc.delete(elf);
4787 }5502 }
4788 }5503 }
...@@ -4796,29 +5511,42 @@ fn flushMovedNodeRelocs(...@@ -4796,29 +5511,42 @@ fn flushMovedNodeRelocs(
4796 elf: *Elf,5511 elf: *Elf,
4797 node: MappedFile.Node.Index,5512 node: MappedFile.Node.Index,
4798 node_vaddr: u64,5513 node_vaddr: u64,
4799 first_symbol_reloc: SymbolReloc.Index,5514 opts: struct {
4800 first_got_reloc: GotReloc.Index,5515 first_symbol_reloc: SymbolReloc.Index = .none,
5516 skip_symbol_relocs: MappedFile.Node.Index.Optional = .none,
5517 first_node_reloc: NodeReloc.Index = .none,
5518 skip_node_relocs: MappedFile.Node.Index.Optional = .none,
5519 first_got_reloc: GotReloc.Index = .none,
5520 },
4801) void {5521) void {
4802 if (first_symbol_reloc != .none) {5522 if (opts.first_symbol_reloc != .none) {
4803 for (elf.symbol_relocs.items[@backingInt(first_symbol_reloc)..]) |*reloc| {5523 for (elf.symbol_relocs.items[@backingInt(opts.first_symbol_reloc)..]) |*reloc| {
4804 if (reloc.node != node) break;5524 if (reloc.node != node.toOptional()) {
4805 if (reloc.rela_index.unwrap()) |rela_index| {5525 if (reloc.node == .none) continue;
4806 // The node has moved, so the offset of the relocation within the section might have5526 if (reloc.node == opts.skip_symbol_relocs) continue;
4807 // changed, so update the `offset` field of the `ElfN.Rela` entry.5527 break;
4808 reloc.relaSection(elf).relaSetOffset(elf, rela_index, node_vaddr + reloc.offset);5528 }
4809 }5529 reloc.flushMovedNode(elf, node_vaddr);
4810 // This is not just the inverse of the above condition, because if `reloc` is relative5530 }
4811 // to the base of this DSO, then `rela_index` is an `R_*_RELATIVE` relocation, but we5531 }
4812 // still need to call `SymbolReloc.apply` to update that relocation's addend.5532
4813 if (elf.ehdrType() != .REL) {5533 if (opts.first_node_reloc != .none) {
4814 reloc.apply(elf);5534 for (elf.node_relocs.items[@backingInt(opts.first_node_reloc)..]) |*reloc| {
5535 if (reloc.node != node.toOptional()) {
5536 if (reloc.node == .none) continue;
5537 if (reloc.node == opts.skip_node_relocs) continue;
5538 break;
4815 }5539 }
5540 reloc.flushMovedNode(elf, node_vaddr);
4816 }5541 }
4817 }5542 }
48185543
4819 if (first_got_reloc != .none) {5544 if (opts.first_got_reloc != .none) {
4820 for (elf.got_relocs.items[@backingInt(first_got_reloc)..]) |*reloc| {5545 for (elf.got_relocs.items[@backingInt(opts.first_got_reloc)..]) |*reloc| {
4821 if (reloc.node != node.toOptional()) break;5546 if (reloc.node != node.toOptional()) {
5547 if (reloc.node == .none) continue;
5548 break;
5549 }
4822 reloc.apply(elf);5550 reloc.apply(elf);
4823 }5551 }
4824 }5552 }
...@@ -5088,13 +5816,12 @@ const ShdrPtr = union(std.elf.CLASS) {...@@ -5088,13 +5816,12 @@ const ShdrPtr = union(std.elf.CLASS) {
5088 @"64": *std.elf.Elf64.Shdr,5816 @"64": *std.elf.Elf64.Shdr,
5089};5817};
5090fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr {5818fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr {
5091 const raw_slice = elf.ni.shdr.slice(&elf.mf);5819 const slice = elf.ni.shdr.slice(&elf.mf);
5092 switch (elf.identClass()) {5820 switch (elf.identClass()) {
5093 .NONE, _ => unreachable,5821 .NONE, _ => unreachable,
5094 inline else => |class| {5822 inline else => |class| {
5095 const shdrs_len = elf.shdrs.items.len + 1; // +1 for SHN_UNDEF
5096 const shdr_slice: []class.ElfN().Shdr = @ptrCast(@alignCast(5823 const shdr_slice: []class.ElfN().Shdr = @ptrCast(@alignCast(
5097 raw_slice[0 .. shdrs_len * @sizeOf(class.ElfN().Shdr)],5824 slice[0 .. @sizeOf(class.ElfN().Shdr) * (1 + elf.shdrs.items.len)],
5098 ));5825 ));
5099 const shdr_ptr = &shdr_slice[@backingInt(shndx)];5826 const shdr_ptr = &shdr_slice[@backingInt(shndx)];
5100 return @unionInit(ShdrPtr, @tagName(class), shdr_ptr);5827 return @unionInit(ShdrPtr, @tagName(class), shdr_ptr);
...@@ -5226,7 +5953,7 @@ fn mapInputSection(elf: *Elf, opts: struct {...@@ -5226,7 +5953,7 @@ fn mapInputSection(elf: *Elf, opts: struct {
5226 }5953 }
52275954
5228 switch (elf.targetLoad(&shdr.type)) {5955 switch (elf.targetLoad(&shdr.type)) {
5229 .NULL, .PROGBITS => {},5956 .NULL, .PROGBITS, .X86_64_UNWIND => {},
5230 else => return error.SectionTypeConflict,5957 else => return error.SectionTypeConflict,
5231 }5958 }
52325959
...@@ -5270,6 +5997,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node...@@ -5270,6 +5997,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
5270 })) |shndx| {5997 })) |shndx| {
5271 break :section shndx;5998 break :section shndx;
5272 } else |err| switch (err) {5999 } else |err| switch (err) {
6000 else => |e| return e,
5273 error.StripSection,6001 error.StripSection,
5274 error.TlsSectionUnavailable,6002 error.TlsSectionUnavailable,
5275 error.UnsupportedSectionFlags,6003 error.UnsupportedSectionFlags,
...@@ -5277,7 +6005,6 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node...@@ -5277,7 +6005,6 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
5277 error.SectionFlagsConflict,6005 error.SectionFlagsConflict,
5278 => {}, // fall back to default behavior below6006 => {}, // fall back to default behavior below
52796007
5280 else => |e| return e,
5281 }6008 }
5282 }6009 }
5283 if (elf.base.comp.config.any_non_single_threaded and nav.resolved.?.@"threadlocal") {6010 if (elf.base.comp.config.any_non_single_threaded and nav.resolved.?.@"threadlocal") {
...@@ -5294,15 +6021,11 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node...@@ -5294,15 +6021,11 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
5294 .@"fn" => a: {6021 .@"fn" => a: {
5295 const mod = zcu.navFileScope(nav_index).mod.?;6022 const mod = zcu.navFileScope(nav_index).mod.?;
5296 const target = &mod.resolved_target.result;6023 const target = &mod.resolved_target.result;
5297 const min = target_util.minFunctionAlignment(target);
5298 break :a .fromIp(switch (nav.resolved.?.@"align") {6024 break :a .fromIp(switch (nav.resolved.?.@"align") {
5299 else => |a| a.maxStrict(min),6025 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
5300 .none => switch (mod.optimize_mode) {6026 .none => switch (mod.optimize_mode) {
5301 .debug,6027 .debug, .safe, .fast => target_util.defaultFunctionAlignment(target),
5302 .safe,6028 .small => target_util.minFunctionAlignment(target),
5303 .fast,
5304 => target_util.defaultFunctionAlignment(target),
5305 .small => min,
5306 }.maxStrict(Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu)),6029 }.maxStrict(Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu)),
5307 });6030 });
5308 },6031 },
...@@ -5312,9 +6035,9 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node...@@ -5312,9 +6035,9 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
5312 },6035 },
5313 };6036 };
5314 try shndx.ensureAligned(elf, alignment);6037 try shndx.ensureAligned(elf, alignment);
5315 const node = try shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{6038 const node = elf.addNodeAssumeCapacity(try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{
5316 .alignment = alignment,6039 .alignment = alignment,
5317 });6040 }), .{ .nav = nmi });
5318 nav_gop.value_ptr.* = .{6041 nav_gop.value_ptr.* = .{
5319 .lsi = elf.addLocalSymbolAssumeCapacity(.{6042 .lsi = elf.addLocalSymbolAssumeCapacity(.{
5320 .node = .wrap(node),6043 .node = .wrap(node),
...@@ -5327,7 +6050,6 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node...@@ -5327,7 +6050,6 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
5327 .first_symbol_reloc = .none,6050 .first_symbol_reloc = .none,
5328 .first_got_reloc = .none,6051 .first_got_reloc = .none,
5329 };6052 };
5330 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
5331 }6053 }
5332 return nmi;6054 return nmi;
5333}6055}
...@@ -5356,16 +6078,12 @@ fn uavMapIndex(...@@ -5356,16 +6078,12 @@ fn uavMapIndex(
5356 if (!uav_gop.found_existing) {6078 if (!uav_gop.found_existing) {
5357 const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs6079 const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs
5358 try shndx.ensureAligned(elf, resolved_align);6080 try shndx.ensureAligned(elf, resolved_align);
5359 const node = try shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{6081 const node = elf.addNodeAssumeCapacity(try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{
5360 .moved = true, // see assert at end of `genUav`6082 .moved = true, // see assert at end of `genUav`
5361 .alignment = resolved_align,6083 .alignment = resolved_align,
5362 });6084 }), .{ .uav = umi });
5363 var name_buf: [32]u8 = undefined;6085 var name_buf: [std.fmt.count("__anon_{d}", .{std.math.maxInt(u32)})]u8 = undefined;
5364 const name = std.mem.print(6086 const name = std.mem.print(&name_buf, "__anon_{d}", .{umi}) catch unreachable;
5365 &name_buf,
5366 "__anon_{d}",
5367 .{@backingInt(uav_val)},
5368 ) catch unreachable;
5369 uav_gop.value_ptr.* = .{6087 uav_gop.value_ptr.* = .{
5370 .lsi = elf.addLocalSymbolAssumeCapacity(.{6088 .lsi = elf.addLocalSymbolAssumeCapacity(.{
5371 .node = .wrap(node),6089 .node = .wrap(node),
...@@ -5377,15 +6095,14 @@ fn uavMapIndex(...@@ -5377,15 +6095,14 @@ fn uavMapIndex(
5377 }),6095 }),
5378 .first_symbol_reloc = .none,6096 .first_symbol_reloc = .none,
5379 };6097 };
5380 elf.nodes.appendAssumeCapacity(.{ .uav = umi });
5381 elf.const_prog_node.increaseEstimatedTotalItems(1);6098 elf.const_prog_node.increaseEstimatedTotalItems(1);
5382 elf.pending_uavs.appendAssumeCapacity(umi);6099 elf.pending_uavs.appendAssumeCapacity(umi);
5383 } else {6100 } else {
5384 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node.unwrap().?;6101 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node.unwrap().?;
5385 const shndx = elf.getNode(node.parent(&elf.mf).unwrap().?).section;6102 const shndx = elf.getNodeShndx(node);
5386 try shndx.ensureAligned(elf, resolved_align);6103 try shndx.ensureAligned(elf, resolved_align);
5387 if (resolved_align.order(node.alignment(&elf.mf)).compare(.gt)) {6104 if (resolved_align.order(node.alignment(&elf.mf)).compare(.gt)) {
5388 try node.realign(&elf.mf, gpa, resolved_align);6105 try node.realign(gpa, &elf.mf, resolved_align);
5389 }6106 }
5390 }6107 }
5391 return umi;6108 return umi;
...@@ -5518,9 +6235,9 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load...@@ -5518,9 +6235,9 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load
5518 return error.BadMagic;6235 return error.BadMagic;
5519 }6236 }
5520 }6237 }
5521 var strtab: std.Io.Writer.Allocating = .init(gpa);6238 var strtab: Io.Writer.Allocating = .init(gpa);
5522 defer strtab.deinit();6239 defer strtab.deinit();
5523 while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| {6240 while (r.takeStruct(std.elf.ar_hdr, .native)) |header| {
5524 if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG))6241 if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG))
5525 return diags.failParse(path, "bad file magic", .{});6242 return diags.failParse(path, "bad file magic", .{});
5526 const offset = fr.logicalPos();6243 const offset = fr.logicalPos();
...@@ -5530,8 +6247,8 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load...@@ -5530,8 +6247,8 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load
5530 strtab.clearRetainingCapacity();6247 strtab.clearRetainingCapacity();
5531 try strtab.ensureTotalCapacityPrecise(size);6248 try strtab.ensureTotalCapacityPrecise(size);
5532 r.streamExact(&strtab.writer, size) catch |err| switch (err) {6249 r.streamExact(&strtab.writer, size) catch |err| switch (err) {
5533 error.WriteFailed => return error.OutOfMemory,
5534 else => |e| return e,6250 else => |e| return e,
6251 error.WriteFailed => return error.OutOfMemory,
5535 };6252 };
5536 continue;6253 continue;
5537 }6254 }
...@@ -5562,14 +6279,14 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load...@@ -5562,14 +6279,14 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load
5562 }6279 }
5563 try fr.seekTo(std.mem.alignForward(u64, offset + size, 2));6280 try fr.seekTo(std.mem.alignForward(u64, offset + size, 2));
5564 } else |err| switch (err) {6281 } else |err| switch (err) {
5565 error.EndOfStream => if (!fr.atEnd()) return error.EndOfStream,
5566 else => |e| return e,6282 else => |e| return e,
6283 error.EndOfStream => if (!fr.atEnd()) return error.EndOfStream,
5567 }6284 }
5568}6285}
5569fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEscape) {6286fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEscape) {
5570 return .{ .data = member };6287 return .{ .data = member };
5571}6288}
5572fn memberStringEscape(member: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void {6289fn memberStringEscape(member: ?[]const u8, w: *Io.Writer) Io.Writer.Error!void {
5573 try w.print("({f})", .{std.zig.fmtString(member orelse return)});6290 try w.print("({f})", .{std.zig.fmtString(member orelse return)});
5574}6291}
5575fn loadObject(6292fn loadObject(
...@@ -5614,11 +6331,13 @@ fn loadObject(...@@ -5614,11 +6331,13 @@ fn loadObject(
5614 };6331 };
56156332
5616 try elf.nodes.ensureUnusedCapacity(gpa, 1);6333 try elf.nodes.ensureUnusedCapacity(gpa, 1);
5617 const new_member_ni = try archive.ni.addFooterChildBefore(&elf.mf, gpa, first_member_oni, .{6334 const new_member_ni = elf.addNodeAssumeCapacity(
5618 .size = Alignment.@"2".forward(@sizeOf(std.elf.ar_hdr) + fl.size),6335 try archive.ni.addFooterChildBefore(gpa, &elf.mf, first_member_oni, .{
5619 .alignment = .@"2",6336 .size = Alignment.@"2".forward(@sizeOf(std.elf.ar_hdr) + fl.size),
5620 });6337 .alignment = .@"2",
5621 elf.nodes.appendAssumeCapacity(.{ .archive_input_member = input_index });6338 }),
6339 .{ .archive_input_member = input_index },
6340 );
5622 input.extra = .{ .node = new_member_ni };6341 input.extra = .{ .node = new_member_ni };
5623 elf.input_prog_node.increaseEstimatedTotalItems(1);6342 elf.input_prog_node.increaseEstimatedTotalItems(1);
56246343
...@@ -5717,18 +6436,19 @@ fn loadObject(...@@ -5717,18 +6436,19 @@ fn loadObject(
5717 for (sections[1..]) |*section| {6436 for (sections[1..]) |*section| {
5718 if (section.shdr.name >= shstrtab.len) continue;6437 if (section.shdr.name >= shstrtab.len) continue;
5719 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);6438 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
6439 if (!comp.config.any_unwind_tables and std.mem.eql(u8, name, ".eh_frame")) continue;
5720 const opts: struct {6440 const opts: struct {
5721 shndx: Section.Index,6441 shndx: Section.Index,
5722 has_file_bits: bool,
5723 node_fixed: bool,6442 node_fixed: bool,
5724 } = switch (section.shdr.type) {6443 } = switch (section.shdr.type) {
5725 else => continue,6444 else => continue,
5726 .PROGBITS, .NOBITS => opts: {6445 .PROGBITS, .NOBITS, .X86_64_UNWIND => opts: {
5727 const shndx = elf.mapInputSection(.{6446 const shndx = elf.mapInputSection(.{
5728 .name = name,6447 .name = name,
5729 .flags = section.shdr.flags.shf,6448 .flags = section.shdr.flags.shf,
5730 .entsize = section.shdr.entsize,6449 .entsize = section.shdr.entsize,
5731 }) catch |err| switch (err) {6450 }) catch |err| switch (err) {
6451 else => |e| return e,
5732 error.StripSection => continue,6452 error.StripSection => continue,
5733 error.TlsSectionUnavailable => return diags.failParse(6453 error.TlsSectionUnavailable => return diags.failParse(
5734 path,6454 path,
...@@ -5759,7 +6479,6 @@ fn loadObject(...@@ -5759,7 +6479,6 @@ fn loadObject(
5759 "flags of section '{s}' conflict with other inputs",6479 "flags of section '{s}' conflict with other inputs",
5760 .{name},6480 .{name},
5761 ),6481 ),
5762 else => |e| return e,
5763 };6482 };
5764 if (section.shdr.flags.shf.COMPRESSED) {6483 if (section.shdr.flags.shf.COMPRESSED) {
5765 // SHF_COMPRESSED is only allowed on non-alloc sections.6484 // SHF_COMPRESSED is only allowed on non-alloc sections.
...@@ -5776,7 +6495,6 @@ fn loadObject(...@@ -5776,7 +6495,6 @@ fn loadObject(
5776 }6495 }
5777 break :opts .{6496 break :opts .{
5778 .shndx = shndx,6497 .shndx = shndx,
5779 .has_file_bits = section.shdr.type == .PROGBITS,
5780 // For well-known sections, we know that it's fine to have e.g. random6498 // For well-known sections, we know that it's fine to have e.g. random
5781 // padding, so there's no need to make the sections fixed. For custom6499 // padding, so there's no need to make the sections fixed. For custom
5782 // sections, however, we do want fixed nodes to avoid padding.6500 // sections, however, we do want fixed nodes to avoid padding.
...@@ -5819,7 +6537,6 @@ fn loadObject(...@@ -5819,7 +6537,6 @@ fn loadObject(
5819 }6537 }
5820 break :shndx shndx.*;6538 break :shndx shndx.*;
5821 },6539 },
5822 .has_file_bits = true,
5823 // This node must be fixed to prevent padding from being added between different6540 // This node must be fixed to prevent padding from being added between different
5824 // INIT_ARRAY/FINI_ARRAY/PREINIT_ARRAY input sections.6541 // INIT_ARRAY/FINI_ARRAY/PREINIT_ARRAY input sections.
5825 .node_fixed = true,6542 .node_fixed = true,
...@@ -5834,28 +6551,26 @@ fn loadObject(...@@ -5834,28 +6551,26 @@ fn loadObject(
5834 .alignment = need_align,6551 .alignment = need_align,
5835 .moved = true, // see assert at end of `flushInputSection`6552 .moved = true, // see assert at end of `flushInputSection`
5836 };6553 };
5837 const ni = if (opts.node_fixed) ni: {6554 const ni = elf.addNodeAssumeCapacity(
5838 const shndx_ni = opts.shndx.get(elf).ni;6555 if (opts.node_fixed) ni: {
5839 const after_oni: MappedFile.Node.Index.Optional = after: {6556 const shndx_ni = opts.shndx.get(elf).ni;
5840 const last_ni = shndx_ni.last(&elf.mf).unwrap() orelse break :after .none;6557 const after_oni: MappedFile.Node.Index.Optional = after: {
5841 break :after switch (last_ni.position(&elf.mf)) {6558 const last_ni = shndx_ni.last(&elf.mf).unwrap() orelse break :after .none;
5842 .header => .wrap(last_ni),6559 break :after switch (last_ni.position(&elf.mf)) {
5843 .footer, .floating => .none,6560 .header => .wrap(last_ni),
6561 .footer, .floating => .none,
6562 };
5844 };6563 };
5845 };6564 break :ni try shndx_ni.addHeaderChildAfter(gpa, &elf.mf, after_oni, add_node_opts);
5846 break :ni try shndx_ni.addHeaderChildAfter(&elf.mf, gpa, after_oni, add_node_opts);6565 } else try opts.shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, add_node_opts),
5847 } else ni: {6566 .{ .input_section = @fromBackingInt(@intCast(elf.input_sections.items.len)) },
5848 break :ni try opts.shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, add_node_opts);6567 );
5849 };
5850 elf.nodes.appendAssumeCapacity(.{
5851 .input_section = @fromBackingInt(@intCast(elf.input_sections.items.len)),
5852 });
5853 section.isi = @fromBackingInt(@intCast(elf.input_sections.items.len));6568 section.isi = @fromBackingInt(@intCast(elf.input_sections.items.len));
5854 elf.input_sections.addOneAssumeCapacity().* = .{6569 elf.input_sections.addOneAssumeCapacity().* = .{
5855 .input = input_index,6570 .input = input_index,
5856 .file_location = .{6571 .file_location = .{
5857 .offset = fl.offset + section.shdr.offset,6572 .offset = fl.offset + section.shdr.offset,
5858 .size = if (opts.has_file_bits) section.shdr.size else 0,6573 .size = if (section.shdr.type == .NOBITS) 0 else section.shdr.size,
5859 },6574 },
5860 // The section vaddr is initially 0, because the symbol addresses are6575 // The section vaddr is initially 0, because the symbol addresses are
5861 // zero-based. This will eventually be updated by `flushMoved`.6576 // zero-based. This will eventually be updated by `flushMoved`.
...@@ -6043,6 +6758,7 @@ fn loadObject(...@@ -6043,6 +6758,7 @@ fn loadObject(
6043 rel.addend,6758 rel.addend,
6044 rt,6759 rt,
6045 ) catch |err| switch (err) {6760 ) catch |err| switch (err) {
6761 else => |e| return e,
6046 error.UnknownRelocation => diags.addParseError(6762 error.UnknownRelocation => diags.addParseError(
6047 path,6763 path,
6048 "unknown relocation type '{f}'",6764 "unknown relocation type '{f}'",
...@@ -6058,7 +6774,6 @@ fn loadObject(...@@ -6058,7 +6774,6 @@ fn loadObject(
6058 "TODO(Elf2): unimplemented relocation type '{f}'",6774 "TODO(Elf2): unimplemented relocation type '{f}'",
6059 .{rt.fmt(elf)},6775 .{rt.fmt(elf)},
6060 ),6776 ),
6061 else => |e| return e,
6062 };6777 };
6063 }6778 }
6064 },6779 },
...@@ -6102,7 +6817,7 @@ fn populateArchiveMemberName(elf: *Elf, member_ar_hdr: *std.elf.ar_hdr, member_n...@@ -6102,7 +6817,7 @@ fn populateArchiveMemberName(elf: *Elf, member_ar_hdr: *std.elf.ar_hdr, member_n
6102 // We set the size of the archive header node exactly, because we want padding bytes to go into6817 // We set the size of the archive header node exactly, because we want padding bytes to go into
6103 // the root `.archive` node. That way, those bytes could still be used to grow the string table6818 // the root `.archive` node. That way, those bytes could still be used to grow the string table
6104 // if necessary, but they could also be used for new archive members.6819 // if necessary, but they could also be used for new archive members.
6105 try archive_header_ni.resizeLeaf(&elf.mf, gpa, old_archive_header_size + member_name.len + 2);6820 try archive_header_ni.resizeLeaf(gpa, &elf.mf, old_archive_header_size + member_name.len + 2);
61066821
6107 const dest_slice = archive_header_ni.slice(&elf.mf)[@intCast(old_archive_header_size)..];6822 const dest_slice = archive_header_ni.slice(&elf.mf)[@intCast(old_archive_header_size)..];
6108 @memcpy(dest_slice[0 .. dest_slice.len - 2], member_name);6823 @memcpy(dest_slice[0 .. dest_slice.len - 2], member_name);
...@@ -6254,8 +6969,12 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars...@@ -6254,8 +6969,12 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars
6254 // We have a copy relocation for this global, but the amount of space we6969 // We have a copy relocation for this global, but the amount of space we
6255 // reserved for it could be too small or underaligned!6970 // reserved for it could be too small or underaligned!
6256 try Section.Index.data.ensureAligned(elf, gop.value_ptr.alignment);6971 try Section.Index.data.ensureAligned(elf, gop.value_ptr.alignment);
6257 try copied_global.node.resizeLeaf(&elf.mf, gpa, gop.value_ptr.alignment.forward(gop.value_ptr.size));6972 try copied_global.node.resizeLeaf(
6258 try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment);6973 gpa,
6974 &elf.mf,
6975 gop.value_ptr.alignment.forward(gop.value_ptr.size),
6976 );
6977 try copied_global.node.realign(gpa, &elf.mf, gop.value_ptr.alignment);
6259 const global_ptr = elf.globalByName(name).?;6978 const global_ptr = elf.globalByName(name).?;
6260 switch (elf.symPtr(global_ptr.symtab_index)) {6979 switch (elf.symPtr(global_ptr.symtab_index)) {
6261 inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)),6980 inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)),
...@@ -6407,6 +7126,7 @@ fn createInitFiniArraySection(...@@ -6407,6 +7126,7 @@ fn createInitFiniArraySection(
6407 .type = @"type",7126 .type = @"type",
6408 .flags = .{ .WRITE = true, .ALLOC = true },7127 .flags = .{ .WRITE = true, .ALLOC = true },
6409 .node_align = addr_align,7128 .node_align = addr_align,
7129 .manual_size = true,
6410 });7130 });
6411 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});7131 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});
6412 try elf.ensureUnusedSymbolCapacity(2, .maybe_global);7132 try elf.ensureUnusedSymbolCapacity(2, .maybe_global);
...@@ -6454,8 +7174,9 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) link.Error!void {...@@ -6454,8 +7174,9 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) link.Error!void {
6454fn prelinkInner(elf: *Elf) Error!void {7174fn prelinkInner(elf: *Elf) Error!void {
6455 const comp = elf.base.comp;7175 const comp = elf.base.comp;
6456 const gpa = comp.gpa;7176 const gpa = comp.gpa;
7177 if (comp.zcu) |_| self_hosted_codegen: {
7178 if (comp.config.use_llvm) break :self_hosted_codegen;
64577179
6458 if (comp.zcu != null and !comp.config.use_llvm and elf.ni.elf == .root) {
6459 // We're using self-hosted codegen---add an input representing the Zig "object".7180 // We're using self-hosted codegen---add an input representing the Zig "object".
6460 try elf.ensureUnusedSymbolCapacity(1, .all_local);7181 try elf.ensureUnusedSymbolCapacity(1, .all_local);
6461 try elf.inputs.ensureUnusedCapacity(gpa, 1);7182 try elf.inputs.ensureUnusedCapacity(gpa, 1);
...@@ -6475,7 +7196,226 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -6475,7 +7196,226 @@ fn prelinkInner(elf: *Elf) Error!void {
6475 .extra = .{ .file_symbol = zcu_file_symbol },7196 .extra = .{ .file_symbol = zcu_file_symbol },
6476 };7197 };
6477 elf.input_pending_index += 1;7198 elf.input_pending_index += 1;
7199
7200 try elf.nodes.ensureUnusedCapacity(gpa, 5 + 4);
7201
7202 switch (elf.shndx.debug_abbrev) {
7203 .UNDEF => {},
7204 else => |debug_abbrev_shndx| elf.dwarf.debug_abbrev.ni = .wrap(elf.addNodeAssumeCapacity(
7205 try debug_abbrev_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}),
7206 .{ .debug_shared = .debug_abbrev },
7207 )),
7208 }
7209 switch (elf.shndx.debug_line_str) {
7210 .UNDEF => {},
7211 else => |debug_line_str_shndx| elf.dwarf.debug_line_str.ni =
7212 .wrap(elf.addNodeAssumeCapacity(
7213 try debug_line_str_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}),
7214 .{ .debug_shared = .debug_line_str },
7215 )),
7216 }
7217 switch (elf.shndx.debug_str) {
7218 .UNDEF => {},
7219 else => |debug_str_shndx| elf.dwarf.debug_str.ni = .wrap(elf.addNodeAssumeCapacity(
7220 try debug_str_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}),
7221 .{ .debug_shared = .debug_str },
7222 )),
7223 }
7224 switch (elf.shndx.debug_str_offsets) {
7225 .UNDEF => {},
7226 else => |debug_str_offsets_shndx| elf.dwarf.debug_str_offsets.ni =
7227 .wrap(elf.addNodeAssumeCapacity(
7228 try debug_str_offsets_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}),
7229 .{ .debug_shared = .debug_str_offsets },
7230 )),
7231 }
7232
7233 for ([5]Section.Index{
7234 elf.shndx.eh_frame,
7235 elf.shndx.debug_frame,
7236 elf.shndx.debug_info,
7237 elf.shndx.debug_line,
7238 elf.shndx.debug_rnglists,
7239 }) |debug_shndx| {
7240 if (debug_shndx == .UNDEF) continue;
7241 const debug_ni = debug_shndx.get(elf).ni;
7242 const frame_format = debug_shndx.debugFrameFormat(elf);
7243 const unit_padding_ni = elf.addNodeAssumeCapacity(
7244 try debug_ni.addHeaderChildAfter(gpa, &elf.mf, last_header_oni: {
7245 var last_header_oni = debug_ni.last(&elf.mf);
7246 while (last_header_oni.unwrap()) |last_header_ni|
7247 switch (last_header_ni.position(&elf.mf)) {
7248 .header => break,
7249 .footer => last_header_oni = last_header_ni.prev(&elf.mf),
7250 .floating => unreachable,
7251 };
7252 break :last_header_oni last_header_oni;
7253 }, .{
7254 .alignment = if (frame_format) |_| switch (elf.identClass()) {
7255 .NONE, _ => unreachable,
7256 .@"32" => .@"4",
7257 .@"64" => .@"8",
7258 } else .@"1",
7259 .next_moved = true,
7260 .enable_next_moved = true,
7261 }),
7262 .unit_padding,
7263 );
7264 var debug_nw: MappedFile.Node.Writer = undefined;
7265 unit_padding_ni.writer(gpa, &elf.mf, &debug_nw);
7266 defer debug_nw.deinit();
7267 (if (frame_format) |format|
7268 elf.dwarf.genDebugFrameCie(&debug_nw.interface, null, format)
7269 else
7270 elf.dwarf.genUnitPadding(&debug_nw.interface)) catch |err| switch (err) {
7271 error.WriteFailed => return debug_nw.err.?,
7272 };
7273 }
7274 }
7275}
7276
7277pub fn zcuFilesReady(elf: *Elf, zcu: *Zcu) link.Error!void {
7278 elf.zcuFilesReadyInner(zcu) catch |err| switch (err) {
7279 else => |e| return e,
7280 error.MappedFileIo => return elf.base.comp.link_diags.fail(
7281 "failed to write output file: {t}",
7282 .{elf.mf.io_err.?},
7283 ),
7284 };
7285}
7286fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void {
7287 const gpa = zcu.gpa;
7288 const units_len = zcu.module_roots.count();
7289 if (elf.dwarf_units.len == 0) {
7290 @branchHint(.unlikely);
7291 try elf.dwarf.initUnits(gpa, units_len);
7292 elf.dwarf_units = try gpa.alloc(dwarf_relocs.Unit, zcu.module_roots.count());
7293 @memset(elf.dwarf_units, .{
7294 .frame_cie_first_target_reloc = .none,
7295 .debug_info_header_first_target_reloc = .none,
7296 .debug_info_header_first_node_reloc = .none,
7297 .debug_line_header_first_target_reloc = .none,
7298 .debug_line_header_first_node_reloc = .none,
7299 .debug_rnglists_first_target_reloc = .none,
7300 .debug_rnglists_symbol_relocs = .empty,
7301 });
7302 }
7303 if (!try elf.dwarf.updateUnits(zcu)) return;
7304 try elf.nodes.ensureUnusedCapacity(gpa, 5 * units_len);
7305 for (0..units_len) |unit_index| {
7306 const ui: Dwarf.Unit.Index = @fromBackingInt(@intCast(unit_index));
7307 const unit = ui.get(&elf.dwarf);
7308 if (!unit.alive) continue;
7309 switch (elf.shndx.debug_info) {
7310 .UNDEF => {},
7311 else => |debug_info_shndx| {
7312 const debug_info_ni = unit.debug_info_ni.unwrap() orelse debug_info_ni: {
7313 const debug_info_ni = elf.addNodeAssumeCapacity(
7314 try debug_info_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{
7315 .alignment = elf.mf.flags.block_size,
7316 .enable_next_moved = true,
7317 }),
7318 .{ .unit_debug_info = ui },
7319 );
7320 unit.debug_info_ni = .wrap(debug_info_ni);
7321 break :debug_info_ni debug_info_ni;
7322 };
7323 if (unit.debug_info_header_ni == .none) unit.debug_info_header_ni = .wrap(
7324 elf.addNodeAssumeCapacity(try debug_info_ni.addOnlyHeaderChild(gpa, &elf.mf, .{
7325 .next_moved = true,
7326 .enable_next_moved = true,
7327 }), .{ .unit_debug_info_header = ui }),
7328 );
7329 if (unit.debug_info_footer_ni == .none) unit.debug_info_footer_ni = .wrap(
7330 elf.addNodeAssumeCapacity(try debug_info_ni.addOnlyFooterChild(gpa, &elf.mf, .{
7331 .size = comptime Dwarf.uleb128Size(@backingInt(Dwarf.AbbrevCode.null)) * 2,
7332 }), .{ .unit_debug_info_footer = ui }),
7333 );
7334 },
7335 }
7336 switch (elf.shndx.debug_line) {
7337 .UNDEF => {},
7338 else => |debug_line_shndx| {
7339 const debug_line_ni = unit.debug_line_ni.unwrap() orelse debug_line_ni: {
7340 const debug_line_ni = elf.addNodeAssumeCapacity(
7341 try debug_line_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{
7342 .alignment = elf.mf.flags.block_size,
7343 .enable_next_moved = true,
7344 }),
7345 .{ .unit_debug_line = ui },
7346 );
7347 unit.debug_line_ni = .wrap(debug_line_ni);
7348 break :debug_line_ni debug_line_ni;
7349 };
7350 if (unit.debug_line_header_ni == .none) unit.debug_line_header_ni = .wrap(
7351 elf.addNodeAssumeCapacity(try debug_line_ni.addOnlyHeaderChild(gpa, &elf.mf, .{
7352 // Idle tasks are going to try to keep this up to date before we are able to
7353 // write out the full header, so just reserve space for them to do so.
7354 .size = elf.dwarf.unitLengthSize(),
7355 .enable_next_moved = true,
7356 }), .{ .unit_debug_line_header = ui }),
7357 );
7358 },
7359 }
7360 switch (elf.shndx.debug_rnglists) {
7361 .UNDEF => {},
7362 else => |debug_rnglists_shndx| {
7363 const debug_rnglists_ni = unit.debug_rnglists_ni.unwrap() orelse debug_rnglists_ni: {
7364 const debug_rnglists_ni = elf.addNodeAssumeCapacity(
7365 try debug_rnglists_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{
7366 .next_moved = true,
7367 .enable_next_moved = true,
7368 }),
7369 .{ .unit_debug_rnglists = ui },
7370 );
7371 unit.debug_rnglists_ni = .wrap(debug_rnglists_ni);
7372 break :debug_rnglists_ni debug_rnglists_ni;
7373 };
7374
7375 var drh_nw: MappedFile.Node.Writer = undefined;
7376 debug_rnglists_ni.writer(gpa, &elf.mf, &drh_nw);
7377 defer drh_nw.deinit();
7378 elf.dwarf.genDebugRnglistsHeader(unit, &drh_nw) catch |err| switch (err) {
7379 else => |e| return e,
7380 error.WriteFailed => return drh_nw.err.?,
7381 };
7382 },
7383 }
6478 }7384 }
7385 for (0..units_len) |unit_index| {
7386 const ui: Dwarf.Unit.Index = @fromBackingInt(@intCast(unit_index));
7387 const unit = ui.get(&elf.dwarf);
7388 if (unit.debug_info_header_ni == .none) continue;
7389 var dih_nw: MappedFile.Node.Writer = undefined;
7390 const debug_info_header_ni = unit.debug_info_header_ni.unwrap().?;
7391 debug_info_header_ni.writer(gpa, &elf.mf, &dih_nw);
7392 defer dih_nw.deinit();
7393 elf.resetNodeRelocs(debug_info_header_ni);
7394 elf.dwarf.genDebugInfoHeader(zcu, ui.mod(&elf.dwarf), unit, &dih_nw) catch |err| switch (err) {
7395 else => |e| return e,
7396 error.WriteFailed => return dih_nw.err.?,
7397 };
7398 }
7399}
7400
7401fn flushFiles(elf: *Elf) Error!void {
7402 const gpa = elf.base.comp.gpa;
7403 if (elf.shndx.debug_line != .UNDEF) for (elf.dwarf.units) |*unit| {
7404 if (!unit.cleanDebugLineHeaderChanged()) continue;
7405 assert(unit.alive);
7406 const debug_line_header_ni = unit.debug_line_header_ni.unwrap().?;
7407 try debug_line_header_ni.parent(&elf.mf).unwrap().?.nextMoved(gpa, &elf.mf);
7408 try debug_line_header_ni.moved(gpa, &elf.mf);
7409 try debug_line_header_ni.nextMoved(gpa, &elf.mf);
7410 var dlh_nw: MappedFile.Node.Writer = undefined;
7411 debug_line_header_ni.writer(gpa, &elf.mf, &dlh_nw);
7412 defer dlh_nw.deinit();
7413 elf.resetNodeRelocs(debug_line_header_ni);
7414 elf.dwarf.genDebugLineHeader(unit, &dlh_nw, elf.base.comp.zcu.?) catch |err| switch (err) {
7415 else => |e| return e,
7416 error.WriteFailed => return dlh_nw.err.?,
7417 };
7418 };
6479}7419}
64807420
6481fn prepareDynamic(elf: *Elf) Error!void {7421fn prepareDynamic(elf: *Elf) Error!void {
...@@ -6500,7 +7440,7 @@ fn prepareDynamic(elf: *Elf) Error!void {...@@ -6500,7 +7440,7 @@ fn prepareDynamic(elf: *Elf) Error!void {
65007440
6501 const dynamic_size = dynamic_len * 2 * elf.targetPtrSize();7441 const dynamic_size = dynamic_len * 2 * elf.targetPtrSize();
65027442
6503 try elf.shndx.dynamic.get(elf).ni.resizeLeaf(&elf.mf, comp.gpa, dynamic_size);7443 try elf.shndx.dynamic.get(elf).ni.resizeLeaf(comp.gpa, &elf.mf, dynamic_size);
6504 switch (elf.shdrPtr(elf.shndx.dynamic)) {7444 switch (elf.shdrPtr(elf.shndx.dynamic)) {
6505 inline else => |shdr| elf.targetStore(&shdr.size, @intCast(dynamic_size)),7445 inline else => |shdr| elf.targetStore(&shdr.size, @intCast(dynamic_size)),
6506 }7446 }
...@@ -6610,7 +7550,7 @@ fn flushDynamic(elf: *Elf) void {...@@ -6610,7 +7550,7 @@ fn flushDynamic(elf: *Elf) void {
6610 dynamic_index += 9;7550 dynamic_index += 9;
66117551
6612 assert(dynamic_index == dynamic_entries.len);7552 assert(dynamic_index == dynamic_entries.len);
6613 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|7553 if (elf.targetEndian() != std.lang.Endian.native) for (dynamic_entries) |*dynamic_entry|
6614 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);7554 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);
6615 },7555 },
6616 }7556 }
...@@ -6626,6 +7566,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -6626,6 +7566,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
6626 addralign: Alignment = .@"1",7566 addralign: Alignment = .@"1",
6627 entsize: std.elf.Word = 0,7567 entsize: std.elf.Word = 0,
6628 node_align: Alignment = .@"1",7568 node_align: Alignment = .@"1",
7569 manual_size: bool = false,
6629}) Error!Section.Index {7570}) Error!Section.Index {
6630 switch (opts.type) {7571 switch (opts.type) {
6631 .NULL => assert(opts.size == 0),7572 .NULL => assert(opts.size == 0),
...@@ -6639,7 +7580,11 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -6639,7 +7580,11 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
6639 const gpa = elf.base.comp.gpa;7580 const gpa = elf.base.comp.gpa;
6640 try elf.nodes.ensureUnusedCapacity(gpa, 1);7581 try elf.nodes.ensureUnusedCapacity(gpa, 1);
6641 try elf.shdrs.ensureUnusedCapacity(gpa, 1);7582 try elf.shdrs.ensureUnusedCapacity(gpa, 1);
6642 if (opts.flags.ALLOC) try elf.ensureUnusedSymbolCapacity(1, .all_local);7583 const want_symbol = opts.flags.ALLOC or switch (opts.type) {
7584 .NULL, .PROGBITS, .NOBITS, .X86_64_UNWIND => elf.ehdrType() == .REL,
7585 else => false,
7586 };
7587 if (want_symbol) try elf.ensureUnusedSymbolCapacity(1, .all_local);
66437588
6644 const shstrtab_entry = try elf.string(.shstrtab, opts.name);7589 const shstrtab_entry = try elf.string(.shstrtab, opts.name);
6645 const shndx: Section.Index, const new_shdr_size = shndx: switch (elf.ehdrPtr()) {7590 const shndx: Section.Index, const new_shdr_size = shndx: switch (elf.ehdrPtr()) {
...@@ -6669,32 +7614,38 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -6669,32 +7614,38 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
6669 break :shndx .{ @fromBackingInt(shndx), @as(u64, elf.targetLoad(&ehdr.shentsize)) * @as(u64, shnum) };7614 break :shndx .{ @fromBackingInt(shndx), @as(u64, elf.targetLoad(&ehdr.shentsize)) * @as(u64, shnum) };
6670 },7615 },
6671 };7616 };
6672 try elf.ni.shdr.ensureMinimumSize(&elf.mf, gpa, new_shdr_size);7617 try elf.ni.shdr.ensureMinimumSize(gpa, &elf.mf, new_shdr_size);
6673 const parent_ni = switch (elf.ehdrType()) {7618 const parent_ni = switch (elf.ehdrType()) {
6674 .REL => elf.ni.elf,7619 .REL => elf.ni.elf,
6675 .EXEC, .DYN => segment_ni,7620 .EXEC, .DYN => segment_ni,
6676 };7621 };
6677 assert(opts.addralign.check(opts.size));7622 assert(opts.addralign.check(opts.size));
6678 const ni = try parent_ni.addFloatingChild(&elf.mf, gpa, .{7623 const ni = elf.addNodeAssumeCapacity(try parent_ni.addFloatingChild(gpa, &elf.mf, .{
6679 .size = opts.node_align.forward(opts.size),7624 .size = opts.node_align.forward(opts.size),
6680 .alignment = opts.addralign.max(opts.node_align),7625 .alignment = opts.addralign.max(opts.node_align),
6681 .resized = opts.size > 0,7626 .resized = opts.size > 0,
7627 .bubbles_moved = opts.flags.ALLOC,
7628 }), switch (opts.manual_size) {
7629 false => .{ .section = shndx },
7630 true => .{ .section_manual_size = shndx },
6682 });7631 });
6683 const addr = elf.computeNodeVAddr(ni);7632 const addr = elf.computeNodeVAddr(ni);
6684 const lsi: Symbol.LocalIndex = if (opts.flags.ALLOC) elf.addLocalSymbolAssumeCapacity(.{7633 elf.shdrs.appendAssumeCapacity(.{
6685 .node = .wrap(ni),7634 .lsi = if (want_symbol) elf.addLocalSymbolAssumeCapacity(.{
6686 .name = .empty,7635 .node = ni.toOptional(),
6687 .value = addr,7636 .name = .empty,
6688 .size = 0,7637 .value = addr,
6689 .type = .SECTION,7638 .size = 0,
6690 .shndx = shndx,7639 .type = .SECTION,
6691 }) else .null;7640 .shndx = shndx,
6692 elf.shdrs.appendAssumeCapacity(.{ .lsi = lsi, .ni = ni, .rela = switch (opts.type) {7641 }) else .null,
6693 .REL => unreachable,7642 .ni = ni,
6694 .RELA => .{ .free_head = .none },7643 .rela = switch (opts.type) {
6695 else => .{ .shndx = .UNDEF },7644 .REL => unreachable,
6696 } });7645 .RELA => .{ .free_head = .none },
6697 elf.nodes.appendAssumeCapacity(.{ .section = shndx });7646 else => .{ .shndx = .UNDEF },
7647 },
7648 });
6698 switch (elf.shdrPtr(shndx)) {7649 switch (elf.shdrPtr(shndx)) {
6699 inline else => |shdr, class| {7650 inline else => |shdr, class| {
6700 shdr.* = .{7651 shdr.* = .{
...@@ -6702,14 +7653,14 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -6702,14 +7653,14 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
6702 .type = opts.type,7653 .type = opts.type,
6703 .flags = .{ .shf = opts.flags },7654 .flags = .{ .shf = opts.flags },
6704 .addr = @intCast(addr),7655 .addr = @intCast(addr),
6705 .offset = @intCast(elf.getNodeElfOffset(ni)),7656 .offset = @intCast(elf.computeNodeElfOffset(ni)),
6706 .size = @intCast(opts.size),7657 .size = @intCast(opts.size),
6707 .link = opts.link,7658 .link = opts.link,
6708 .info = opts.info,7659 .info = opts.info,
6709 .addralign = @intCast(opts.addralign.toByteUnits()),7660 .addralign = @intCast(opts.addralign.toByteUnits()),
6710 .entsize = opts.entsize,7661 .entsize = opts.entsize,
6711 };7662 };
6712 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr);7663 if (elf.targetEndian() != std.lang.Endian.native) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr);
6713 },7664 },
6714 }7665 }
6715 return shndx;7666 return shndx;
...@@ -6719,6 +7670,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)...@@ -6719,6 +7670,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
6719 if (len == 0) return;7670 if (len == 0) return;
6720 const gpa = elf.base.comp.gpa;7671 const gpa = elf.base.comp.gpa;
6721 try elf.symbol_relocs.ensureUnusedCapacity(gpa, len);7672 try elf.symbol_relocs.ensureUnusedCapacity(gpa, len);
7673 try elf.node_relocs.ensureUnusedCapacity(gpa, len);
6722 try elf.got_relocs.ensureUnusedCapacity(gpa, len);7674 try elf.got_relocs.ensureUnusedCapacity(gpa, len);
6723 const class = elf.identClass();7675 const class = elf.identClass();
6724 switch (elf.ehdrType()) {7676 switch (elf.ehdrType()) {
...@@ -6749,6 +7701,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)...@@ -6749,6 +7701,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
6749 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),7701 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
6750 },7702 },
6751 .node_align = elf.mf.flags.block_size,7703 .node_align = elf.mf.flags.block_size,
7704 .manual_size = true,
6752 });7705 });
6753 elf.section_by_name.putAssumeCapacityNoClobber(rela_shndx.name(elf), {});7706 elf.section_by_name.putAssumeCapacityNoClobber(rela_shndx.name(elf), {});
6754 shndx.get(elf).rela.shndx = rela_shndx;7707 shndx.get(elf).rela.shndx = rela_shndx;
...@@ -6763,7 +7716,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)...@@ -6763,7 +7716,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
6763 .NONE, _ => unreachable,7716 .NONE, _ => unreachable,
6764 inline else => |ct_class| (elf.got.count() + new_got_entries) * @sizeOf(ct_class.ElfN().Addr),7717 inline else => |ct_class| (elf.got.count() + new_got_entries) * @sizeOf(ct_class.ElfN().Addr),
6765 };7718 };
6766 try elf.shndx.got.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_got_size);7719 try elf.shndx.got.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_got_size);
67677720
6768 if (elf.shndx.dynamic != .UNDEF) {7721 if (elf.shndx.dynamic != .UNDEF) {
6769 try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, new_got_entries);7722 try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, new_got_entries);
...@@ -6795,17 +7748,12 @@ fn addRelocAssumeCapacity(...@@ -6795,17 +7748,12 @@ fn addRelocAssumeCapacity(
6795 .addend = addend,7748 .addend = addend,
6796 });7749 });
6797 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));7750 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
6798 const next: SymbolReloc.Index = next: {7751 const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc;
6799 const target_ptr = target.index(elf).ptr(elf);7752 const next = first_target_reloc.*;
6800 const next = target_ptr.first_target_reloc;7753 first_target_reloc.* = ri;
6801 target_ptr.first_target_reloc = ri;7754 if (next != .none) next.get(elf).prev = ri;
6802 break :next next;
6803 };
6804 if (next != .none) {
6805 next.get(elf).prev = ri;
6806 }
6807 elf.symbol_relocs.appendAssumeCapacity(.{7755 elf.symbol_relocs.appendAssumeCapacity(.{
6808 .node = node,7756 .node = node.toOptional(),
6809 .offset = offset,7757 .offset = offset,
6810 .type = undefined,7758 .type = undefined,
6811 .target = target,7759 .target = target,
...@@ -6816,7 +7764,6 @@ fn addRelocAssumeCapacity(...@@ -6816,7 +7764,6 @@ fn addRelocAssumeCapacity(
6816 .result = .ok,7764 .result = .ok,
6817 });7765 });
6818 },7766 },
6819
6820 .DYN, .EXEC => switch (elf.ehdrMachine()) {7767 .DYN, .EXEC => switch (elf.ehdrMachine()) {
6821 .AARCH64 => switch (@"type".AARCH64) {7768 .AARCH64 => switch (@"type".AARCH64) {
6822 .NONE => {},7769 .NONE => {},
...@@ -7239,14 +8186,12 @@ fn addSymbolRelocAssumeCapacity(...@@ -7239,14 +8186,12 @@ fn addSymbolRelocAssumeCapacity(
7239 };8186 };
72408187
7241 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));8188 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
7242 const target_ptr = target.index(elf).ptr(elf);8189 const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc;
7243 const next = target_ptr.first_target_reloc;8190 const next = first_target_reloc.*;
7244 target_ptr.first_target_reloc = ri;8191 first_target_reloc.* = ri;
7245 if (next != .none) {8192 if (next != .none) next.get(elf).prev = ri;
7246 next.get(elf).prev = ri;
7247 }
7248 elf.symbol_relocs.appendAssumeCapacity(.{8193 elf.symbol_relocs.appendAssumeCapacity(.{
7249 .node = node,8194 .node = node.toOptional(),
7250 .offset = offset,8195 .offset = offset,
7251 .target = target,8196 .target = target,
7252 .addend = addend,8197 .addend = addend,
...@@ -7263,6 +8208,103 @@ fn addSymbolRelocAssumeCapacity(...@@ -7263,6 +8208,103 @@ fn addSymbolRelocAssumeCapacity(
7263 // Actually apply the new relocation!8208 // Actually apply the new relocation!
7264 ri.get(elf).apply(elf);8209 ri.get(elf).apply(elf);
7265}8210}
8211fn addNodeRelocAssumeCapacity(
8212 elf: *Elf,
8213 node: MappedFile.Node.Index,
8214 offset: u64,
8215 target: MappedFile.Node.Index,
8216 addend: i64,
8217 @"type": NodeReloc.Type,
8218) Error!void {
8219 const shndx = elf.getNodeShndx(target);
8220 assert(!shndx.flags(elf).ALLOC); // not yet needed so not implemented
8221 const first_target_reloc = switch (elf.getNode(target)) {
8222 else => unreachable,
8223 .debug_shared => |ss| &elf.dwarf_shared.getPtr(ss).first_target_reloc,
8224 .unit_frame_cie => |ui| &elf.dwarf_units[@backingInt(ui)].frame_cie_first_target_reloc,
8225 .unit_debug_info_header => |ui| &elf.dwarf_units[@backingInt(ui)].debug_info_header_first_target_reloc,
8226 .unit_debug_line_header => |ui| &elf.dwarf_units[@backingInt(ui)].debug_line_header_first_target_reloc,
8227 .unit_debug_rnglists => |ui| &elf.dwarf_units[@backingInt(ui)].debug_rnglists_first_target_reloc,
8228 .const_debug_info => |cpi| &elf.dwarf_consts.getPtr(cpi).?.debug_info_first_target_reloc,
8229 .global_debug_info => |gi| &elf.dwarf_globals.items[@backingInt(gi)].debug_info_first_target_reloc,
8230 .func_debug_info => |fi| &elf.dwarf_funcs.items[@backingInt(fi)].debug_info_first_target_reloc,
8231 .decl_debug_info => |di| &elf.dwarf_decls.getPtr(di).?.debug_info_first_target_reloc,
8232 };
8233 const next = first_target_reloc.*;
8234 const ri: NodeReloc.Index = @fromBackingInt(@intCast(elf.node_relocs.items.len));
8235 first_target_reloc.* = ri;
8236 if (next != .none) next.get(elf).prev = ri;
8237 switch (elf.ehdrType()) {
8238 .REL => {
8239 const rela_shndx = elf.getNodeShndx(node).get(elf).rela.shndx;
8240 const rela_index = rela_shndx.relaAddOneAssumeCapacity(elf, .{
8241 .type = switch (elf.ehdrMachine()) {
8242 .AARCH64 => .{ .AARCH64 = switch (@"type") {
8243 .abs32 => .ABS32,
8244 .abs64 => .ABS64,
8245 } },
8246 .LOONGARCH => .{ .LARCH = switch (@"type") {
8247 .abs32 => .@"32",
8248 .abs64 => .@"64",
8249 } },
8250 .PPC64 => .{ .PPC64 = switch (@"type") {
8251 .abs32 => .ADDR32,
8252 .abs64 => .ADDR64,
8253 } },
8254 .RISCV => .{ .RISCV = switch (@"type") {
8255 .abs32 => .@"32",
8256 .abs64 => .@"64",
8257 } },
8258 .SPARCV9 => .{ .SPARC = switch (@"type") {
8259 .abs32 => .UA32,
8260 .abs64 => .UA64,
8261 } },
8262 .X86_64 => .{ .X86_64 = switch (@"type") {
8263 .abs32 => .@"32",
8264 .abs64 => .@"64",
8265 } },
8266 },
8267 // This field needs to equal the offset into the section, which is *not* necessarily
8268 // the same thing as our `offset`, which is the offset into `node`. We could compute
8269 // the section offset now, but there's no point, because `flushMovedNodeRelocs` will
8270 // eventually do it for us anyway, so just init to 0.
8271 .offset = 0,
8272 .raw_sym_index = @backingInt(switch (shndx.get(elf).lsi) {
8273 .null => unreachable,
8274 else => |lsi| lsi.index(),
8275 }),
8276 .addend = 0,
8277 });
8278 elf.node_relocs.appendAssumeCapacity(.{
8279 .node = node.toOptional(),
8280 .offset = offset,
8281 .type = undefined,
8282 .target = target,
8283 .addend = addend,
8284 .next = next,
8285 .prev = .none,
8286 .rela_index = rela_index.toOptional(),
8287 .result = .ok,
8288 });
8289 },
8290 .DYN, .EXEC => {
8291 elf.node_relocs.appendAssumeCapacity(.{
8292 .node = node.toOptional(),
8293 .offset = offset,
8294 .target = target,
8295 .addend = addend,
8296 .type = @"type",
8297 .next = next,
8298 .prev = .none,
8299 .rela_index = .none,
8300 .result = .ok,
8301 });
8302
8303 // Actually apply the new relocation!
8304 ri.get(elf).apply(elf);
8305 },
8306 }
8307}
7266fn addGotRelocAssumeCapacity(8308fn addGotRelocAssumeCapacity(
7267 elf: *Elf,8309 elf: *Elf,
7268 node: MappedFile.Node.Index,8310 node: MappedFile.Node.Index,
...@@ -7273,6 +8315,7 @@ fn addGotRelocAssumeCapacity(...@@ -7273,6 +8315,7 @@ fn addGotRelocAssumeCapacity(
7273) void {8315) void {
7274 assert(elf.ehdrType() != .REL);8316 assert(elf.ehdrType() != .REL);
7275 switch (elf.getNode(node)) {8317 switch (elf.getNode(node)) {
8318 .deleted,
7276 .archive,8319 .archive,
7277 .archive_header,8320 .archive_header,
7278 .archive_input_member,8321 .archive_input_member,
...@@ -7282,8 +8325,26 @@ fn addGotRelocAssumeCapacity(...@@ -7282,8 +8325,26 @@ fn addGotRelocAssumeCapacity(
7282 .shdr,8325 .shdr,
7283 .segment,8326 .segment,
7284 .copied_global,8327 .copied_global,
8328 .debug_shared,
8329 .eh_frame_footer,
8330 .unit_padding,
8331 .unit_frame,
8332 .unit_frame_cie,
8333 .unit_debug_info,
8334 .unit_debug_info_header,
8335 .unit_debug_info_footer,
8336 .unit_debug_line,
8337 .unit_debug_line_header,
8338 .unit_debug_rnglists,
8339 .const_debug_info,
8340 .global_debug_info,
8341 .func_frame_fde,
8342 .func_debug_info,
8343 .func_debug_line,
8344 .decl_debug_info,
7285 => unreachable, // cannot contain relocs,8345 => unreachable, // cannot contain relocs,
7286 .section,8346 .section,
8347 .section_manual_size,
7287 .uav,8348 .uav,
7288 => unreachable, // cannot contain GOT relocs8349 => unreachable, // cannot contain GOT relocs
7289 .input_section,8350 .input_section,
...@@ -7519,14 +8580,13 @@ fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool {...@@ -7519,14 +8580,13 @@ fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool {
7519 try Section.Index.data.ensureAligned(elf, dso_global.alignment);8580 try Section.Index.data.ensureAligned(elf, dso_global.alignment);
75208581
7521 try elf.nodes.ensureUnusedCapacity(gpa, 1);8582 try elf.nodes.ensureUnusedCapacity(gpa, 1);
7522 const node = try Section.Index.data.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{8583 const node = try Section.Index.data.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{
7523 .size = dso_global.alignment.forward(dso_global.size),8584 .size = dso_global.alignment.forward(dso_global.size),
7524 .alignment = dso_global.alignment,8585 .alignment = dso_global.alignment,
7525 });8586 });
7526 errdefer comptime unreachable;8587 errdefer comptime unreachable;
75278588
7528 const vaddr = elf.computeNodeVAddr(node);8589 const vaddr = elf.computeNodeVAddr(node);
7529 elf.nodes.appendAssumeCapacity(.{ .copied_global = global_name });
7530 const rela_index = elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{8590 const rela_index = elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{
7531 .type = .copy(elf),8591 .type = .copy(elf),
7532 .offset = vaddr,8592 .offset = vaddr,
...@@ -7555,10 +8615,12 @@ fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool {...@@ -7555,10 +8615,12 @@ fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool {
7555}8615}
75568616
7557pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void {8617pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void {
7558 const diags = &elf.base.comp.link_diags;
7559 elf.updateNavInner(pt, nav_index) catch |err| switch (err) {8618 elf.updateNavInner(pt, nav_index) catch |err| switch (err) {
7560 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
7561 else => |e| return e,8619 else => |e| return e,
8620 error.MappedFileIo => return elf.base.comp.link_diags.fail(
8621 "failed to write output file: {t}",
8622 .{elf.mf.io_err.?},
8623 ),
7562 };8624 };
7563}8625}
7564fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) Error!void {8626fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) Error!void {
...@@ -7568,11 +8630,14 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -7568,11 +8630,14 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
75688630
7569 const nav = ip.getNav(nav_index);8631 const nav = ip.getNav(nav_index);
7570 if (ip.indexToKey(nav.resolved.?.value) == .@"extern") return;8632 if (ip.indexToKey(nav.resolved.?.value) == .@"extern") return;
7571 if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return;8633 if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) {
8634 if (elf.ehdrMachine() != .X86_64) return;
8635 const mod = zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?;
8636 return if (!mod.strip) elf.dwarf.updateComptimeNav(pt, nav_index);
8637 }
75728638
7573 const nmi = try elf.navMapIndex(zcu, nav_index);8639 const nmi = try elf.navMapIndex(zcu, nav_index);
7574 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;8640 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;
7575 elf.resetNodeRelocs(ni);
75768641
7577 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be8642 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
7578 // called to apply the NAV's new relocations.8643 // called to apply the NAV's new relocations.
...@@ -7580,8 +8645,9 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -7580,8 +8645,9 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
75808645
7581 {8646 {
7582 var nw: MappedFile.Node.Writer = undefined;8647 var nw: MappedFile.Node.Writer = undefined;
7583 ni.writer(&elf.mf, gpa, &nw);8648 ni.writer(gpa, &elf.mf, &nw);
7584 defer nw.deinit();8649 defer nw.deinit();
8650 elf.resetNodeRelocs(ni);
7585 codegen.generateSymbol(8651 codegen.generateSymbol(
7586 &elf.base,8652 &elf.base,
7587 pt,8653 pt,
...@@ -7589,16 +8655,153 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -7589,16 +8655,153 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
7589 &nw.interface,8655 &nw.interface,
7590 .{ .atom_index = Node.toAtom(ni) },8656 .{ .atom_index = Node.toAtom(ni) },
7591 ) catch |err| switch (err) {8657 ) catch |err| switch (err) {
7592 error.WriteFailed => return nw.err.?,
7593 else => |e| return e,8658 else => |e| return e,
8659 error.WriteFailed => return nw.err.?,
7594 };8660 };
7595 switch (elf.symPtr(nmi.symbol(elf).index())) {8661 switch (elf.symPtr(nmi.symbol(elf).index())) {
7596 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),8662 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
7597 }8663 }
7598 }8664 }
75998665
7600 // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs.8666 // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs.
7601 try elf.genPending(pt);8667 try elf.genPending(pt);
8668 try elf.dwarf.const_pool.flushPending(pt, .{ .elf2 = elf });
8669}
8670
8671pub fn updateContainerType(
8672 elf: *Elf,
8673 pt: Zcu.PerThread,
8674 ty: InternPool.Index,
8675 success: bool,
8676) link.Error!void {
8677 elf.updateContainerTypeInner(pt, ty, success) catch |err| switch (err) {
8678 else => |e| return e,
8679 error.MappedFileIo => return elf.base.comp.link_diags.fail(
8680 "failed to write output file: {t}",
8681 .{elf.mf.io_err.?},
8682 ),
8683 };
8684}
8685pub fn updateContainerTypeInner(
8686 elf: *Elf,
8687 pt: Zcu.PerThread,
8688 ty: InternPool.Index,
8689 success: bool,
8690) Error!void {
8691 switch (elf.base.comp.config.debug_format) {
8692 .strip => {},
8693 .dwarf => {
8694 try elf.dwarf.const_pool.updateContainerType(pt, .{ .elf2 = elf }, ty, success);
8695 try elf.dwarf.const_pool.flushPending(pt, .{ .elf2 = elf });
8696 },
8697 .code_view => unreachable,
8698 }
8699 if (!success) return;
8700 var lazy_it = elf.lazy.iterator();
8701 while (lazy_it.next()) |lazy| if (lazy.value.map.getIndex(ty)) |lmi| {
8702 if (lazy.value.pending_index <= lmi) continue;
8703 // This type has changed on this incremental update, so update the lazy code/data.
8704 try elf.genLazy(pt, .{ .kind = lazy.key, .index = @intCast(lmi) });
8705 };
8706}
8707
8708pub fn addConst(
8709 elf: *Elf,
8710 _: Zcu.PerThread,
8711 cpi: link.ConstPool.Index,
8712 val: InternPool.Index,
8713) link.Error!void {
8714 switch (elf.base.comp.config.debug_format) {
8715 .strip => {},
8716 .dwarf => {
8717 const gpa = elf.base.comp.gpa;
8718 try elf.nodes.ensureUnusedCapacity(gpa, 1);
8719 try elf.dwarf.consts.ensureUnusedCapacity(gpa, 1);
8720 try elf.dwarf_consts.ensureUnusedCapacity(gpa, 1);
8721 try elf.dwarf.addConst(cpi, val, &addConstNode);
8722 },
8723 .code_view => unreachable,
8724 }
8725}
8726fn addConstNode(lf: *link.File, ui: Dwarf.Unit.Index, cpi: link.ConstPool.Index) link.Error!MappedFile.Node.Index {
8727 const elf = lf.cast(.elf2).?;
8728 const unit = ui.get(&elf.dwarf);
8729 const debug_info_ni = elf.addNodeAssumeCapacity(
8730 unit.debug_info_ni.unwrap().?.addFloatingChild(lf.comp.gpa, &elf.mf, .{
8731 .enable_next_moved = true,
8732 }) catch |err| switch (err) {
8733 else => |e| return e,
8734 error.MappedFileIo => return lf.comp.link_diags.fail("failed to write output file: {t}", .{
8735 elf.mf.io_err.?,
8736 }),
8737 },
8738 .{ .const_debug_info = cpi },
8739 );
8740 elf.dwarf_consts.putAssumeCapacityNoClobber(cpi, .{
8741 .debug_info_first_target_reloc = .none,
8742 .debug_info_first_symbol_reloc = .none,
8743 .debug_info_first_node_reloc = .none,
8744 });
8745 return debug_info_ni;
8746}
8747
8748pub fn updateConst(
8749 elf: *Elf,
8750 pt: Zcu.PerThread,
8751 cpi: link.ConstPool.Index,
8752 val: InternPool.Index,
8753) link.Error!void {
8754 switch (val) {
8755 .anyerror_type => {}, // handled in `updateErrorData` instead
8756 else => try elf.updateConstInner(pt, cpi, val, .complete),
8757 }
8758}
8759fn updateConstInner(
8760 elf: *Elf,
8761 pt: Zcu.PerThread,
8762 cpi: link.ConstPool.Index,
8763 val: InternPool.Index,
8764 complete: enum { incomplete, complete },
8765) link.Error!void {
8766 switch (elf.base.comp.config.debug_format) {
8767 .strip => {},
8768 .dwarf => {
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 }
8780 const gpa = elf.base.comp.gpa;
8781 const debug_info_ni = Dwarf.Const.get(cpi, &elf.dwarf).debug_info_ni.unwrap().?;
8782 try debug_info_ni.moved(gpa, &elf.mf);
8783 var di_nw: MappedFile.Node.Writer = undefined;
8784 debug_info_ni.writer(gpa, &elf.mf, &di_nw);
8785 defer di_nw.deinit();
8786 elf.resetNodeRelocs(debug_info_ni);
8787 switch (complete) {
8788 .incomplete => try elf.dwarf.updateConstIncomplete(pt, &di_nw, val),
8789 .complete => try elf.dwarf.updateConst(pt, &di_nw, val),
8790 }
8791 }
8792 try elf.genPending(pt);
8793 },
8794 .code_view => unreachable,
8795 }
8796}
8797
8798pub fn updateConstIncomplete(
8799 elf: *Elf,
8800 pt: Zcu.PerThread,
8801 cpi: link.ConstPool.Index,
8802 val: InternPool.Index,
8803) link.Error!void {
8804 return elf.updateConstInner(pt, cpi, val, .incomplete);
7602}8805}
76038806
7604pub fn updateFunc(8807pub fn updateFunc(
...@@ -7607,10 +8810,12 @@ pub fn updateFunc(...@@ -7607,10 +8810,12 @@ pub fn updateFunc(
7607 func_index: InternPool.Index,8810 func_index: InternPool.Index,
7608 mir: *const codegen.AnyMir,8811 mir: *const codegen.AnyMir,
7609) link.Error!void {8812) link.Error!void {
7610 const diags = &elf.base.comp.link_diags;
7611 elf.updateFuncInner(pt, func_index, mir) catch |err| switch (err) {8813 elf.updateFuncInner(pt, func_index, mir) catch |err| switch (err) {
7612 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
7613 else => |e| return e,8814 else => |e| return e,
8815 error.MappedFileIo => return elf.base.comp.link_diags.fail(
8816 "failed to write output file: {t}",
8817 .{elf.mf.io_err.?},
8818 ),
7614 };8819 };
7615}8820}
7616fn updateFuncInner(8821fn updateFuncInner(
...@@ -7627,8 +8832,8 @@ fn updateFuncInner(...@@ -7627,8 +8832,8 @@ fn updateFuncInner(
76278832
7628 const nmi = try elf.navMapIndex(zcu, func.owner_nav);8833 const nmi = try elf.navMapIndex(zcu, func.owner_nav);
7629 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) });8834 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) });
7630 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;8835 const lsi = nmi.symbol(elf);
7631 elf.resetNodeRelocs(ni);8836 const ni = lsi.index().ptr(elf).node.unwrap().?;
76328837
7633 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be8838 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
7634 // called to apply the NAV's new relocations.8839 // called to apply the NAV's new relocations.
...@@ -7636,8 +8841,145 @@ fn updateFuncInner(...@@ -7636,8 +8841,145 @@ fn updateFuncInner(
76368841
7637 {8842 {
7638 var nw: MappedFile.Node.Writer = undefined;8843 var nw: MappedFile.Node.Writer = undefined;
7639 ni.writer(&elf.mf, gpa, &nw);8844 ni.writer(gpa, &elf.mf, &nw);
7640 defer nw.deinit();8845 defer nw.deinit();
8846 var debug_output_buf: Dwarf.WipNav.Debug = undefined;
8847 const debug_output: link.File.DebugInfoOutput, const dwarf_func = debug_output: {
8848 if (elf.ehdrMachine() != .X86_64) break :debug_output .{ .none, undefined };
8849 const dwarf = &elf.dwarf;
8850 const src_inst = nav.srcInst(ip);
8851 const mod = zcu.fileByIndex(src_inst.resolveFile(ip)).mod.?;
8852 if (mod.strip and mod.unwind_tables == .none) break :debug_output .{ .none, undefined };
8853
8854 try elf.nodes.ensureUnusedCapacity(gpa, 4);
8855 const dwarf_fi = try dwarf.getFunc(func.owner_nav);
8856
8857 const wip_nav = &debug_output_buf.wip_nav;
8858 wip_nav.* = .{
8859 .dwarf = dwarf,
8860 .unit = dwarf.getUnit(mod),
8861 .func = func_index,
8862 .func_si = Symbol.Id.local(lsi).toTypeErased(),
8863 .cfi = .{
8864 .loc = 0,
8865 .cfa = dwarf.frame.header.initial_instructions[0].def_cfa,
8866 },
8867 .frame_format = switch (mod.unwind_tables) {
8868 .none => .debug_frame,
8869 .sync, .async => .eh_frame,
8870 },
8871 .fde_writer = undefined,
8872 .frame_func_length = undefined,
8873 };
8874 const unit = wip_nav.unit.get(dwarf);
8875
8876 const frame_align: Alignment = switch (elf.identClass()) {
8877 .NONE, _ => unreachable,
8878 .@"32" => .@"4",
8879 .@"64" => .@"8",
8880 };
8881 const frame_ni = unit.frame_ni.unwrap() orelse frame_ni: {
8882 const frame_ni = elf.addNodeAssumeCapacity(try switch (wip_nav.frame_format) {
8883 .debug_frame => elf.shndx.debug_frame,
8884 .eh_frame => elf.shndx.eh_frame,
8885 }.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{
8886 .alignment = frame_align.max(elf.mf.flags.block_size),
8887 .enable_next_moved = true,
8888 }), .{ .unit_frame = wip_nav.unit });
8889 unit.frame_ni = .wrap(frame_ni);
8890 break :frame_ni frame_ni;
8891 };
8892 if (unit.cie_ni == .none) {
8893 const cie_ni = elf.addNodeAssumeCapacity(
8894 try frame_ni.addOnlyHeaderChild(gpa, &elf.mf, .{
8895 .alignment = frame_align,
8896 .next_moved = true,
8897 .enable_next_moved = true,
8898 }),
8899 .{ .unit_frame_cie = wip_nav.unit },
8900 );
8901 unit.cie_ni = .wrap(cie_ni);
8902 var cie_nw: MappedFile.Node.Writer = undefined;
8903 cie_ni.writer(gpa, &elf.mf, &cie_nw);
8904 defer cie_nw.deinit();
8905 dwarf.genDebugFrameCie(&cie_nw.interface, switch (elf.ehdrMachine()) {
8906 else => unreachable,
8907 .X86_64 => .x86_64,
8908 }, wip_nav.frame_format) catch |err| switch (err) {
8909 error.WriteFailed => return cie_nw.err.?,
8910 };
8911 }
8912 const dwarf_func = dwarf_fi.get(dwarf);
8913 const fde_ni = if (dwarf_func.fde_ni.unwrap()) |fde_ni| fde_ni: {
8914 try fde_ni.moved(gpa, &elf.mf);
8915 try fde_ni.nextMoved(gpa, &elf.mf);
8916 break :fde_ni fde_ni;
8917 } else fde_ni: {
8918 const fde_ni = elf.addNodeAssumeCapacity(try frame_ni.addFloatingChild(gpa, &elf.mf, .{
8919 .alignment = frame_align,
8920 .moved = true,
8921 .next_moved = true,
8922 .enable_next_moved = true,
8923 }), .{ .func_frame_fde = dwarf_fi });
8924 dwarf_func.fde_ni = .wrap(fde_ni);
8925 break :fde_ni fde_ni;
8926 };
8927 fde_ni.writer(gpa, &elf.mf, &wip_nav.fde_writer);
8928
8929 if (mod.strip) break :debug_output .{ .{ .eh_frame = wip_nav }, dwarf_func };
8930
8931 const debug = &debug_output_buf;
8932 debug.pt = pt;
8933 debug.any_children = false;
8934 debug.blocks = .empty;
8935 dwarf_func.state = .resolved;
8936
8937 const debug_info_ni = dwarf_func.debug_info_ni.unwrap().?;
8938 try dwarf.decls.put(zcu.comp.gpa, src_inst, .{
8939 .debug_info_ni = debug_info_ni.toOptional(),
8940 });
8941 try debug_info_ni.moved(gpa, &elf.mf);
8942 try debug_info_ni.nextMoved(gpa, &elf.mf);
8943 debug_info_ni.writer(gpa, &elf.mf, &debug.info_writer);
8944
8945 const debug_line_ni = dwarf_func.debug_line_ni.unwrap() orelse debug_line_ni: {
8946 const debug_line_ni = elf.addNodeAssumeCapacity(
8947 try unit.debug_line_ni.unwrap().?.addFloatingChild(gpa, &elf.mf, .{
8948 .moved = true,
8949 .next_moved = true,
8950 .enable_next_moved = true,
8951 }),
8952 .{ .func_debug_line = dwarf_fi },
8953 );
8954 dwarf_func.debug_line_ni = .wrap(debug_line_ni);
8955 break :debug_line_ni debug_line_ni;
8956 };
8957 debug_line_ni.writer(gpa, &elf.mf, &debug.line_writer);
8958
8959 break :debug_output .{ .{ .dwarf2 = debug }, dwarf_func };
8960 };
8961 defer switch (debug_output) {
8962 .dwarf => unreachable,
8963 inline .eh_frame, .dwarf2 => |dwarf| dwarf.deinit(),
8964 .none => {},
8965 };
8966 switch (debug_output) {
8967 .dwarf => unreachable,
8968 .eh_frame => |wip_nav| {
8969 elf.resetNodeRelocs(dwarf_func.fde_ni.unwrap().?);
8970 try wip_nav.genDebugFrameHeader();
8971 },
8972 .dwarf2 => |debug| {
8973 elf.resetNodeRelocs(dwarf_func.fde_ni.unwrap().?);
8974 try debug.wip_nav.genDebugFrameHeader();
8975 elf.resetNodeRelocs(dwarf_func.debug_line_ni.unwrap().?);
8976 try debug.startDebugLine();
8977 elf.resetNodeRelocs(dwarf_func.debug_info_ni.unwrap().?);
8978 try debug.startFuncDebugInfo();
8979 },
8980 .none => {},
8981 }
8982 elf.resetNodeRelocs(ni);
7641 codegen.emitFunction(8983 codegen.emitFunction(
7642 &elf.base,8984 &elf.base,
7643 pt,8985 pt,
...@@ -7645,29 +8987,101 @@ fn updateFuncInner(...@@ -7645,29 +8987,101 @@ fn updateFuncInner(
7645 Node.toAtom(ni),8987 Node.toAtom(ni),
7646 mir,8988 mir,
7647 &nw.interface,8989 &nw.interface,
7648 .none,8990 debug_output,
7649 ) catch |err| switch (err) {8991 ) catch |err| switch (err) {
7650 error.WriteFailed => return nw.err.?,
7651 else => |e| return e,8992 else => |e| return e,
8993 error.WriteFailed => if (nw.err) |e| return e,
7652 };8994 };
8995 const func_length = nw.interface.end;
7653 switch (elf.symPtr(nmi.symbol(elf).index())) {8996 switch (elf.symPtr(nmi.symbol(elf).index())) {
7654 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),8997 inline else => |sym| elf.targetStore(&sym.size, @intCast(func_length)),
8998 }
8999 switch (debug_output) {
9000 .dwarf => unreachable,
9001 .eh_frame => |wip_nav| wip_nav.finishDebugFrameFde(func_length),
9002 .dwarf2 => |debug| {
9003 try debug.finishFunc(func_length);
9004 const unit = debug.wip_nav.unit.get(debug.wip_nav.dwarf);
9005 {
9006 var dr_nw: MappedFile.Node.Writer = undefined;
9007 unit.debug_rnglists_ni.unwrap().?.writer(gpa, &elf.mf, &dr_nw);
9008 defer dr_nw.deinit();
9009 const first_symbol_reloc = elf.symbol_relocs.items.len;
9010 debug.wip_nav.dwarf.genDebugRnglists(
9011 unit,
9012 &dr_nw,
9013 debug.wip_nav.func_si,
9014 func_length,
9015 ) catch |err| switch (err) {
9016 else => |e| return e,
9017 error.WriteFailed => return dr_nw.err.?,
9018 };
9019 const symbol_relocs = &elf.dwarf_units[@backingInt(debug.wip_nav.unit)]
9020 .debug_rnglists_symbol_relocs;
9021 try symbol_relocs.ensureUnusedCapacity(gpa, elf.symbol_relocs.items.len -
9022 first_symbol_reloc);
9023 for (first_symbol_reloc..elf.symbol_relocs.items.len) |symbol_ri|
9024 symbol_relocs.putAssumeCapacityNoClobber(
9025 @fromBackingInt(@intCast(symbol_ri)),
9026 {},
9027 );
9028 }
9029 debug.wip_nav.finishDebugFrameFde(func_length);
9030 if (func.analysisUnordered(ip).inferred_error_set) {
9031 const ies = ip.getIfExists(.{ .inferred_error_set_type = func_index }).?;
9032 if (elf.dwarf.const_pool.getIfExists(ies)) |cpi|
9033 try elf.updateConstInner(pt, cpi, ies, .complete);
9034 }
9035 },
9036 .none => {},
7655 }9037 }
7656 }9038 }
76579039
7658 // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs.9040 // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs.
7659 try elf.genPending(pt);9041 try elf.genPending(pt);
9042 try elf.dwarf.const_pool.flushPending(pt, .{ .elf2 = elf });
7660}9043}
76619044
7662pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void {9045pub fn updateLineNumber(
7663 const diags = &elf.base.comp.link_diags;9046 elf: *Elf,
7664 elf.genLazy(pt, .{9047 _: Zcu.PerThread,
7665 .kind = .const_data,9048 inst: InternPool.TrackedInst.Index,
7666 .index = @intCast(elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return),9049 line: u32,
7667 }) catch |err| switch (err) {9050) void {
7668 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),9051 elf.dwarf.updateLineNumber(&elf.mf, inst, line);
9052}
9053
9054pub fn lostTracking(
9055 elf: *Elf,
9056 _: Zcu.PerThread,
9057 inst: InternPool.TrackedInst.Index,
9058) link.Error!void {
9059 const di = elf.dwarf.getDeclIfExists(inst) orelse return;
9060 const decl_ni = di.get(&elf.dwarf).debug_info_ni.unwrap() orelse return;
9061 const comp = elf.base.comp;
9062 var di_nw: MappedFile.Node.Writer = undefined;
9063 decl_ni.writer(comp.gpa, &elf.mf, &di_nw);
9064 defer di_nw.deinit();
9065 elf.resetNodeRelocs(decl_ni);
9066 elf.dwarf.lostTracking(&di_nw) catch |err| switch (err) {
7669 else => |e| return e,9067 else => |e| return e,
9068 error.WriteFailed => unreachable,
7670 };9069 };
9070 decl_ni.resizeLeaf(comp.gpa, &elf.mf, di_nw.interface.end) catch |err| switch (err) {
9071 else => |e| return e,
9072 error.MappedFileIo => return comp.link_diags.fail("failed to write output file: {t}", .{
9073 elf.mf.io_err.?,
9074 }),
9075 };
9076}
9077
9078pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void {
9079 if (elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type)) |lmi| try elf.genLazyInner(pt, .{
9080 .kind = .const_data,
9081 .index = @intCast(lmi),
9082 });
9083 if (elf.dwarf.const_pool.getIfExists(.anyerror_type)) |cpi|
9084 try elf.updateConstInner(pt, cpi, .anyerror_type, .complete);
7671}9085}
76729086
7673pub fn flush(9087pub fn flush(
...@@ -7677,8 +9091,11 @@ pub fn flush(...@@ -7677,8 +9091,11 @@ pub fn flush(
7677 prog_node: std.Progress.Node,9091 prog_node: std.Progress.Node,
7678) link.Error!void {9092) link.Error!void {
7679 elf.flushInner(arena, tid, prog_node) catch |err| switch (err) {9093 elf.flushInner(arena, tid, prog_node) catch |err| switch (err) {
7680 error.MappedFileIo => return elf.base.comp.link_diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
7681 else => |e| return e,9094 else => |e| return e,
9095 error.MappedFileIo => return elf.base.comp.link_diags.fail(
9096 "failed to write output file: {t}",
9097 .{elf.mf.io_err.?},
9098 ),
7682 };9099 };
7683}9100}
7684fn flushInner(9101fn flushInner(
...@@ -7694,6 +9111,8 @@ fn flushInner(...@@ -7694,6 +9111,8 @@ fn flushInner(
7694 const sub_prog_node = prog_node.start("ELF Flush", 0);9111 const sub_prog_node = prog_node.start("ELF Flush", 0);
7695 defer sub_prog_node.end();9112 defer sub_prog_node.end();
76969113
9114 try elf.flushFiles();
9115
7697 if (comp.config.output_mode == .Exe) {9116 if (comp.config.output_mode == .Exe) {
7698 var any_undef = false;9117 var any_undef = false;
7699 for (elf.globals.strong_undef.keys()) |name| {9118 for (elf.globals.strong_undef.keys()) |name| {
...@@ -7708,8 +9127,13 @@ fn flushInner(...@@ -7708,8 +9127,13 @@ fn flushInner(
77089127
7709 while (try elf.idle(tid)) {}9128 while (try elf.idle(tid)) {}
77109129
9130 assert(elf.pending_uavs.items.len == 0);
9131 assert(elf.dwarf.const_pool.pending.items.len == 0);
9132
7711 // We've done the final `idle` loop, so everything is at its final place in the file. We have a9133 // We've done the final `idle` loop, so everything is at its final place in the file. We have a
7712 // few more things to check and write now that addresses and offsets are finalized.9134 // few more things to check and write now that addresses and offsets are finalized.
9135 elf.mf.nodes_lock.lock();
9136 defer elf.mf.nodes_lock.unlock();
77139137
7714 if (elf.overflowed_reloc_count > 0) {9138 if (elf.overflowed_reloc_count > 0) {
7715 diags.addError("failed to apply {d} relocations: overflow", .{elf.overflowed_reloc_count});9139 diags.addError("failed to apply {d} relocations: overflow", .{elf.overflowed_reloc_count});
...@@ -7753,20 +9177,19 @@ fn flushInner(...@@ -7753,20 +9177,19 @@ fn flushInner(
77539177
7754 if (elf.options.enable_link_snapshots)9178 if (elf.options.enable_link_snapshots)
7755 elf.dumpStderr(tid) catch |err|9179 elf.dumpStderr(tid) catch |err|
7756 return comp.link_diags.fail("dumping link snapshot failed: {t}", .{err});9180 return diags.fail("dumping link snapshot failed: {t}", .{err});
7757}9181}
77589182
7759pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {9183pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {
7760 const comp = elf.base.comp;9184 // This function is called non-deterministically, and so must not affect the layout of any nodes.
7761 const diags = &comp.link_diags;
7762
7763 elf.mf.nodes_lock.lock();9185 elf.mf.nodes_lock.lock();
7764 defer elf.mf.nodes_lock.unlock();9186 defer elf.mf.nodes_lock.unlock();
77659187
9188 const comp = elf.base.comp;
9189 const diags = &comp.link_diags;
9190
7766 assert(elf.pending_uavs.items.len == 0);9191 assert(elf.pending_uavs.items.len == 0);
7767 for (&elf.lazy.values) |*lazy| {9192 assert(elf.dwarf.const_pool.pending.items.len == 0);
7768 assert(lazy.pending_index == lazy.map.count());
7769 }
77709193
7771 task: {9194 task: {
7772 if (elf.input_pending_index < elf.inputs.items.len) {9195 if (elf.input_pending_index < elf.inputs.items.len) {
...@@ -7775,8 +9198,8 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {...@@ -7775,8 +9198,8 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {
7775 const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(ii.node(elf)));9198 const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(ii.node(elf)));
7776 defer sub_prog_node.end();9199 defer sub_prog_node.end();
7777 elf.flushInput(ii) catch |err| switch (err) {9200 elf.flushInput(ii) catch |err| switch (err) {
7778 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
7779 else => |e| return e,9201 else => |e| return e,
9202 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
7780 };9203 };
7781 break :task;9204 break :task;
7782 }9205 }
...@@ -7786,8 +9209,8 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {...@@ -7786,8 +9209,8 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {
7786 const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.node(elf)));9209 const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.node(elf)));
7787 defer sub_prog_node.end();9210 defer sub_prog_node.end();
7788 elf.flushInputSection(isi) catch |err| switch (err) {9211 elf.flushInputSection(isi) catch |err| switch (err) {
7789 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
7790 else => |e| return e,9212 else => |e| return e,
9213 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
7791 };9214 };
7792 break :task;9215 break :task;
7793 }9216 }
...@@ -7885,18 +9308,18 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {...@@ -7885,18 +9308,18 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {
78859308
7886 break :task;9309 break :task;
7887 }9310 }
7888 while (elf.mf.updates.pop()) |ni| {9311 while (elf.mf.updates.pop()) |ni| : (elf.mf.update_prog_node.completeOne()) {
9312 if (ni.pendingDelete(&elf.mf)) continue;
7889 const clean_moved = ni.cleanMoved(&elf.mf);9313 const clean_moved = ni.cleanMoved(&elf.mf);
7890 const clean_resized = ni.cleanResized(&elf.mf);9314 const clean_resized = ni.cleanResized(&elf.mf);
7891 const clean_next_moved = ni.cleanNextMoved(&elf.mf);9315 const clean_next_moved = ni.cleanNextMoved(&elf.mf);
7892 if (clean_moved or clean_resized or clean_next_moved) {9316 if (!clean_moved and !clean_resized and !clean_next_moved) continue;
7893 const sub_prog_node = elf.idleProgNode(tid, elf.mf.update_prog_node, elf.getNode(ni));9317 const sub_prog_node = elf.idleProgNode(tid, elf.mf.update_prog_node, elf.getNode(ni));
7894 defer sub_prog_node.end();9318 defer sub_prog_node.end();
7895 if (clean_moved) try elf.flushMoved(ni);9319 if (clean_moved) try elf.flushMoved(ni);
7896 if (clean_resized) try elf.flushResized(ni);9320 if (clean_resized) try elf.flushResized(ni);
7897 if (clean_next_moved) try elf.flushNextMoved(ni);9321 if (clean_moved or clean_resized or clean_next_moved) try elf.flushPadding(ni);
7898 break :task;9322 break :task;
7899 } else elf.mf.update_prog_node.completeOne();
7900 }9323 }
7901 }9324 }
7902 if (elf.input_sections.items.len > elf.input_section_pending_index) return true;9325 if (elf.input_sections.items.len > elf.input_section_pending_index) return true;
...@@ -7915,62 +9338,119 @@ fn idleProgNode(...@@ -7915,62 +9338,119 @@ fn idleProgNode(
7915 var name: [std.Progress.Node.max_name_len]u8 = undefined;9338 var name: [std.Progress.Node.max_name_len]u8 = undefined;
7916 return prog_node.start(name: switch (node) {9339 return prog_node.start(name: switch (node) {
7917 else => |tag| @tagName(tag),9340 else => |tag| @tagName(tag),
7918 .section => |shndx| shndx.name(elf).slice(elf),
7919 .archive_input_member => |ii| std.mem.print(&name, "{f}{f}", .{9341 .archive_input_member => |ii| std.mem.print(&name, "{f}{f}", .{
7920 ii.path(elf).fmtEscapeString(),9342 ii.path(elf).fmtEscapeString(),
7921 fmtMemberString(ii.member(elf)),9343 fmtMemberString(ii.member(elf)),
7922 }) catch &name,9344 }) catch &name,
9345 .section, .section_manual_size => |shndx| shndx.name(elf).slice(elf),
7923 .input_section => |isi| {9346 .input_section => |isi| {
7924 const ii = isi.input(elf);9347 const ii = isi.input(elf);
7925 break :name std.mem.print(&name, "{f}{f} {s}", .{9348 break :name std.mem.print(&name, "{f}{f} {s}", .{
7926 ii.path(elf).fmtEscapeString(),9349 ii.path(elf).fmtEscapeString(),
7927 fmtMemberString(ii.member(elf)),9350 fmtMemberString(ii.member(elf)),
7928 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),9351 elf.getNodeShndx(isi.node(elf)).name(elf).slice(elf),
7929 }) catch &name;9352 }) catch &name;
7930 },9353 },
7931 .nav => |nmi| {9354 .nav => |nmi| {
7932 const ip = &elf.base.comp.zcu.?.intern_pool;9355 const ip = &elf.base.comp.zcu.?.intern_pool;
7933 break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip);9356 break :name ip.getNav(nmi.nav(elf)).fqn.toSlice(ip);
7934 },9357 },
7935 .uav => |umi| std.mem.print(&name, "{f}", .{9358 .uav => |umi| std.mem.print(&name, "{f}", .{
7936 Value.fromInterned(umi.uavValue(elf)).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),9359 Value.fromInterned(umi.uavValue(elf)).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
7937 }) catch &name,9360 }) catch &name,
9361 .debug_shared => |ss| switch (ss) {
9362 .debug_abbrev => "debug info abbrevs",
9363 .debug_str, .debug_str_offsets => "debug info strings",
9364 .debug_line_str => "line info strings",
9365 },
9366 .unit_frame,
9367 .unit_frame_cie,
9368 .unit_debug_info,
9369 .unit_debug_info_header,
9370 .unit_debug_info_footer,
9371 .unit_debug_line,
9372 .unit_debug_line_header,
9373 .unit_debug_rnglists,
9374 => |ui, tag| std.mem.print(&name, "{s} info for {s}", .{
9375 switch (tag) {
9376 else => unreachable,
9377 .unit_frame, .unit_frame_cie => "unwind",
9378 .unit_debug_info,
9379 .unit_debug_info_header,
9380 .unit_debug_info_footer,
9381 .unit_debug_rnglists,
9382 => "debug",
9383 .unit_debug_line, .unit_debug_line_header => "line",
9384 },
9385 ui.mod(&elf.dwarf).fully_qualified_name,
9386 }) catch &name,
9387 .const_debug_info => |cpi| switch (cpi.val(&elf.dwarf.const_pool)) {
9388 .generic_poison_type => "anytype",
9389 else => |val| std.mem.print(&name, "debug info for {f}", .{
9390 Value.fromInterned(val).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
9391 }) catch &name,
9392 },
9393 .global_debug_info => |gi| {
9394 const ip = &elf.base.comp.zcu.?.intern_pool;
9395 break :name std.mem.print(&name, "debug info for {f}", .{
9396 ip.getNav(gi.nav(&elf.dwarf)).fqn.fmt(ip),
9397 }) catch &name;
9398 },
9399 .func_frame_fde, .func_debug_info, .func_debug_line => |fi, tag| {
9400 const ip = &elf.base.comp.zcu.?.intern_pool;
9401 break :name std.mem.print(&name, "{s} info for {f}", .{
9402 switch (tag) {
9403 else => unreachable,
9404 .func_frame_fde => "unwind",
9405 .func_debug_info => "debug",
9406 .func_debug_line => "line",
9407 },
9408 ip.getNav(fi.nav(&elf.dwarf)).fqn.fmt(ip),
9409 }) catch &name;
9410 },
9411 .decl_debug_info => |di| {
9412 const comp = elf.base.comp;
9413 const zcu = comp.zcu.?;
9414 break :name std.mem.print(&name, "debug info for {f}", .{
9415 zcu.fileByIndex(di.srcInst(&elf.dwarf).resolveFile(&zcu.intern_pool)).path.fmt(comp),
9416 }) catch &name;
9417 },
7938 }, 0);9418 }, 0);
7939}9419}
79409420
7941fn genPending(elf: *Elf, pt: Zcu.PerThread) Error!void {9421fn genPending(elf: *Elf, pt: Zcu.PerThread) link.Error!void {
7942 const zcu = elf.base.comp.zcu.?;9422 while (elf.pending_uavs.pop()) |umi| {
7943 pending: while (true) {9423 var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined;
7944 if (elf.pending_uavs.pop()) |umi| {9424 const prog_name = std.mem.print(&prog_name_buf, "{f}", .{
7945 var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined;9425 Value.fromInterned(umi.uavValue(elf)).fmtValue(pt),
7946 const prog_name = std.mem.print(&prog_name_buf, "{f}", .{9426 }) catch &prog_name_buf;
7947 Value.fromInterned(umi.uavValue(elf)).fmtValue(pt),9427 const prog_node = elf.const_prog_node.start(prog_name, 0);
7948 }) catch &prog_name_buf;9428 defer prog_node.end();
7949 const prog_node = elf.const_prog_node.start(prog_name, 0);9429 try elf.genUav(pt, umi);
7950 defer prog_node.end();9430 }
7951 try elf.genUav(pt, umi);9431 var lazy_it = elf.lazy.iterator();
7952 continue :pending;9432 while (lazy_it.next()) |lazy| while (lazy.value.pending_index < lazy.value.map.count()) {
7953 }9433 try elf.genLazy(pt, .{ .kind = lazy.key, .index = lazy.value.pending_index });
7954 var lazy_it = elf.lazy.iterator();9434 lazy.value.pending_index += 1;
7955 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {9435 };
7956 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };9436 switch (elf.base.comp.config.debug_format) {
7957 lazy.value.pending_index += 1;9437 .strip => {},
7958 const lazy_ty: Type = .fromInterned(lmr.lazySymbol(elf).ty);9438 .dwarf => {
7959 var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined;9439 const gpa = elf.base.comp.gpa;
7960 const prog_name: []const u8 = switch (lazy_ty.zigTypeTag(zcu)) {9440 while (true) {
7961 .@"enum" => std.mem.print(&prog_name_buf, "@tagName({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf,9441 const pending = elf.dwarf.pending_decl;
7962 .error_set => switch (lmr.kind) {9442 if (pending.instance_val == .none) break;
7963 .code => std.mem.print(&prog_name_buf, "@errorCast({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf,9443 elf.dwarf.pending_decl = .{ .di = undefined, .instance_val = .none };
7964 .const_data => "@errorName",9444 const debug_info_ni = pending.di.get(&elf.dwarf).debug_info_ni.unwrap().?;
7965 },9445 try debug_info_ni.moved(gpa, &elf.mf);
7966 else => unreachable,9446 var di_nw: MappedFile.Node.Writer = undefined;
7967 };9447 debug_info_ni.writer(gpa, &elf.mf, &di_nw);
7968 const prog_node = elf.synth_prog_node.start(prog_name, 0);9448 defer di_nw.deinit();
7969 defer prog_node.end();9449 elf.resetNodeRelocs(debug_info_ni);
7970 try elf.genLazy(pt, lmr);9450 try elf.dwarf.genDecl(pt, &di_nw, pending.instance_val);
7971 continue :pending;9451 }
7972 };9452 },
7973 break;9453 .code_view => unreachable,
7974 }9454 }
7975}9455}
79769456
...@@ -7978,17 +9458,17 @@ fn genUav(...@@ -7978,17 +9458,17 @@ fn genUav(
7978 elf: *Elf,9458 elf: *Elf,
7979 pt: Zcu.PerThread,9459 pt: Zcu.PerThread,
7980 umi: Node.UavMapIndex,9460 umi: Node.UavMapIndex,
7981) Error!void {9461) link.Error!void {
7982 const comp = elf.base.comp;9462 const comp = elf.base.comp;
7983 const gpa = comp.gpa;9463 const gpa = comp.gpa;
79849464
7985 const uav_val = umi.uavValue(elf);9465 const uav_val = umi.uavValue(elf);
7986 const ni = umi.symbol(elf).index().ptr(elf).node.unwrap().?;9466 const ni = umi.symbol(elf).index().ptr(elf).node.unwrap().?;
7987 elf.resetNodeRelocs(ni);
79889467
7989 var nw: MappedFile.Node.Writer = undefined;9468 var nw: MappedFile.Node.Writer = undefined;
7990 ni.writer(&elf.mf, gpa, &nw);9469 ni.writer(gpa, &elf.mf, &nw);
7991 defer nw.deinit();9470 defer nw.deinit();
9471 elf.resetNodeRelocs(ni);
7992 codegen.generateSymbol(9472 codegen.generateSymbol(
7993 &elf.base,9473 &elf.base,
7994 pt,9474 pt,
...@@ -7996,8 +9476,11 @@ fn genUav(...@@ -7996,8 +9476,11 @@ fn genUav(
7996 &nw.interface,9476 &nw.interface,
7997 .{ .atom_index = Node.toAtom(ni) },9477 .{ .atom_index = Node.toAtom(ni) },
7998 ) catch |err| switch (err) {9478 ) catch |err| switch (err) {
7999 error.WriteFailed => return nw.err.?,
8000 else => |e| return e,9479 else => |e| return e,
9480 error.WriteFailed => switch (nw.err.?) {
9481 else => |e| return e,
9482 error.MappedFileIo => return comp.link_diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
9483 },
8001 };9484 };
8002 switch (elf.symPtr(umi.symbol(elf).index())) {9485 switch (elf.symPtr(umi.symbol(elf).index())) {
8003 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),9486 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
...@@ -8007,13 +9490,29 @@ fn genUav(...@@ -8007,13 +9490,29 @@ fn genUav(
8007 assert(ni.hasMoved(&elf.mf));9490 assert(ni.hasMoved(&elf.mf));
8008}9491}
80099492
8010fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {9493fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) link.Error!void {
9494 const lazy = lmr.lazySymbol(elf);
9495 if (lazy.ty == .anyerror_type) return;
9496 const lazy_ty: Type = .fromInterned(lazy.ty);
9497 var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined;
9498 const prog_name: []const u8 = switch (lazy_ty.zigTypeTag(pt.zcu)) {
9499 .@"enum" => std.mem.print(&prog_name_buf, "@tagName({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf,
9500 .error_set => switch (lmr.kind) {
9501 .code => std.mem.print(&prog_name_buf, "@errorCast({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf,
9502 .const_data => "@errorName(anyerror)",
9503 },
9504 else => unreachable,
9505 };
9506 const prog_node = elf.base.comp.link_prog_node.start(prog_name, 0);
9507 defer prog_node.end();
9508 try elf.genLazyInner(pt, lmr);
9509}
9510fn genLazyInner(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) link.Error!void {
8011 const zcu = pt.zcu;9511 const zcu = pt.zcu;
8012 const gpa = zcu.gpa;9512 const gpa = zcu.gpa;
80139513
8014 const lazy = lmr.lazySymbol(elf);9514 const lazy = lmr.lazySymbol(elf);
8015 const ni = lmr.symbol(elf).index().ptr(elf).node.unwrap().?;9515 const ni = lmr.symbol(elf).index().ptr(elf).node.unwrap().?;
8016 elf.resetNodeRelocs(ni);
80179516
8018 // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually9517 // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually
8019 // be called to apply the lazy node's new relocations.9518 // be called to apply the lazy node's new relocations.
...@@ -8021,8 +9520,9 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {...@@ -8021,8 +9520,9 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {
80219520
8022 var required_alignment: InternPool.Alignment = .none;9521 var required_alignment: InternPool.Alignment = .none;
8023 var nw: MappedFile.Node.Writer = undefined;9522 var nw: MappedFile.Node.Writer = undefined;
8024 ni.writer(&elf.mf, gpa, &nw);9523 ni.writer(gpa, &elf.mf, &nw);
8025 defer nw.deinit();9524 defer nw.deinit();
9525 elf.resetNodeRelocs(ni);
8026 codegen.generateLazySymbol(9526 codegen.generateLazySymbol(
8027 &elf.base,9527 &elf.base,
8028 pt,9528 pt,
...@@ -8032,8 +9532,14 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {...@@ -8032,8 +9532,14 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {
8032 .none,9532 .none,
8033 .{ .atom_index = Node.toAtom(ni) },9533 .{ .atom_index = Node.toAtom(ni) },
8034 ) catch |err| switch (err) {9534 ) catch |err| switch (err) {
8035 error.WriteFailed => return nw.err.?,
8036 else => |e| return e,9535 else => |e| return e,
9536 error.WriteFailed => return switch (nw.err.?) {
9537 else => |e| return e,
9538 error.MappedFileIo => return elf.base.comp.link_diags.fail(
9539 "failed to write output file: {t}",
9540 .{elf.mf.io_err.?},
9541 ),
9542 },
8037 };9543 };
8038 switch (elf.symPtr(lmr.symbol(elf).index())) {9544 switch (elf.symPtr(lmr.symbol(elf).index())) {
8039 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),9545 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
...@@ -8104,18 +9610,18 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {...@@ -8104,18 +9610,18 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {
8104 fr.seekTo(file_loc.offset) catch |err| switch (err) {9610 fr.seekTo(file_loc.offset) catch |err| switch (err) {
8105 error.Canceled => |e| return e,9611 error.Canceled => |e| return e,
8106 else => |e| return diags.fail("failed to read input section '{s}' from \"{f}{f}\": {t}", .{9612 else => |e| return diags.fail("failed to read input section '{s}' from \"{f}{f}\": {t}", .{
8107 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),9613 elf.getNodeShndx(isi.node(elf)).name(elf).slice(elf),
8108 path.fmtEscapeString(),9614 path.fmtEscapeString(),
8109 fmtMemberString(ii.member(elf)),9615 fmtMemberString(ii.member(elf)),
8110 e,9616 e,
8111 }),9617 }),
8112 };9618 };
8113 var nw: MappedFile.Node.Writer = undefined;9619 var nw: MappedFile.Node.Writer = undefined;
8114 isi.node(elf).writer(&elf.mf, gpa, &nw);9620 isi.node(elf).writer(gpa, &elf.mf, &nw);
8115 defer nw.deinit();9621 defer nw.deinit();
8116 const n_bytes = nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) catch |err| switch (err) {9622 const n_bytes = nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) catch |err| switch (err) {
8117 error.ReadFailed => return diags.fail("failed to read input section '{s}' from \"{f}{f}\": {t}", .{9623 error.ReadFailed => return diags.fail("failed to read input section '{s}' from \"{f}{f}\": {t}", .{
8118 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),9624 elf.getNodeShndx(isi.node(elf)).name(elf).slice(elf),
8119 path.fmtEscapeString(),9625 path.fmtEscapeString(),
8120 fmtMemberString(ii.member(elf)),9626 fmtMemberString(ii.member(elf)),
8121 fr.err orelse (fr.seek_err orelse fr.size_err.?),9627 fr.err orelse (fr.seek_err orelse fr.size_err.?),
...@@ -8123,7 +9629,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {...@@ -8123,7 +9629,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {
8123 error.WriteFailed => return nw.err.?,9629 error.WriteFailed => return nw.err.?,
8124 };9630 };
8125 if (n_bytes != file_loc.size) return diags.fail("failed to read input section '{s}' from \"{f}{f}\": unexpected eof", .{9631 if (n_bytes != file_loc.size) return diags.fail("failed to read input section '{s}' from \"{f}{f}\": unexpected eof", .{
8126 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),9632 elf.getNodeShndx(isi.node(elf)).name(elf).slice(elf),
8127 path.fmtEscapeString(),9633 path.fmtEscapeString(),
8128 fmtMemberString(ii.member(elf)),9634 fmtMemberString(ii.member(elf)),
8129 });9635 });
...@@ -8133,7 +9639,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {...@@ -8133,7 +9639,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {
8133}9639}
81349640
8135fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {9641fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {
8136 const elf_offset = elf.getNodeElfOffset(ni);9642 const elf_offset = elf.computeNodeElfOffset(ni);
8137 switch (elf.getNode(ni)) {9643 switch (elf.getNode(ni)) {
8138 else => unreachable,9644 else => unreachable,
8139 .ehdr => assert(elf_offset == 0),9645 .ehdr => assert(elf_offset == 0),
...@@ -8155,7 +9661,7 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {...@@ -8155,7 +9661,7 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {
8155 elf.flushElfOffset(child_ni);9661 elf.flushElfOffset(child_ni);
8156 }9662 }
8157 },9663 },
8158 .section => |shndx| switch (elf.shdrPtr(shndx)) {9664 .section, .section_manual_size => |shndx| switch (elf.shdrPtr(shndx)) {
8159 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(elf_offset)),9665 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(elf_offset)),
8160 },9666 },
8161 }9667 }
...@@ -8166,17 +9672,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8166,17 +9672,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8166 defer trace.end();9672 defer trace.end();
81679673
8168 switch (elf.getNode(ni)) {9674 switch (elf.getNode(ni)) {
8169 .archive => unreachable,9675 .deleted => unreachable,
8170 .archive_header => unreachable,9676 .archive, .archive_header => unreachable,
81719677 .archive_input_member, .archive_elf_member_header, .elf => {
8172 .archive_input_member,
8173 .archive_elf_member_header,
8174 .elf,
8175 => {
8176 assert(elf.archive != null);9678 assert(elf.archive != null);
8177 return;9679 return;
8178 },9680 },
8179
8180 .ehdr, .shdr => elf.flushElfOffset(ni),9681 .ehdr, .shdr => elf.flushElfOffset(ni),
8181 .segment => |phndx| {9682 .segment => |phndx| {
8182 elf.flushElfOffset(ni);9683 elf.flushElfOffset(ni);
...@@ -8194,6 +9695,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8194,6 +9695,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8194 .INTERP,9695 .INTERP,
8195 .PHDR,9696 .PHDR,
8196 .TLS,9697 .TLS,
9698 .GNU_EH_FRAME,
8197 .GNU_RELRO,9699 .GNU_RELRO,
8198 => {9700 => {
8199 const new_vaddr = elf.computeNodeVAddr(ni);9701 const new_vaddr = elf.computeNodeVAddr(ni);
...@@ -8204,14 +9706,11 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8204,14 +9706,11 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8204 },9706 },
8205 }9707 }
8206 },9708 },
8207 .section => |shndx| {9709 .section, .section_manual_size => |shndx| {
8208 elf.flushElfOffset(ni);9710 elf.flushElfOffset(ni);
8209 const addr = elf.computeNodeVAddr(ni);9711 const addr = elf.computeNodeVAddr(ni);
8210 const old_addr: u64, const flags: std.elf.SHF = switch (elf.shdrPtr(shndx)) {9712 const old_addr: u64, const flags: std.elf.SHF = switch (elf.shdrPtr(shndx)) {
8211 inline else => |shdr| .{9713 inline else => |shdr| .{ elf.targetLoad(&shdr.addr), elf.targetLoad(&shdr.flags).shf },
8212 elf.targetLoad(&shdr.addr),
8213 elf.targetLoad(&shdr.flags).shf,
8214 },
8215 };9714 };
82169715
8217 if (flags.ALLOC) {9716 if (flags.ALLOC) {
...@@ -8225,10 +9724,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8225,10 +9724,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8225 var name = first_name;9724 var name = first_name;
8226 while (name != .empty) {9725 while (name != .empty) {
8227 const old_sym_addr = Symbol.Id.global(name).value(elf);9726 const old_sym_addr = Symbol.Id.global(name).value(elf);
8228 Symbol.Id.global(name).flushMoved(9727 Symbol.Id.global(name).flushMoved(elf, old_sym_addr - old_addr + addr);
8229 elf,
8230 old_sym_addr - old_addr + addr,
8231 );
8232 name = elf.globalByName(name).?.next_in_node;9728 name = elf.globalByName(name).?.next_in_node;
8233 }9729 }
8234 }9730 }
...@@ -8246,12 +9742,18 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8246,12 +9742,18 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8246 reloc.apply(elf);9742 reloc.apply(elf);
8247 }9743 }
8248 } else if (shndx == elf.shndx.plt) {9744 } else if (shndx == elf.shndx.plt) {
8249 elf.flushMovedNodeRelocs(ni, addr, elf.plt_first_symbol_reloc, .none);9745 elf.flushMovedNodeRelocs(ni, addr, .{
9746 .first_symbol_reloc = elf.plt_first_symbol_reloc,
9747 });
8250 elf.flushMovedPltSection(.plt, old_addr, addr);9748 elf.flushMovedPltSection(.plt, old_addr, addr);
8251 } else if (shndx == elf.shndx.got_plt) {9749 } else if (shndx == elf.shndx.got_plt) {
8252 elf.flushMovedPltSection(.got_plt, old_addr, addr);9750 elf.flushMovedPltSection(.got_plt, old_addr, addr);
8253 } else if (shndx == elf.shndx.plt_sec) {9751 } else if (shndx == elf.shndx.plt_sec) {
8254 elf.flushMovedPltSection(.plt_sec, old_addr, addr);9752 elf.flushMovedPltSection(.plt_sec, old_addr, addr);
9753 } else if (shndx == elf.shndx.eh_frame_hdr) {
9754 elf.flushMovedNodeRelocs(ni, addr, .{
9755 .first_symbol_reloc = elf.eh_frame_hdr_first_symbol_reloc,
9756 });
8255 }9757 }
8256 },9758 },
8257 .input_section => |isi| {9759 .input_section => |isi| {
...@@ -8298,12 +9800,10 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8298,12 +9800,10 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8298 }9800 }
8299 }9801 }
83009802
8301 elf.flushMovedNodeRelocs(9803 elf.flushMovedNodeRelocs(ni, new_section_addr, .{
8302 ni,9804 .first_symbol_reloc = isi.ptrConst(elf).first_symbol_reloc,
8303 new_section_addr,9805 .first_got_reloc = isi.ptrConst(elf).first_got_reloc,
8304 isi.ptrConst(elf).first_symbol_reloc,9806 });
8305 isi.ptrConst(elf).first_got_reloc,
8306 );
8307 },9807 },
8308 .copied_global => |global_name| {9808 .copied_global => |global_name| {
8309 const copied_global = elf.copied_globals.getPtr(global_name) orelse {9809 const copied_global = elf.copied_globals.getPtr(global_name) orelse {
...@@ -8318,7 +9818,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8318,7 +9818,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
83189818
8319 Symbol.Id.global(global_name).flushMoved(elf, new_addr);9819 Symbol.Id.global(global_name).flushMoved(elf, new_addr);
8320 },9820 },
8321 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| {9821 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi, tag| {
8322 const new_addr = elf.computeNodeVAddr(ni);9822 const new_addr = elf.computeNodeVAddr(ni);
8323 Symbol.Id.local(mi.symbol(elf)).flushMoved(elf, new_addr);9823 Symbol.Id.local(mi.symbol(elf)).flushMoved(elf, new_addr);
8324 if (elf.node_global_symbols.get(ni)) |first_name| {9824 if (elf.node_global_symbols.get(ni)) |first_name| {
...@@ -8329,12 +9829,173 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8329,12 +9829,173 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8329 name = elf.globalByName(name).?.next_in_node;9829 name = elf.globalByName(name).?.next_in_node;
8330 }9830 }
8331 }9831 }
8332 elf.flushMovedNodeRelocs(9832 elf.flushMovedNodeRelocs(ni, new_addr, .{
8333 ni,9833 .first_symbol_reloc = mi.firstSymbolReloc(elf),
8334 new_addr,9834 .skip_symbol_relocs = switch (tag) {
8335 mi.firstSymbolReloc(elf),9835 else => comptime unreachable,
8336 mi.firstGotReloc(elf),9836 .nav => if (elf.dwarf.getFuncIfExists(mi.nav(elf))) |dwarf_fi|
8337 );9837 dwarf_fi.get(&elf.dwarf).debug_info_ni
9838 else
9839 .none,
9840 .uav, .lazy_code, .lazy_const_data => .none,
9841 },
9842 .first_got_reloc = mi.firstGotReloc(elf),
9843 });
9844 },
9845 .debug_shared => |ss| {
9846 const target_section_offset = elf.computeNodeSectionOffset(ni);
9847 var target_ri = elf.dwarf_shared.getPtr(ss).first_target_reloc;
9848 while (target_ri != .none) {
9849 const target_reloc = target_ri.get(elf);
9850 assert(target_reloc.target == ni);
9851 target_reloc.flushMovedTarget(elf, target_section_offset);
9852 target_ri = target_reloc.next;
9853 }
9854 },
9855 .eh_frame_footer, .unit_padding, .unit_frame, .unit_debug_info, .unit_debug_line => {},
9856 .unit_frame_cie => |ui| {
9857 const target_section_offset = elf.computeNodeSectionOffset(ni);
9858 var target_ri = elf.dwarf_units[@backingInt(ui)].frame_cie_first_target_reloc;
9859 while (target_ri != .none) {
9860 const target_reloc = target_ri.get(elf);
9861 assert(target_reloc.target == ni);
9862 target_reloc.flushMovedTarget(elf, target_section_offset);
9863 target_ri = target_reloc.next;
9864 }
9865 },
9866 .unit_debug_info_header => |ui| {
9867 const dwarf_unit = &elf.dwarf_units[@backingInt(ui)];
9868 const target_section_offset = elf.computeNodeSectionOffset(ni);
9869 var target_ri = dwarf_unit.debug_info_header_first_target_reloc;
9870 while (target_ri != .none) {
9871 const target_reloc = target_ri.get(elf);
9872 assert(target_reloc.target == ni);
9873 target_reloc.flushMovedTarget(elf, target_section_offset);
9874 target_ri = target_reloc.next;
9875 }
9876 elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{
9877 .first_node_reloc = dwarf_unit.debug_info_header_first_node_reloc,
9878 });
9879 },
9880 .unit_debug_info_footer => {},
9881 .unit_debug_line_header => |ui| {
9882 const dwarf_unit = &elf.dwarf_units[@backingInt(ui)];
9883 const target_section_offset = elf.computeNodeSectionOffset(ni);
9884 var target_ri = dwarf_unit.debug_line_header_first_target_reloc;
9885 while (target_ri != .none) {
9886 const target_reloc = target_ri.get(elf);
9887 assert(target_reloc.target == ni);
9888 target_reloc.flushMovedTarget(elf, target_section_offset);
9889 target_ri = target_reloc.next;
9890 }
9891 elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{
9892 .first_node_reloc = dwarf_unit.debug_line_header_first_node_reloc,
9893 });
9894 },
9895 .unit_debug_rnglists => |ui| {
9896 const dwarf_unit = &elf.dwarf_units[@backingInt(ui)];
9897 const target_section_offset = elf.computeNodeSectionOffset(ni);
9898 var target_ri = dwarf_unit.debug_rnglists_first_target_reloc;
9899 while (target_ri != .none) {
9900 const target_reloc = target_ri.get(elf);
9901 assert(target_reloc.target == ni);
9902 target_reloc.flushMovedTarget(elf, target_section_offset);
9903 target_ri = target_reloc.next;
9904 }
9905 const node_vaddr = elf.computeNodeVAddr(ni);
9906 for (dwarf_unit.debug_rnglists_symbol_relocs.keys()) |symbol_ri| {
9907 const symbol_reloc = symbol_ri.get(elf);
9908 assert(symbol_reloc.node.unwrap().? == ni);
9909 symbol_reloc.flushMovedNode(elf, node_vaddr);
9910 }
9911 },
9912 .const_debug_info => |cpi| {
9913 const dwarf_const = &elf.dwarf_consts.get(cpi).?;
9914 const target_section_offset = elf.computeNodeSectionOffset(ni);
9915 var target_ri = dwarf_const.debug_info_first_target_reloc;
9916 while (target_ri != .none) {
9917 const target_reloc = target_ri.get(elf);
9918 assert(target_reloc.target == ni);
9919 target_reloc.flushMovedTarget(elf, target_section_offset);
9920 target_ri = target_reloc.next;
9921 }
9922 elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{
9923 .first_symbol_reloc = dwarf_const.debug_info_first_symbol_reloc,
9924 .first_node_reloc = dwarf_const.debug_info_first_node_reloc,
9925 });
9926 },
9927 .global_debug_info => |gi| {
9928 const dwarf_global = &elf.dwarf_globals.items[@backingInt(gi)];
9929 const target_section_offset = elf.computeNodeSectionOffset(ni);
9930 var target_ri = dwarf_global.debug_info_first_target_reloc;
9931 while (target_ri != .none) {
9932 const target_reloc = target_ri.get(elf);
9933 assert(target_reloc.target == ni);
9934 target_reloc.flushMovedTarget(elf, target_section_offset);
9935 target_ri = target_reloc.next;
9936 }
9937 elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{
9938 .first_symbol_reloc = dwarf_global.debug_info_first_symbol_reloc,
9939 .first_node_reloc = dwarf_global.debug_info_first_node_reloc,
9940 });
9941 },
9942 .func_frame_fde => |fi| {
9943 const dwarf_func = &elf.dwarf_funcs.items[@backingInt(fi)];
9944 const zcu = elf.base.comp.zcu.?;
9945 const mod = zcu.navFileScope(fi.nav(&elf.dwarf)).mod.?;
9946 switch (mod.unwind_tables) {
9947 .none => {},
9948 .sync, .async => {
9949 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);
9950 elf.dwarf.updateEhFrameFde(ni.slice(&elf.mf), offset);
9951 },
9952 }
9953 elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{
9954 .first_symbol_reloc = dwarf_func.frame_fde_first_symbol_reloc,
9955 .first_node_reloc = dwarf_func.frame_fde_first_node_reloc,
9956 });
9957 },
9958 .func_debug_info => |fi| {
9959 const dwarf_func = &elf.dwarf_funcs.items[@backingInt(fi)];
9960 const target_section_offset = elf.computeNodeSectionOffset(ni);
9961 var target_ri = dwarf_func.debug_info_first_target_reloc;
9962 while (target_ri != .none) {
9963 const target_reloc = target_ri.get(elf);
9964 assert(target_reloc.target == ni);
9965 target_reloc.flushMovedTarget(elf, target_section_offset);
9966 target_ri = target_reloc.next;
9967 }
9968 elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{
9969 .first_symbol_reloc = dwarf_func.debug_info_first_symbol_reloc,
9970 .skip_symbol_relocs = if (elf.navs.getPtr(fi.nav(&elf.dwarf))) |nav|
9971 nav.lsi.index().ptr(elf).node
9972 else
9973 .none,
9974 .first_node_reloc = dwarf_func.debug_info_first_node_reloc,
9975 .skip_node_relocs = fi.get(&elf.dwarf).debug_line_ni,
9976 });
9977 },
9978 .func_debug_line => |fi| {
9979 const dwarf_func = &elf.dwarf_funcs.items[@backingInt(fi)];
9980 elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{
9981 .first_symbol_reloc = dwarf_func.debug_line_first_symbol_reloc,
9982 .first_node_reloc = dwarf_func.debug_line_first_node_reloc,
9983 .skip_node_relocs = fi.get(&elf.dwarf).debug_info_ni,
9984 });
9985 },
9986 .decl_debug_info => |di| {
9987 const dwarf_decl = &elf.dwarf_decls.get(di).?;
9988 const target_section_offset = elf.computeNodeSectionOffset(ni);
9989 var target_ri = dwarf_decl.debug_info_first_target_reloc;
9990 while (target_ri != .none) {
9991 const target_reloc = target_ri.get(elf);
9992 assert(target_reloc.target == ni);
9993 target_reloc.flushMovedTarget(elf, target_section_offset);
9994 target_ri = target_reloc.next;
9995 }
9996 elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{
9997 .first_node_reloc = dwarf_decl.debug_info_first_node_reloc,
9998 });
8338 },9999 },
8339 }10000 }
8340 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);10001 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
...@@ -8496,6 +10157,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo...@@ -8496,6 +10157,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
849610157
8497 _, const size = ni.location(&elf.mf).resolve(&elf.mf);10158 _, const size = ni.location(&elf.mf).resolve(&elf.mf);
8498 switch (elf.getNode(ni)) {10159 switch (elf.getNode(ni)) {
10160 .deleted => unreachable,
8499 .archive, .archive_header => {},10161 .archive, .archive_header => {},
8500 .archive_input_member => unreachable,10162 .archive_input_member => unreachable,
8501 .archive_elf_member_header => unreachable,10163 .archive_elf_member_header => unreachable,
...@@ -8523,7 +10185,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo...@@ -8523,7 +10185,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
8523 elf.targetStore(&ph.type, if (size > 0) .LOAD else .NULL);10185 elf.targetStore(&ph.type, if (size > 0) .LOAD else .NULL);
8524 try elf.allocateSegmentLoadAddress(phndx);10186 try elf.allocateSegmentLoadAddress(phndx);
8525 },10187 },
8526 .DYNAMIC, .INTERP, .PHDR, std.elf.PT.GNU_RELRO => {10188 .DYNAMIC, .INTERP, .PHDR, .GNU_EH_FRAME, .GNU_RELRO => {
8527 elf.targetStore(&ph.memsz, @intCast(size));10189 elf.targetStore(&ph.memsz, @intCast(size));
8528 },10190 },
8529 .TLS => {10191 .TLS => {
...@@ -8558,39 +10220,47 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo...@@ -8558,39 +10220,47 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
8558 inline else => |shdr| {10220 inline else => |shdr| {
8559 switch (elf.targetLoad(&shdr.type)) {10221 switch (elf.targetLoad(&shdr.type)) {
8560 else => unreachable,10222 else => unreachable,
8561
8562 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),10223 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),
8563 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),10224 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
856410225 .X86_64_UNWIND => {},
8565 .INIT_ARRAY,
8566 .FINI_ARRAY,
8567 .PREINIT_ARRAY,
8568 .STRTAB,
8569 .SYMTAB,
8570 .DYNAMIC,
8571 .REL,
8572 .RELA,
8573 .DYNSYM,
8574 .HASH,
8575 => return,
8576 }
8577 if (shndx != elf.shndx.plt and
8578 shndx != elf.shndx.got and
8579 shndx != elf.shndx.got_plt)
8580 {
8581 elf.targetStore(&shdr.size, @intCast(size));
8582 }10226 }
10227 elf.targetStore(&shdr.size, @intCast(size));
8583 },10228 },
8584 },10229 },
8585 .input_section, .copied_global, .nav, .uav, .lazy_code, .lazy_const_data => {},10230 .section_manual_size,
10231 .input_section,
10232 .copied_global,
10233 .nav,
10234 .uav,
10235 .lazy_code,
10236 .lazy_const_data,
10237 .debug_shared,
10238 .eh_frame_footer,
10239 .unit_padding,
10240 .unit_frame,
10241 .unit_frame_cie,
10242 .unit_debug_info,
10243 .unit_debug_info_header,
10244 .unit_debug_info_footer,
10245 .unit_debug_line,
10246 .unit_debug_line_header,
10247 .unit_debug_rnglists,
10248 .const_debug_info,
10249 .global_debug_info,
10250 .func_frame_fde,
10251 .func_debug_info,
10252 .func_debug_line,
10253 .decl_debug_info,
10254 => {},
8586 }10255 }
8587}10256}
858810257
8589fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void {10258fn flushPadding(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void {
8590 const trace = tracy.trace(@src());10259 const trace = tracy.trace(@src());
8591 defer trace.end();10260 defer trace.end();
859210261
8593 switch (elf.getNode(ni)) {10262 switch (elf.getNode(ni)) {
10263 .deleted => unreachable,
8594 .archive,10264 .archive,
8595 .archive_input_member,10265 .archive_input_member,
8596 .archive_elf_member_header,10266 .archive_elf_member_header,
...@@ -8599,13 +10269,17 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!...@@ -8599,13 +10269,17 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!
8599 .shdr,10269 .shdr,
8600 .segment,10270 .segment,
8601 .section,10271 .section,
10272 .section_manual_size,
8602 .input_section,10273 .input_section,
8603 .copied_global,10274 .copied_global,
8604 .nav,10275 .nav,
8605 .uav,10276 .uav,
8606 .lazy_code,10277 .lazy_code,
8607 .lazy_const_data,10278 .lazy_const_data,
8608 => unreachable,10279 .debug_shared,
10280 .eh_frame_footer,
10281 .unit_debug_info_footer,
10282 => {},
860910283
8610 .archive_header => {10284 .archive_header => {
8611 const archive = &elf.archive.?;10285 const archive = &elf.archive.?;
...@@ -8633,6 +10307,190 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!...@@ -8633,6 +10307,190 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!
8633 error.NoSpaceLeft => archive.strtab_member_too_big = true,10307 error.NoSpaceLeft => archive.strtab_member_too_big = true,
8634 }10308 }
8635 },10309 },
10310 .unit_padding,
10311 .unit_frame_cie,
10312 .unit_debug_info_header,
10313 .unit_debug_line_header,
10314 .unit_debug_rnglists,
10315 .const_debug_info,
10316 .global_debug_info,
10317 .func_frame_fde,
10318 .func_debug_info,
10319 .func_debug_line,
10320 .decl_debug_info,
10321 => |_, tag| {
10322 const offset, const size = ni.location(&elf.mf).resolve(&elf.mf);
10323 const parent_ni = ni.parent(&elf.mf).unwrap().?;
10324 const slice = slice: {
10325 if (ni.next(&elf.mf).unwrap()) |next_ni| switch (next_ni.position(&elf.mf)) {
10326 .header => unreachable,
10327 .footer => {},
10328 .floating => {
10329 const parent_slice = parent_ni.slicePadding(&elf.mf);
10330 const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf);
10331 break :slice parent_slice[@intCast(offset)..@intCast(next_offset)];
10332 },
10333 };
10334 switch (tag) {
10335 else => unreachable,
10336 .unit_padding, .unit_debug_rnglists => {
10337 const parent_slice = parent_ni.slicePadding(&elf.mf);
10338 const frame_shndx = elf.getNodeShndx(parent_ni);
10339 const frame_format = frame_shndx.debugFrameFormat(elf) orelse
10340 break :slice parent_slice[@intCast(offset)..];
10341 const footer_size = elf.debugFrameFooterSize(frame_format);
10342 @memset(parent_slice[@intCast(offset + size)..][0..footer_size], 0);
10343 frame_shndx.setSize(elf, offset + size + footer_size);
10344 break :slice parent_slice[@intCast(offset)..][0..@intCast(size)];
10345 },
10346 .unit_frame_cie, .func_frame_fde => {
10347 const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf);
10348 const frame_ni = parent_ni.parent(&elf.mf).unwrap().?;
10349 const frame_slice = frame_ni.slicePadding(&elf.mf);
10350 const frame_shndx = elf.getNode(frame_ni).section_manual_size;
10351 const frame_format = frame_shndx.debugFrameFormat(elf).?;
10352 if (parent_ni.next(&elf.mf).unwrap()) |parent_next_ni| {
10353 switch (parent_next_ni.position(&elf.mf)) {
10354 .header => unreachable,
10355 .footer => {},
10356 .floating => {
10357 const parent_next_offset, _ =
10358 parent_next_ni.location(&elf.mf).resolve(&elf.mf);
10359 const slice = frame_slice[@intCast(
10360 parent_offset + offset,
10361 )..@intCast(parent_next_offset)];
10362 var fw: Io.Writer = .fixed(slice[@intCast(size)..]);
10363 elf.dwarf.genDebugFrameCie(
10364 &fw,
10365 null,
10366 frame_format,
10367 ) catch |err| switch (err) {
10368 error.WriteFailed => break :slice slice,
10369 };
10370 elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len);
10371 break :slice slice[0..@intCast(size)];
10372 },
10373 }
10374 }
10375 const footer_size = elf.debugFrameFooterSize(frame_format);
10376 @memset(
10377 frame_slice[@intCast(parent_offset + offset + size)..][0..footer_size],
10378 0,
10379 );
10380 frame_shndx.setSize(elf, parent_offset + offset + size + footer_size);
10381 break :slice frame_slice[@intCast(parent_offset + offset)..][0..@intCast(size)];
10382 },
10383 .unit_debug_info_header,
10384 .unit_debug_line_header,
10385 .const_debug_info,
10386 .global_debug_info,
10387 .func_debug_info,
10388 .func_debug_line,
10389 .decl_debug_info,
10390 => {
10391 const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf);
10392 const debug_ni = parent_ni.parent(&elf.mf).unwrap().?;
10393 const debug_slice = debug_ni.slicePadding(&elf.mf);
10394 var fw: Io.Writer = .fixed(buffer: {
10395 if (parent_ni.next(&elf.mf).unwrap()) |parent_next_ni| {
10396 switch (parent_next_ni.position(&elf.mf)) {
10397 .header => unreachable,
10398 .footer => {},
10399 .floating => {
10400 const parent_next_offset, _ =
10401 parent_next_ni.location(&elf.mf).resolve(&elf.mf);
10402 break :buffer debug_slice[@intCast(
10403 parent_offset,
10404 )..@intCast(parent_next_offset)];
10405 },
10406 }
10407 }
10408 break :buffer debug_slice[@intCast(parent_offset)..];
10409 });
10410 fw.end = @intCast(offset + size);
10411 switch (tag) {
10412 else => unreachable,
10413 .unit_debug_info_header,
10414 .const_debug_info,
10415 .global_debug_info,
10416 .func_debug_info,
10417 .decl_debug_info,
10418 => for (0..2) |_| fw.writeUleb128(@backingInt(Dwarf.AbbrevCode.null)) catch
10419 unreachable,
10420 .unit_debug_line_header, .func_debug_line => {},
10421 }
10422 const unit_padding_offset = fw.end;
10423 const unit_padding = fw.unusedCapacitySlice();
10424 elf.dwarf.genUnitPadding(&fw) catch |err| switch (err) {
10425 error.WriteFailed => {
10426 fw.end = unit_padding_offset;
10427 elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len);
10428 switch (tag) {
10429 else => unreachable,
10430 .unit_debug_info_header,
10431 .const_debug_info,
10432 .global_debug_info,
10433 .func_debug_info,
10434 .decl_debug_info,
10435 => {
10436 comptime assert(
10437 Dwarf.uleb128Size(@backingInt(Dwarf.AbbrevCode.null)) == 1,
10438 );
10439 @memset(
10440 fw.unusedCapacitySlice(),
10441 @backingInt(Dwarf.AbbrevCode.null),
10442 );
10443 },
10444 .unit_debug_line_header,
10445 .func_debug_line,
10446 => Dwarf.genDebugLinePadding(&fw, fw.unusedCapacityLen()) catch
10447 unreachable,
10448 }
10449 return;
10450 },
10451 };
10452 elf.dwarf.updateUnitLength(fw.buffer, unit_padding_offset);
10453 elf.dwarf.updateUnitLength(unit_padding, unit_padding.len);
10454 return;
10455 },
10456 }
10457 };
10458 var fw: Io.Writer = .fixed(slice[@intCast(size)..]);
10459 switch (tag) {
10460 else => unreachable,
10461 .unit_padding => elf.dwarf.updateUnitLength(slice, slice.len),
10462 .unit_frame_cie, .func_frame_fde => {
10463 elf.dwarf.updateUnitLength(slice, slice.len);
10464 @memset(fw.buffer, std.dwarf.CFA.nop);
10465 },
10466 .unit_debug_info_header,
10467 .const_debug_info,
10468 .global_debug_info,
10469 .func_debug_info,
10470 .decl_debug_info,
10471 => elf.dwarf.genDebugInfoPadding(&fw, fw.buffer.len) catch unreachable,
10472 .unit_debug_line_header,
10473 .func_debug_line,
10474 => Dwarf.genDebugLinePadding(&fw, fw.buffer.len) catch unreachable,
10475 .unit_debug_rnglists => {
10476 elf.dwarf.genUnitPadding(&fw) catch |err| switch (err) {
10477 error.WriteFailed => {
10478 elf.dwarf.updateUnitLength(slice, slice.len);
10479 @memset(fw.buffer, std.dwarf.RLE.end_of_list);
10480 return;
10481 },
10482 };
10483 elf.dwarf.updateUnitLength(slice, size);
10484 elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len);
10485 },
10486 }
10487 },
10488 .unit_frame, .unit_debug_info, .unit_debug_line => {
10489 var last_ni = ni.last(&elf.mf).unwrap() orelse return;
10490 while (last_ni.position(&elf.mf) == .footer)
10491 last_ni = last_ni.prev(&elf.mf).unwrap() orelse return;
10492 try last_ni.nextMoved(elf.base.comp.gpa, &elf.mf);
10493 },
8636 }10494 }
8637}10495}
863810496
...@@ -8987,11 +10845,10 @@ pub fn updateExports(...@@ -8987,11 +10845,10 @@ pub fn updateExports(
8987 pt: Zcu.PerThread,10845 pt: Zcu.PerThread,
8988 export_indices: []const Zcu.Export.Index,10846 export_indices: []const Zcu.Export.Index,
8989) link.Error!void {10847) link.Error!void {
8990 const diags = &elf.base.comp.link_diags;
8991 for (export_indices) |export_index| {10848 for (export_indices) |export_index| {
8992 elf.updateExportInner(pt, export_index) catch |err| switch (err) {10849 elf.updateExportInner(pt, export_index) catch |err| switch (err) {
8993 else => |e| return e,10850 else => |e| return e,
8994 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),10851 error.MappedFileIo => return elf.base.comp.link_diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
8995 };10852 };
8996 }10853 }
8997}10854}
...@@ -9068,17 +10925,19 @@ fn updateExportInner(...@@ -9068,17 +10925,19 @@ fn updateExportInner(
9068 };10925 };
9069}10926}
907010927
9071fn dumpStderr(elf: *Elf, tid: Zcu.PerThread.Id) !void {10928fn dumpStderr(elf: *Elf, tid: Zcu.PerThread.Id) Io.File.Writer.Error!void {
9072 const comp = elf.base.comp;10929 const comp = elf.base.comp;
9073 const io = comp.io;10930 const io = comp.io;
9074 var buffer: [512]u8 = undefined;10931 var buffer: [512]u8 = undefined;
9075 const stderr = try io.lockStderr(&buffer, null);10932 const stderr = try io.lockStderr(&buffer, null);
9076 defer io.unlockStderr();10933 defer io.unlockStderr();
9077 const w = &stderr.file_writer.interface;10934 const w = &stderr.file_writer.interface;
9078 _ = try elf.dump(w, tid);10935 _ = elf.dump(w, tid) catch |err| switch (err) {
10936 error.WriteFailed => return stderr.file_writer.err.?,
10937 };
9079}10938}
908010939
9081pub fn dump(elf: *Elf, w: *Io.Writer, tid: Zcu.PerThread.Id) !link.File.DumpResult {10940pub fn dump(elf: *Elf, w: *Io.Writer, tid: Zcu.PerThread.Id) Io.Writer.Error!link.File.DumpResult {
9082 if (elf.options.enable_link_snapshots) {10941 if (elf.options.enable_link_snapshots) {
9083 try elf.printNode(tid, w, .root, 0);10942 try elf.printNode(tid, w, .root, 0);
9084 return .enabled;10943 return .enabled;
...@@ -9118,22 +10977,22 @@ pub fn printNode(...@@ -9118,22 +10977,22 @@ pub fn printNode(
9118 try w.writeByte(')');10977 try w.writeByte(')');
9119 },10978 },
9120 },10979 },
9121 .section => |shndx| try w.print("({s})", .{shndx.name(elf).slice(elf)}),10980 .section, .section_manual_size => |shndx| try w.print("({s})", .{shndx.name(elf).slice(elf)}),
9122 .input_section => |isi| {10981 .input_section => |isi| {
9123 const ii = isi.input(elf);10982 const ii = isi.input(elf);
9124 try w.print("({f}{f}, {s})", .{10983 try w.print("({f}{f}, {s})", .{
9125 ii.path(elf).fmtEscapeString(),10984 ii.path(elf).fmtEscapeString(),
9126 fmtMemberString(ii.member(elf)),10985 fmtMemberString(ii.member(elf)),
9127 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),10986 elf.getNodeShndx(isi.node(elf)).name(elf).slice(elf),
9128 });10987 });
9129 },10988 },
9130 .copied_global => |name| try w.print("(copy:{s})", .{name.slice(elf)}),10989 .copied_global => |name| try w.print("(copy:{s})", .{name.slice(elf)}),
9131 .nav => |nmi| {10990 .nav => |nmi| {
9132 const zcu = elf.base.comp.zcu.?;10991 const zcu = elf.base.comp.zcu.?;
9133 const ip = &zcu.intern_pool;10992 const ip = &zcu.intern_pool;
9134 const nav = ip.getNav(nmi.navIndex(elf));10993 const nav = ip.getNav(nmi.nav(elf));
9135 try w.print("({f}, {f})", .{10994 try w.print("({f}, {f})", .{
9136 Type.fromInterned(ip.typeOf(nav.resolved.?.value)).fmt(.{ .zcu = zcu, .tid = tid }),10995 Type.fromInterned(nav.resolved.?.type).fmt(.{ .zcu = zcu, .tid = tid }),
9137 nav.fqn.fmt(ip),10996 nav.fqn.fmt(ip),
9138 });10997 });
9139 },10998 },
...@@ -9151,19 +11010,66 @@ pub fn printNode(...@@ -9151,19 +11010,66 @@ pub fn printNode(
9151 .tid = tid,11010 .tid = tid,
9152 }),11011 }),
9153 }),11012 }),
11013 .debug_shared => |ss| try w.print("({})", .{ss}),
11014 .unit_frame,
11015 .unit_frame_cie,
11016 .unit_debug_info,
11017 .unit_debug_info_header,
11018 .unit_debug_info_footer,
11019 .unit_debug_line,
11020 .unit_debug_line_header,
11021 .unit_debug_rnglists,
11022 => |ui| try w.print("({s})", .{ui.mod(&elf.dwarf).fully_qualified_name}),
11023 .const_debug_info => |cpi| switch (cpi.val(&elf.dwarf.const_pool)) {
11024 .generic_poison_type => try w.writeAll("(anytype)"),
11025 else => |val| try w.print("({f})", .{
11026 Value.fromInterned(val).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
11027 }),
11028 },
11029 .global_debug_info => |gi| {
11030 const zcu = elf.base.comp.zcu.?;
11031 const ip = &zcu.intern_pool;
11032 const nav = ip.getNav(gi.nav(&elf.dwarf));
11033 try w.writeByte('(');
11034 if (nav.resolved) |resolved| try w.print("{f}, ", .{
11035 Type.fromInterned(resolved.type).fmt(.{ .zcu = zcu, .tid = tid }),
11036 });
11037 try w.print("{f})", .{nav.fqn.fmt(ip)});
11038 },
11039 .func_frame_fde, .func_debug_info, .func_debug_line => |fi| {
11040 const zcu = elf.base.comp.zcu.?;
11041 const ip = &zcu.intern_pool;
11042 const nav = ip.getNav(fi.nav(&elf.dwarf));
11043 try w.writeByte('(');
11044 if (nav.resolved) |resolved| try w.print("{f}, ", .{
11045 Type.fromInterned(resolved.type).fmt(.{ .zcu = zcu, .tid = tid }),
11046 });
11047 try w.print("{f})", .{nav.fqn.fmt(ip)});
11048 },
11049 .decl_debug_info => |di| {
11050 const comp = elf.base.comp;
11051 const zcu = comp.zcu.?;
11052 const ip = &zcu.intern_pool;
11053 const src_inst = di.srcInst(&elf.dwarf);
11054 try w.print("({f}, ", .{zcu.fileByIndex(src_inst.resolveFile(ip)).path.fmt(comp)});
11055 if (src_inst.resolve(ip)) |inst| try w.print("%{d}", .{inst}) else try w.writeAll("lost");
11056 try w.writeByte(')');
11057 },
9154 }11058 }
9155 {11059 {
9156 const mf_node = &elf.mf.nodes.items[@backingInt(ni)];11060 const mf_node = &elf.mf.nodes.items[@backingInt(ni)];
9157 const off, const size = mf_node.location().resolve(&elf.mf);11061 const off, const size = mf_node.location().resolve(&elf.mf);
9158 try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x} {t}{s}{s}{s}{s}\n", .{11062 try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x} {t}{s}{s}{s}{s}{s}{s}\n", .{
9159 @backingInt(ni),11063 @backingInt(ni),
9160 off,11064 off,
9161 size,11065 size,
9162 mf_node.flags.alignment.toByteUnits(),11066 mf_node.flags.alignment.toByteUnits(),
9163 mf_node.flags.position,11067 mf_node.flags.position,
9164 if (mf_node.flags.moved) " moved" else "",11068 if (mf_node.flags.bubbles_moved) " bubbles_moved" else "",
9165 if (mf_node.flags.next_moved) " next_moved" else "",11069 if (mf_node.flags.resized) " moved" else "",
9166 if (mf_node.flags.resized) " resized" else "",11070 if (mf_node.flags.resized) " resized" else "",
11071 if (mf_node.flags.enable_next_moved) " enable_next_moved" else "",
11072 if (mf_node.flags.next_moved) " next_moved" else "",
9167 if (mf_node.flags.has_content) " has_content" else "",11073 if (mf_node.flags.has_content) " has_content" else "",
9168 });11074 });
9169 }11075 }
...@@ -9176,26 +11082,30 @@ pub fn printNode(...@@ -9176,26 +11082,30 @@ pub fn printNode(
9176 }11082 }
9177 return;11083 return;
9178 }11084 }
9179 const file_loc = ni.fileLocation(&elf.mf, false);11085 const start_address: usize, const end_address: usize = file_loc: {
9180 var address = file_loc.offset;11086 const file_loc = ni.fileLocation(&elf.mf, false);
9181 if (file_loc.size == 0) {11087 break :file_loc .{ @intCast(file_loc.offset), @intCast(file_loc.offset + file_loc.size) };
9182 try w.splatByteAll(' ', indent + 1);11088 };
9183 try w.print("{x:0>8}\n", .{address});11089 var address = start_address;
9184 return;
9185 }
9186 const line_len = 0x10;11090 const line_len = 0x10;
9187 var line_it = std.mem.window(11091 while (true) : (address = @min(std.mem.alignForward(usize, address + 1, line_len), end_address)) {
9188 u8,
9189 elf.mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
9190 line_len,
9191 line_len,
9192 );
9193 while (line_it.next()) |line_bytes| : (address += line_len) {
9194 try w.splatByteAll(' ', indent + 1);11092 try w.splatByteAll(' ', indent + 1);
9195 try w.print("{x:0>8} ", .{address});11093 try w.print("{x:0>8}", .{address});
9196 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});11094 if (address == end_address) break try w.writeByte('\n');
9197 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);11095 try w.splatByteAll(' ', 2);
9198 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');11096 const start_byte_address = std.mem.alignBackward(usize, address, line_len);
11097 const end_byte_address = start_byte_address + line_len;
11098 for (start_byte_address..end_byte_address) |byte_address|
11099 if (byte_address < start_address or byte_address >= end_address)
11100 try w.splatByteAll(' ', 3)
11101 else
11102 try w.print("{x:0>2} ", .{elf.mf.memory_map.memory[byte_address]});
11103 try w.writeByte(' ');
11104 for (start_byte_address..@min(end_address, end_byte_address)) |byte_address|
11105 try w.writeByte(if (byte_address < start_address or byte_address >= end_address) ' ' else char: {
11106 const byte = elf.mf.memory_map.memory[byte_address];
11107 break :char if (std.ascii.isPrint(byte)) byte else '.';
11108 });
9199 try w.writeByte('\n');11109 try w.writeByte('\n');
9200 }11110 }
9201}11111}
...@@ -9209,7 +11119,7 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: Alignment) Error...@@ -9209,7 +11119,7 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: Alignment) Error
9209 // Align the actual node11119 // Align the actual node
9210 const seg_ni = elf.phdrs.items[phndx].unwrap().?;11120 const seg_ni = elf.phdrs.items[phndx].unwrap().?;
9211 if (min_align.compare(.gt, seg_ni.alignment(&elf.mf))) {11121 if (min_align.compare(.gt, seg_ni.alignment(&elf.mf))) {
9212 try seg_ni.realign(&elf.mf, gpa, min_align);11122 try seg_ni.realign(gpa, &elf.mf, min_align);
9213 }11123 }
9214 // Update the phdr `@"align"` field if necessary11124 // Update the phdr `@"align"` field if necessary
9215 switch (elf.phdrSlice()) {11125 switch (elf.phdrSlice()) {
...@@ -9240,6 +11150,21 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: Alignment) Error...@@ -9240,6 +11150,21 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: Alignment) Error
9240 }11150 }
9241}11151}
924211152
11153pub fn addNodeAssumeCapacity(elf: *Elf, ni: MappedFile.Node.Index, node: Node) MappedFile.Node.Index {
11154 if (elf.nodes.len - @backingInt(ni) > 0) {
11155 assert(elf.getNode(ni) == .deleted);
11156 elf.nodes.set(@backingInt(ni), node);
11157 } else elf.nodes.appendAssumeCapacity(node);
11158 return ni;
11159}
11160
11161fn deleteNode(elf: *Elf, node: *MappedFile.Node.Index.Optional) std.mem.Allocator.Error!void {
11162 const ni = node.unwrap().?;
11163 try ni.delete(elf.base.comp.gpa, &elf.mf);
11164 elf.nodes.set(@backingInt(ni), .deleted);
11165 node.* = .none;
11166}
11167
9243/// If `sym` has a PLT entry, returns the address of that entry (specifically, the address which a11168/// If `sym` has a PLT entry, returns the address of that entry (specifically, the address which a
9244/// branch to the PLT should target). If `sym` does not have a PLT entry, returns `null`.11169/// branch to the PLT should target). If `sym` does not have a PLT entry, returns `null`.
9245fn pltEntryTargetAddr(elf: *Elf, sym: Symbol.Id) ?u64 {11170fn pltEntryTargetAddr(elf: *Elf, sym: Symbol.Id) ?u64 {
src/link/MachO.zig+2-3
...@@ -3095,8 +3095,8 @@ pub fn updateNav(self: *MachO, pt: Zcu.PerThread, nav: InternPool.Nav.Index) lin...@@ -3095,8 +3095,8 @@ pub fn updateNav(self: *MachO, pt: Zcu.PerThread, nav: InternPool.Nav.Index) lin
3095 return self.getZigObject().?.updateNav(self, pt, nav);3095 return self.getZigObject().?.updateNav(self, pt, nav);
3096}3096}
30973097
3098pub fn updateLineNumber(self: *MachO, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) link.Error!void {3098pub fn updateLineNumber(self: *MachO, pt: Zcu.PerThread, inst: InternPool.TrackedInst.Index, line: u32) link.Error!void {
3099 return self.getZigObject().?.updateLineNumber(pt, ti_id);3099 return self.getZigObject().?.updateLineNumber(pt, inst, line);
3100}3100}
31013101
3102pub fn updateExports(3102pub fn updateExports(
...@@ -5503,4 +5503,3 @@ const Value = @import("../Value.zig");...@@ -5503,4 +5503,3 @@ const Value = @import("../Value.zig");
5503const UnwindInfo = @import("MachO/UnwindInfo.zig");5503const UnwindInfo = @import("MachO/UnwindInfo.zig");
5504const WeakBind = bind.WeakBind;5504const WeakBind = bind.WeakBind;
5505const ZigObject = @import("MachO/ZigObject.zig");5505const ZigObject = @import("MachO/ZigObject.zig");
5506const dev = @import("../dev.zig");
src/link/MachO/Atom.zig+2-2
...@@ -853,7 +853,7 @@ fn resolveRelocInner(...@@ -853,7 +853,7 @@ fn resolveRelocInner(
853853
854const x86_64 = struct {854const x86_64 = struct {
855 fn relaxGotLoad(self: Atom, code: []u8, rel: Relocation, macho_file: *MachO) ResolveError!void {855 fn relaxGotLoad(self: Atom, code: []u8, rel: Relocation, macho_file: *MachO) ResolveError!void {
856 dev.check(.x86_64_backend);856 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
857 const t = &macho_file.base.comp.root_mod.resolved_target.result;857 const t = &macho_file.base.comp.root_mod.resolved_target.result;
858 const diags = &macho_file.base.comp.link_diags;858 const diags = &macho_file.base.comp.link_diags;
859 const old_inst = disassemble(code) orelse return error.RelaxFail;859 const old_inst = disassemble(code) orelse return error.RelaxFail;
...@@ -879,7 +879,7 @@ const x86_64 = struct {...@@ -879,7 +879,7 @@ const x86_64 = struct {
879 }879 }
880880
881 fn relaxTlv(code: []u8, t: *const std.Target) error{RelaxFail}!void {881 fn relaxTlv(code: []u8, t: *const std.Target) error{RelaxFail}!void {
882 dev.check(.x86_64_backend);882 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
883 const old_inst = disassemble(code) orelse return error.RelaxFail;883 const old_inst = disassemble(code) orelse return error.RelaxFail;
884 switch (old_inst.encoding.mnemonic) {884 switch (old_inst.encoding.mnemonic) {
885 .mov => {885 .mov => {
src/link/MachO/Object.zig+5
...@@ -3,6 +3,7 @@ const Object = @This();...@@ -3,6 +3,7 @@ const Object = @This();
3const trace = @import("../../tracy.zig").trace;3const trace = @import("../../tracy.zig").trace;
4const Archive = @import("Archive.zig");4const Archive = @import("Archive.zig");
5const Atom = @import("Atom.zig");5const Atom = @import("Atom.zig");
6const dev = @import("../../dev.zig");
6const Dwarf = @import("Dwarf.zig");7const Dwarf = @import("Dwarf.zig");
7const File = @import("file.zig").File;8const File = @import("file.zig").File;
8const MachO = @import("../MachO.zig");9const MachO = @import("../MachO.zig");
...@@ -2826,6 +2827,7 @@ const x86_64 = struct {...@@ -2826,6 +2827,7 @@ const x86_64 = struct {
2826 handle: File.Handle,2827 handle: File.Handle,
2827 macho_file: *MachO,2828 macho_file: *MachO,
2828 ) !void {2829 ) !void {
2830 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
2829 const comp = macho_file.base.comp;2831 const comp = macho_file.base.comp;
2830 const io = comp.io;2832 const io = comp.io;
2831 const gpa = comp.gpa;2833 const gpa = comp.gpa;
...@@ -2938,6 +2940,7 @@ const x86_64 = struct {...@@ -2938,6 +2940,7 @@ const x86_64 = struct {
2938 }2940 }
29392941
2940 fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_x86_64, is_extern: bool) !Relocation.Type {2942 fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_x86_64, is_extern: bool) !Relocation.Type {
2943 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
2941 switch (rel_type) {2944 switch (rel_type) {
2942 .X86_64_RELOC_UNSIGNED => {2945 .X86_64_RELOC_UNSIGNED => {
2943 if (rel.r_pcrel == 1) return error.Pcrel;2946 if (rel.r_pcrel == 1) return error.Pcrel;
...@@ -2995,6 +2998,7 @@ const aarch64 = struct {...@@ -2995,6 +2998,7 @@ const aarch64 = struct {
2995 handle: File.Handle,2998 handle: File.Handle,
2996 macho_file: *MachO,2999 macho_file: *MachO,
2997 ) !void {3000 ) !void {
3001 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
2998 const comp = macho_file.base.comp;3002 const comp = macho_file.base.comp;
2999 const io = comp.io;3003 const io = comp.io;
3000 const gpa = comp.gpa;3004 const gpa = comp.gpa;
...@@ -3131,6 +3135,7 @@ const aarch64 = struct {...@@ -3131,6 +3135,7 @@ const aarch64 = struct {
3131 }3135 }
31323136
3133 fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_arm64, is_extern: bool) !Relocation.Type {3137 fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_arm64, is_extern: bool) !Relocation.Type {
3138 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
3134 switch (rel_type) {3139 switch (rel_type) {
3135 .ARM64_RELOC_UNSIGNED => {3140 .ARM64_RELOC_UNSIGNED => {
3136 if (rel.r_pcrel == 1) return error.Pcrel;3141 if (rel.r_pcrel == 1) return error.Pcrel;
src/link/MachO/ZigObject.zig+14-18
...@@ -647,14 +647,11 @@ pub fn getNavVAddr(...@@ -647,14 +647,11 @@ pub fn getNavVAddr(
647 },647 },
648 });648 });
649 },649 },
650 .debug_output => |debug_output| switch (debug_output) {650 .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
651 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{651 .source_off = @intCast(reloc_info.offset),
652 .source_off = @intCast(reloc_info.offset),652 .target_sym = @fromBackingInt(@intCast(sym_index)),
653 .target_sym = @fromBackingInt(@intCast(sym_index)),653 .target_off = reloc_info.addend,
654 .target_off = reloc_info.addend,654 }),
655 }),
656 .none => unreachable,
657 },
658 }655 }
659 return vaddr;656 return vaddr;
660}657}
...@@ -686,14 +683,11 @@ pub fn getUavVAddr(...@@ -686,14 +683,11 @@ pub fn getUavVAddr(
686 },683 },
687 });684 });
688 },685 },
689 .debug_output => |debug_output| switch (debug_output) {686 .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
690 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{687 .source_off = @intCast(reloc_info.offset),
691 .source_off = @intCast(reloc_info.offset),688 .target_sym = @fromBackingInt(@intCast(sym_index)),
692 .target_sym = @fromBackingInt(@intCast(sym_index)),689 .target_off = reloc_info.addend,
693 .target_off = reloc_info.addend,690 }),
694 }),
695 .none => unreachable,
696 },
697 }691 }
698 return vaddr;692 return vaddr;
699}693}
...@@ -1418,11 +1412,11 @@ fn updateLazySymbol(...@@ -1418,11 +1412,11 @@ fn updateLazySymbol(
1418 try macho_file.pwriteAll(code, file_offset);1412 try macho_file.pwriteAll(code, file_offset);
1419}1413}
14201414
1421pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) link.Error!void {1415pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index, line: u32) link.Error!void {
1422 if (self.dwarf) |*dwarf| {1416 if (self.dwarf) |*dwarf| {
1423 const comp = dwarf.bin_file.comp;1417 const comp = dwarf.bin_file.comp;
1424 const diags = &comp.link_diags;1418 const diags = &comp.link_diags;
1425 dwarf.updateLineNumber(pt.zcu, ti_id) catch |err| switch (err) {1419 dwarf.updateLineNumber(pt.zcu, ti_id, line) catch |err| switch (err) {
1426 error.OutOfMemory, error.Canceled, error.AlreadyReported => |e| return e,1420 error.OutOfMemory, error.Canceled, error.AlreadyReported => |e| return e,
1427 else => |e| return diags.fail("failed to update dwarf line numbers: {s}", .{@errorName(e)}),1421 else => |e| return diags.fail("failed to update dwarf line numbers: {s}", .{@errorName(e)}),
1428 };1422 };
...@@ -1750,6 +1744,7 @@ const TlvInitializerTable = std.array_hash_map.Auto(Atom.Index, TlvInitializer);...@@ -1750,6 +1744,7 @@ const TlvInitializerTable = std.array_hash_map.Auto(Atom.Index, TlvInitializer);
17501744
1751const x86_64 = struct {1745const x86_64 = struct {
1752 fn writeTrampolineCode(source_addr: u64, target_addr: u64, buf: *[max_trampoline_len]u8) ![]u8 {1746 fn writeTrampolineCode(source_addr: u64, target_addr: u64, buf: *[max_trampoline_len]u8) ![]u8 {
1747 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
1753 const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr)) - 5;1748 const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr)) - 5;
1754 var bytes = [_]u8{1749 var bytes = [_]u8{
1755 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel321750 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel32
...@@ -1764,6 +1759,7 @@ const x86_64 = struct {...@@ -1764,6 +1759,7 @@ const x86_64 = struct {
1764const assert = std.debug.assert;1759const assert = std.debug.assert;
1765const builtin = @import("builtin");1760const builtin = @import("builtin");
1766const codegen = @import("../../codegen.zig");1761const codegen = @import("../../codegen.zig");
1762const dev = @import("../../dev.zig");
1767const link = @import("../../link.zig");1763const link = @import("../../link.zig");
1768const log = std.log.scoped(.link);1764const log = std.log.scoped(.link);
1769const macho = std.macho;1765const macho = std.macho;
src/link/MappedFile.zig+73-57
...@@ -362,7 +362,7 @@ pub const Node = extern struct {...@@ -362,7 +362,7 @@ pub const Node = extern struct {
362 }362 }
363363
364 /// Adds a floating child node to `parent_ni`. Returns the index of the new child.364 /// Adds a floating child node to `parent_ni`. Returns the index of the new child.
365 pub fn addFloatingChild(parent_ni: Node.Index, mf: *MappedFile, gpa: Allocator, opts: AddOptions) Error!Node.Index {365 pub fn addFloatingChild(parent_ni: Node.Index, gpa: Allocator, mf: *MappedFile, opts: AddOptions) Error!Node.Index {
366 return mf.addNode(gpa, .{366 return mf.addNode(gpa, .{
367 .add_options = opts,367 .add_options = opts,
368 .position = .floating,368 .position = .floating,
...@@ -373,11 +373,11 @@ pub const Node = extern struct {...@@ -373,11 +373,11 @@ pub const Node = extern struct {
373 /// Adds a header child node to `parent_ni`. Returns the index of the new child.373 /// Adds a header child node to `parent_ni`. Returns the index of the new child.
374 ///374 ///
375 /// Asserts that `parent_ni` has no existing header children.375 /// Asserts that `parent_ni` has no existing header children.
376 pub fn addOnlyHeaderChild(parent_ni: Node.Index, mf: *MappedFile, gpa: Allocator, opts: AddOptions) Error!Node.Index {376 pub fn addOnlyHeaderChild(parent_ni: Node.Index, gpa: Allocator, mf: *MappedFile, opts: AddOptions) Error!Node.Index {
377 if (parent_ni.first(mf).unwrap()) |first_ni| {377 if (parent_ni.first(mf).unwrap()) |first_ni| {
378 assert(first_ni.position(mf) != .header); // `parent_ni` already has a header child378 assert(first_ni.position(mf) != .header); // `parent_ni` already has a header child
379 }379 }
380 return parent_ni.addHeaderChildAfter(mf, gpa, .none, opts);380 return parent_ni.addHeaderChildAfter(gpa, mf, .none, opts);
381 }381 }
382 /// Adds a header child node to `parent_ni`. Returns the index of the new child.382 /// Adds a header child node to `parent_ni`. Returns the index of the new child.
383 ///383 ///
...@@ -386,7 +386,7 @@ pub const Node = extern struct {...@@ -386,7 +386,7 @@ pub const Node = extern struct {
386 ///386 ///
387 /// Otherwise, asserts that `prev_oni` is a header node and a child of `parent_ni`, and387 /// Otherwise, asserts that `prev_oni` is a header node and a child of `parent_ni`, and
388 /// places the new child node immediately after `prev_oni`.388 /// places the new child node immediately after `prev_oni`.
389 pub fn addHeaderChildAfter(parent_ni: Node.Index, mf: *MappedFile, gpa: Allocator, prev_oni: Node.Index.Optional, opts: AddOptions) Error!Node.Index {389 pub fn addHeaderChildAfter(parent_ni: Node.Index, gpa: Allocator, mf: *MappedFile, prev_oni: Node.Index.Optional, opts: AddOptions) Error!Node.Index {
390 return mf.addNode(gpa, .{390 return mf.addNode(gpa, .{
391 .add_options = opts,391 .add_options = opts,
392 .position = .header,392 .position = .header,
...@@ -397,11 +397,11 @@ pub const Node = extern struct {...@@ -397,11 +397,11 @@ pub const Node = extern struct {
397 /// Adds a footer child node to `parent_ni`. Returns the index of the new child.397 /// Adds a footer child node to `parent_ni`. Returns the index of the new child.
398 ///398 ///
399 /// Asserts that `parent_ni` has no existing footer children.399 /// Asserts that `parent_ni` has no existing footer children.
400 pub fn addOnlyFooterChild(parent_ni: Node.Index, mf: *MappedFile, gpa: Allocator, opts: AddOptions) Error!Node.Index {400 pub fn addOnlyFooterChild(parent_ni: Node.Index, gpa: Allocator, mf: *MappedFile, opts: AddOptions) Error!Node.Index {
401 if (parent_ni.last(mf).unwrap()) |last_ni| {401 if (parent_ni.last(mf).unwrap()) |last_ni| {
402 assert(last_ni.position(mf) != .footer); // `parent_ni` already has a footer child402 assert(last_ni.position(mf) != .footer); // `parent_ni` already has a footer child
403 }403 }
404 return parent_ni.addFooterChildBefore(mf, gpa, .none, opts);404 return parent_ni.addFooterChildBefore(gpa, mf, .none, opts);
405 }405 }
406 /// Adds a footer child node to `parent_ni`. Returns the index of the new child.406 /// Adds a footer child node to `parent_ni`. Returns the index of the new child.
407 ///407 ///
...@@ -410,7 +410,7 @@ pub const Node = extern struct {...@@ -410,7 +410,7 @@ pub const Node = extern struct {
410 ///410 ///
411 /// Otherwise, asserts that `next_oni` is a footer node and a child of `parent_ni`, and411 /// Otherwise, asserts that `next_oni` is a footer node and a child of `parent_ni`, and
412 /// places the new child node immediately before `next_oni`.412 /// places the new child node immediately before `next_oni`.
413 pub fn addFooterChildBefore(parent_ni: Node.Index, mf: *MappedFile, gpa: Allocator, next_oni: Node.Index.Optional, opts: AddOptions) Error!Node.Index {413 pub fn addFooterChildBefore(parent_ni: Node.Index, gpa: Allocator, mf: *MappedFile, next_oni: Node.Index.Optional, opts: AddOptions) Error!Node.Index {
414 const prev_oni: Node.Index.Optional = prev: {414 const prev_oni: Node.Index.Optional = prev: {
415 const next_ni = next_oni.unwrap() orelse {415 const next_ni = next_oni.unwrap() orelse {
416 break :prev parent_ni.last(mf);416 break :prev parent_ni.last(mf);
...@@ -473,8 +473,8 @@ pub const Node = extern struct {...@@ -473,8 +473,8 @@ pub const Node = extern struct {
473 fn setNext(473 fn setNext(
474 ni: Node.Index,474 ni: Node.Index,
475 gpa: Allocator,475 gpa: Allocator,
476 next_ni: Node.Index.Optional,
477 mf: *MappedFile,476 mf: *MappedFile,
477 next_ni: Node.Index.Optional,
478 ) Allocator.Error!void {478 ) Allocator.Error!void {
479 const next_ptr = &ni.get(mf).next;479 const next_ptr = &ni.get(mf).next;
480 if (next_ptr.* == next_ni) return;480 if (next_ptr.* == next_ni) return;
...@@ -514,12 +514,10 @@ pub const Node = extern struct {...@@ -514,12 +514,10 @@ pub const Node = extern struct {
514 return node_moved.*;514 return node_moved.*;
515 }515 }
516 pub fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {516 pub fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
517 if (ni.hasMoved(mf)) return;
518 const node = ni.get(mf);517 const node = ni.get(mf);
518 if (node.prev.unwrap()) |prev_ni| prev_ni.nextMovedAssumeCapacity(mf);
519 if (ni.hasMoved(mf)) return;
519 node.flags.moved = true;520 node.flags.moved = true;
520 if (node.prev.unwrap()) |prev_ni| {
521 prev_ni.nextMovedAssumeCapacity(mf);
522 }
523 if (node.flags.resized or node.flags.next_moved) return;521 if (node.flags.resized or node.flags.next_moved) return;
524 mf.updates.appendAssumeCapacity(ni);522 mf.updates.appendAssumeCapacity(ni);
525 mf.update_prog_node.increaseEstimatedTotalItems(1);523 mf.update_prog_node.increaseEstimatedTotalItems(1);
...@@ -571,7 +569,7 @@ pub const Node = extern struct {...@@ -571,7 +569,7 @@ pub const Node = extern struct {
571 return ni.get(mf).flags.alignment;569 return ni.get(mf).flags.alignment;
572 }570 }
573571
574 fn setLocation(ni: Node.Index, mf: *MappedFile, gpa: Allocator, offset: u64, size: u64) Allocator.Error!void {572 fn setLocation(ni: Node.Index, gpa: Allocator, mf: *MappedFile, offset: u64, size: u64) Allocator.Error!void {
575 try mf.large.ensureUnusedCapacity(gpa, 2);573 try mf.large.ensureUnusedCapacity(gpa, 2);
576 try mf.updates.ensureUnusedCapacity(gpa, 2);574 try mf.updates.ensureUnusedCapacity(gpa, 2);
577 const node = ni.get(mf);575 const node = ni.get(mf);
...@@ -636,15 +634,38 @@ pub const Node = extern struct {...@@ -636,15 +634,38 @@ pub const Node = extern struct {
636 return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];634 return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
637 }635 }
638636
637 pub fn slicePadding(ni: Node.Index, mf: *const MappedFile) []u8 {
638 const file_loc = ni.fileLocation(mf, false);
639 return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
640 }
641
639 pub fn sliceConst(ni: Node.Index, mf: *const MappedFile) []const u8 {642 pub fn sliceConst(ni: Node.Index, mf: *const MappedFile) []const u8 {
640 const file_loc = ni.fileLocation(mf, false);643 const file_loc = ni.fileLocation(mf, false);
641 return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];644 return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
642 }645 }
643646
647 pub fn delete(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void {
648 const node = ni.get(mf);
649 assert(node.first == .none and node.last == .none); // has children
650 mf.removeNodesFromChildList(gpa, ni, ni);
651 const updated = node.flags.moved or node.flags.resized or node.flags.next_moved;
652 node.* = undefined;
653 node.next = ni.toOptional();
654 if (!updated) assert(ni.pendingDelete(mf));
655 }
656
657 pub fn pendingDelete(ni: Node.Index, mf: *MappedFile) bool {
658 const node = ni.get(mf);
659 if (node.next != ni.toOptional()) return false;
660 node.next = mf.free_ni;
661 mf.free_ni = ni.toOptional();
662 return true;
663 }
664
644 /// Ensures that the size of `ni` is at least `min_size`. Valid for any node.665 /// Ensures that the size of `ni` is at least `min_size`. Valid for any node.
645 ///666 ///
646 /// Applies `growth_factor` if necessary (so the caller should *not* apply `growth_factor`).667 /// Applies `growth_factor` if necessary (so the caller should *not* apply `growth_factor`).
647 pub fn ensureMinimumSize(ni: Node.Index, mf: *MappedFile, gpa: Allocator, min_size: u64) Error!void {668 pub fn ensureMinimumSize(ni: Node.Index, gpa: Allocator, mf: *MappedFile, min_size: u64) Error!void {
648 _, const current_size = ni.location(mf).resolve(mf);669 _, const current_size = ni.location(mf).resolve(mf);
649 if (current_size >= min_size) return;670 if (current_size >= min_size) return;
650 const new_size = ni.alignment(mf).forward(min_size +| min_size / growth_factor);671 const new_size = ni.alignment(mf).forward(min_size +| min_size / growth_factor);
...@@ -660,7 +681,7 @@ pub const Node = extern struct {...@@ -660,7 +681,7 @@ pub const Node = extern struct {
660 /// Asserts that `ni` is a leaf node, i.e. has no children.681 /// Asserts that `ni` is a leaf node, i.e. has no children.
661 ///682 ///
662 /// Asserts that `size` is aligned to `ni.alignment(mf)`.683 /// Asserts that `size` is aligned to `ni.alignment(mf)`.
663 pub fn resizeLeaf(ni: Node.Index, mf: *MappedFile, gpa: Allocator, size: u64) Error!void {684 pub fn resizeLeaf(ni: Node.Index, gpa: Allocator, mf: *MappedFile, size: u64) Error!void {
664 assert(ni.first(mf) == .none);685 assert(ni.first(mf) == .none);
665 // The alignment of `size` is asserted by `shrinkLeafNode` and `growNode`.686 // The alignment of `size` is asserted by `shrinkLeafNode` and `growNode`.
666 _, const old_size = ni.location(mf).resolve(mf);687 _, const old_size = ni.location(mf).resolve(mf);
...@@ -680,17 +701,12 @@ pub const Node = extern struct {...@@ -680,17 +701,12 @@ pub const Node = extern struct {
680 /// If the node's current offset or size is not sufficiently aligned, it will be moved701 /// If the node's current offset or size is not sufficiently aligned, it will be moved
681 /// and/or resized to match the new alignment. The node's size may be increased by any702 /// and/or resized to match the new alignment. The node's size may be increased by any
682 /// amount, as if `ensureMinimumSize` were used.703 /// amount, as if `ensureMinimumSize` were used.
683 pub fn realign(704 pub fn realign(ni: Node.Index, gpa: Allocator, mf: *MappedFile, new_alignment: Alignment) Error!void {
684 ni: Node.Index,
685 mf: *MappedFile,
686 gpa: Allocator,
687 new_alignment: Alignment,
688 ) Error!void {
689 try mf.realignNode(gpa, ni, new_alignment);705 try mf.realignNode(gpa, ni, new_alignment);
690 mf.updateWriters();706 mf.updateWriters();
691 }707 }
692708
693 pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: Allocator, w: *Writer) void {709 pub fn writer(ni: Node.Index, gpa: Allocator, mf: *MappedFile, w: *Writer) void {
694 w.* = .{710 w.* = .{
695 .gpa = gpa,711 .gpa = gpa,
696 .mf = mf,712 .mf = mf,
...@@ -820,7 +836,7 @@ pub const Node = extern struct {...@@ -820,7 +836,7 @@ pub const Node = extern struct {
820 ) Io.Writer.Error!void {836 ) Io.Writer.Error!void {
821 _ = preserve;837 _ = preserve;
822 const w: *Writer = @fieldParentPtr("interface", interface);838 const w: *Writer = @fieldParentPtr("interface", interface);
823 w.ni.ensureMinimumSize(w.mf, w.gpa, interface.end + unused_capacity) catch |err| {839 w.ni.ensureMinimumSize(w.gpa, w.mf, interface.end + unused_capacity) catch |err| {
824 w.err = err;840 w.err = err;
825 return error.WriteFailed;841 return error.WriteFailed;
826 };842 };
...@@ -992,7 +1008,7 @@ fn shrinkLeafNode(...@@ -992,7 +1008,7 @@ fn shrinkLeafNode(
992 },1008 },
993 };1009 };
994 try mf.ensureTotalCapacityPrecise(@intCast(new_size));1010 try mf.ensureTotalCapacityPrecise(@intCast(new_size));
995 try ni.setLocation(mf, gpa, old_offset, new_size);1011 try ni.setLocation(gpa, mf, old_offset, new_size);
996 return;1012 return;
997 };1013 };
9981014
...@@ -1000,7 +1016,7 @@ fn shrinkLeafNode(...@@ -1000,7 +1016,7 @@ fn shrinkLeafNode(
1000 .header => {1016 .header => {
1001 const shift = old_size - new_size;1017 const shift = old_size - new_size;
10021018
1003 try ni.setLocation(mf, gpa, old_offset, new_size);1019 try ni.setLocation(gpa, mf, old_offset, new_size);
10041020
1005 // We need to shift backwards all header nodes following us.1021 // We need to shift backwards all header nodes following us.
1006 const next_header_ni = ni.next(mf).unwrap() orelse return;1022 const next_header_ni = ni.next(mf).unwrap() orelse return;
...@@ -1009,7 +1025,7 @@ fn shrinkLeafNode(...@@ -1009,7 +1025,7 @@ fn shrinkLeafNode(
1009 var header_ni = next_header_ni;1025 var header_ni = next_header_ni;
1010 while (true) {1026 while (true) {
1011 const old_header_off, const old_header_size = header_ni.location(mf).resolve(mf);1027 const old_header_off, const old_header_size = header_ni.location(mf).resolve(mf);
1012 try header_ni.setLocation(mf, gpa, old_header_off - shift, old_header_size);1028 try header_ni.setLocation(gpa, mf, old_header_off - shift, old_header_size);
10131029
1014 const next_ni = header_ni.next(mf).unwrap() orelse break;1030 const next_ni = header_ni.next(mf).unwrap() orelse break;
1015 if (next_ni.position(mf) != .header) break;1031 if (next_ni.position(mf) != .header) break;
...@@ -1034,13 +1050,13 @@ fn shrinkLeafNode(...@@ -1034,13 +1050,13 @@ fn shrinkLeafNode(
1034 );1050 );
1035 },1051 },
1036 .floating => {1052 .floating => {
1037 try ni.setLocation(mf, gpa, old_offset, new_size);1053 try ni.setLocation(gpa, mf, old_offset, new_size);
1038 },1054 },
1039 .footer => {1055 .footer => {
1040 const shift = old_size - new_size;1056 const shift = old_size - new_size;
10411057
1042 const new_offset = old_offset + shift;1058 const new_offset = old_offset + shift;
1043 try ni.setLocation(mf, gpa, new_offset, new_size);1059 try ni.setLocation(gpa, mf, new_offset, new_size);
10441060
1045 const prev_footers_size = prev_footers_size: {1061 const prev_footers_size = prev_footers_size: {
1046 // We need to shift forwards all footer nodes preceding us.1062 // We need to shift forwards all footer nodes preceding us.
...@@ -1054,7 +1070,7 @@ fn shrinkLeafNode(...@@ -1054,7 +1070,7 @@ fn shrinkLeafNode(
1054 var footer_ni = prev_footer_ni;1070 var footer_ni = prev_footer_ni;
1055 while (true) {1071 while (true) {
1056 const old_footer_off, const old_footer_size = footer_ni.location(mf).resolve(mf);1072 const old_footer_off, const old_footer_size = footer_ni.location(mf).resolve(mf);
1057 try footer_ni.setLocation(mf, gpa, old_footer_off + shift, old_footer_size);1073 try footer_ni.setLocation(gpa, mf, old_footer_off + shift, old_footer_size);
10581074
1059 const prev_ni = footer_ni.prev(mf).unwrap() orelse break;1075 const prev_ni = footer_ni.prev(mf).unwrap() orelse break;
1060 if (prev_ni.position(mf) != .footer) break;1076 if (prev_ni.position(mf) != .footer) break;
...@@ -1137,7 +1153,7 @@ fn growNode(...@@ -1137,7 +1153,7 @@ fn growNode(
1137 },1153 },
1138 };1154 };
1139 try mf.ensureTotalCapacityPrecise(@intCast(new_size));1155 try mf.ensureTotalCapacityPrecise(@intCast(new_size));
1140 try ni.setLocation(mf, gpa, old_offset, new_size);1156 try ni.setLocation(gpa, mf, old_offset, new_size);
1141 if (grow_options.move_footers) {1157 if (grow_options.move_footers) {
1142 // We need to move any footers to be at the *new* end of the file.1158 // We need to move any footers to be at the *new* end of the file.
1143 if (ni.firstFooter(mf).unwrap()) |first_footer_ni| {1159 if (ni.firstFooter(mf).unwrap()) |first_footer_ni| {
...@@ -1152,7 +1168,7 @@ fn growNode(...@@ -1152,7 +1168,7 @@ fn growNode(
1152 var cur_ni = first_footer_ni;1168 var cur_ni = first_footer_ni;
1153 while (true) {1169 while (true) {
1154 const old_footer_offset, const footer_size = cur_ni.location(mf).resolve(mf);1170 const old_footer_offset, const footer_size = cur_ni.location(mf).resolve(mf);
1155 try cur_ni.setLocation(mf, gpa, old_footer_offset + (new_size - old_size), footer_size);1171 try cur_ni.setLocation(gpa, mf, old_footer_offset + (new_size - old_size), footer_size);
1156 cur_ni = cur_ni.next(mf).unwrap() orelse break;1172 cur_ni = cur_ni.next(mf).unwrap() orelse break;
1157 }1173 }
1158 }1174 }
...@@ -1211,8 +1227,8 @@ fn growNode(...@@ -1211,8 +1227,8 @@ fn growNode(
1211 while (true) {1227 while (true) {
1212 const old_sub_footer_offset, const sub_footer_size = cur_ni.location(mf).resolve(mf);1228 const old_sub_footer_offset, const sub_footer_size = cur_ni.location(mf).resolve(mf);
1213 try cur_ni.setLocation(1229 try cur_ni.setLocation(
1214 mf,
1215 gpa,1230 gpa,
1231 mf,
1216 old_sub_footer_offset + (new_size - old_size),1232 old_sub_footer_offset + (new_size - old_size),
1217 sub_footer_size,1233 sub_footer_size,
1218 );1234 );
...@@ -1227,8 +1243,8 @@ fn growNode(...@@ -1227,8 +1243,8 @@ fn growNode(
1227 assert(moved_header_ni.position(mf) == .header);1243 assert(moved_header_ni.position(mf) == .header);
1228 const moved_header_offset, const moved_header_size = moved_header_ni.location(mf).resolve(mf);1244 const moved_header_offset, const moved_header_size = moved_header_ni.location(mf).resolve(mf);
1229 try moved_header_ni.setLocation(1245 try moved_header_ni.setLocation(
1230 mf,
1231 gpa,1246 gpa,
1247 mf,
1232 moved_header_offset - old_size + new_size,1248 moved_header_offset - old_size + new_size,
1233 moved_header_size,1249 moved_header_size,
1234 );1250 );
...@@ -1237,7 +1253,7 @@ fn growNode(...@@ -1237,7 +1253,7 @@ fn growNode(
1237 }1253 }
12381254
1239 // Finally, update our own size:1255 // Finally, update our own size:
1240 try ni.setLocation(mf, gpa, old_offset, new_size);1256 try ni.setLocation(gpa, mf, old_offset, new_size);
1241 return;1257 return;
1242 },1258 },
1243 .floating => {1259 .floating => {
...@@ -1365,8 +1381,8 @@ fn growNode(...@@ -1365,8 +1381,8 @@ fn growNode(
13651381
1366 // Update our own offset and size:1382 // Update our own offset and size:
1367 try ni.setLocation(1383 try ni.setLocation(
1368 mf,
1369 gpa,1384 gpa,
1385 mf,
1370 node.location().resolve(mf)[0] - shift,1386 node.location().resolve(mf)[0] - shift,
1371 new_size,1387 new_size,
1372 );1388 );
...@@ -1377,7 +1393,7 @@ fn growNode(...@@ -1377,7 +1393,7 @@ fn growNode(
1377 var footer_oni = first_sub_footer_oni;1393 var footer_oni = first_sub_footer_oni;
1378 while (footer_oni.unwrap()) |footer_ni| : (footer_oni = footer_ni.next(mf)) {1394 while (footer_oni.unwrap()) |footer_ni| : (footer_oni = footer_ni.next(mf)) {
1379 const old_footer_offset, const footer_size = footer_ni.location(mf).resolve(mf);1395 const old_footer_offset, const footer_size = footer_ni.location(mf).resolve(mf);
1380 try footer_ni.setLocation(mf, gpa, old_footer_offset + shift, footer_size);1396 try footer_ni.setLocation(gpa, mf, old_footer_offset + shift, footer_size);
1381 }1397 }
1382 }1398 }
13831399
...@@ -1392,7 +1408,7 @@ fn growNode(...@@ -1392,7 +1408,7 @@ fn growNode(
1392 while (footer_ni != ni) : (footer_ni = footer_ni.next(mf).unwrap().?) {1408 while (footer_ni != ni) : (footer_ni = footer_ni.next(mf).unwrap().?) {
1393 moved_has_content = moved_has_content or footer_ni.get(mf).flags.has_content;1409 moved_has_content = moved_has_content or footer_ni.get(mf).flags.has_content;
1394 const old_footer_offset, const footer_size = footer_ni.location(mf).resolve(mf);1410 const old_footer_offset, const footer_size = footer_ni.location(mf).resolve(mf);
1395 try footer_ni.setLocation(mf, gpa, old_footer_offset - shift, footer_size);1411 try footer_ni.setLocation(gpa, mf, old_footer_offset - shift, footer_size);
1396 }1412 }
1397 }1413 }
13981414
...@@ -1444,8 +1460,8 @@ fn growNode(...@@ -1444,8 +1460,8 @@ fn growNode(
1444 }1460 }
14451461
1446 try ni.setLocation(1462 try ni.setLocation(
1447 mf,
1448 gpa,1463 gpa,
1464 mf,
1449 node.location().resolve(mf)[0],1465 node.location().resolve(mf)[0],
1450 actual_new_size,1466 actual_new_size,
1451 );1467 );
...@@ -1461,7 +1477,7 @@ fn growNode(...@@ -1461,7 +1477,7 @@ fn growNode(
1461 assert(footer_ni.position(mf) == .footer);1477 assert(footer_ni.position(mf) == .footer);
1462 moved_has_content = moved_has_content or footer_ni.get(mf).flags.has_content;1478 moved_has_content = moved_has_content or footer_ni.get(mf).flags.has_content;
1463 const footer_old_offset: u64, const footer_size: u64 = footer_ni.location(mf).resolve(mf);1479 const footer_old_offset: u64, const footer_size: u64 = footer_ni.location(mf).resolve(mf);
1464 try footer_ni.setLocation(mf, gpa, footer_old_offset + shift, footer_size);1480 try footer_ni.setLocation(gpa, mf, footer_old_offset + shift, footer_size);
1465 }1481 }
1466 }1482 }
14671483
...@@ -1472,7 +1488,7 @@ fn growNode(...@@ -1472,7 +1488,7 @@ fn growNode(
1472 assert(footer_ni.position(mf) == .footer);1488 assert(footer_ni.position(mf) == .footer);
1473 moved_has_content = moved_has_content or footer_ni.get(mf).flags.has_content;1489 moved_has_content = moved_has_content or footer_ni.get(mf).flags.has_content;
1474 const footer_old_offset: u64, const footer_size: u64 = footer_ni.location(mf).resolve(mf);1490 const footer_old_offset: u64, const footer_size: u64 = footer_ni.location(mf).resolve(mf);
1475 try footer_ni.setLocation(mf, gpa, footer_old_offset + shift, footer_size);1491 try footer_ni.setLocation(gpa, mf, footer_old_offset + shift, footer_size);
1476 }1492 }
1477 }1493 }
14781494
...@@ -1544,7 +1560,7 @@ fn growFloatingNodeWithAlignment(...@@ -1544,7 +1560,7 @@ fn growFloatingNodeWithAlignment(
1544 break :grow_in_place; // the parent is not big enough1560 break :grow_in_place; // the parent is not big enough
1545 }1561 }
1546 // Great, we can grow this node without changing its offset or moving any siblings.1562 // Great, we can grow this node without changing its offset or moving any siblings.
1547 try ni.setLocation(mf, gpa, old_offset, new_size);1563 try ni.setLocation(gpa, mf, old_offset, new_size);
1548 if (grow_options.move_footers) {1564 if (grow_options.move_footers) {
1549 // If we have any footers, we need to move them to the end of our new size, and update1565 // If we have any footers, we need to move them to the end of our new size, and update
1550 // their offsets accordingly.1566 // their offsets accordingly.
...@@ -1554,7 +1570,7 @@ fn growFloatingNodeWithAlignment(...@@ -1554,7 +1570,7 @@ fn growFloatingNodeWithAlignment(
1554 while (true) {1570 while (true) {
1555 footers_have_content = footers_have_content or cur_ni.get(mf).flags.has_content;1571 footers_have_content = footers_have_content or cur_ni.get(mf).flags.has_content;
1556 const old_footer_offset, const footer_size = cur_ni.location(mf).resolve(mf);1572 const old_footer_offset, const footer_size = cur_ni.location(mf).resolve(mf);
1557 try cur_ni.setLocation(mf, gpa, old_footer_offset + (new_size - old_size), footer_size);1573 try cur_ni.setLocation(gpa, mf, old_footer_offset + (new_size - old_size), footer_size);
1558 cur_ni = cur_ni.next(mf).unwrap() orelse break;1574 cur_ni = cur_ni.next(mf).unwrap() orelse break;
1559 }1575 }
1560 if (footers_have_content) {1576 if (footers_have_content) {
...@@ -1691,7 +1707,7 @@ fn growFloatingNodeWithAlignment(...@@ -1691,7 +1707,7 @@ fn growFloatingNodeWithAlignment(
1691 footers_have_content = footers_have_content or cur_ni.get(mf).flags.has_content;1707 footers_have_content = footers_have_content or cur_ni.get(mf).flags.has_content;
1692 const old_footer_offset, const footer_size = cur_ni.location(mf).resolve(mf);1708 const old_footer_offset, const footer_size = cur_ni.location(mf).resolve(mf);
1693 // Our footers' offsets must change to be at the end of our new size.1709 // Our footers' offsets must change to be at the end of our new size.
1694 try cur_ni.setLocation(mf, gpa, old_footer_offset + (new_size - old_size), footer_size);1710 try cur_ni.setLocation(gpa, mf, old_footer_offset + (new_size - old_size), footer_size);
1695 cur_ni = cur_ni.next(mf).unwrap() orelse break;1711 cur_ni = cur_ni.next(mf).unwrap() orelse break;
1696 }1712 }
16971713
...@@ -1718,7 +1734,7 @@ fn growFloatingNodeWithAlignment(...@@ -1718,7 +1734,7 @@ fn growFloatingNodeWithAlignment(
1718 assert(!footers_have_content);1734 assert(!footers_have_content);
1719 }1735 }
17201736
1721 try ni.setLocation(mf, gpa, new_loc.offset, new_size);1737 try ni.setLocation(gpa, mf, new_loc.offset, new_size);
17221738
1723 if (new_loc.prev != ni.toOptional()) {1739 if (new_loc.prev != ni.toOptional()) {
1724 // We're potentially in a different place in `parent_ni`'s child list, so remove and re-add ourselves.1740 // We're potentially in a different place in `parent_ni`'s child list, so remove and re-add ourselves.
...@@ -1918,11 +1934,11 @@ fn growNodeViaInsertRange(...@@ -1918,11 +1934,11 @@ fn growNodeViaInsertRange(
1918 if (cur_ni == .root) {1934 if (cur_ni == .root) {
1919 try mf.ensureTotalCapacityPrecise(@intCast(this_old_size + range_size));1935 try mf.ensureTotalCapacityPrecise(@intCast(this_old_size + range_size));
1920 }1936 }
1921 try cur_ni.setLocation(mf, gpa, this_offset, this_old_size + range_size);1937 try cur_ni.setLocation(gpa, mf, this_offset, this_old_size + range_size);
19221938
1923 while (cur_ni.next(mf).unwrap()) |next_ni| {1939 while (cur_ni.next(mf).unwrap()) |next_ni| {
1924 const next_old_offset, const next_size = next_ni.location(mf).resolve(mf);1940 const next_old_offset, const next_size = next_ni.location(mf).resolve(mf);
1925 try next_ni.setLocation(mf, gpa, next_old_offset + range_size, next_size);1941 try next_ni.setLocation(gpa, mf, next_old_offset + range_size, next_size);
1926 cur_ni = next_ni;1942 cur_ni = next_ni;
1927 }1943 }
19281944
...@@ -1935,7 +1951,7 @@ fn growNodeViaInsertRange(...@@ -1935,7 +1951,7 @@ fn growNodeViaInsertRange(
1935 var footer_ni = first_footer_ni;1951 var footer_ni = first_footer_ni;
1936 while (true) {1952 while (true) {
1937 const old_footer_offset, const footer_size = footer_ni.location(mf).resolve(mf);1953 const old_footer_offset, const footer_size = footer_ni.location(mf).resolve(mf);
1938 try footer_ni.setLocation(mf, gpa, old_footer_offset + range_size, footer_size);1954 try footer_ni.setLocation(gpa, mf, old_footer_offset + range_size, footer_size);
1939 footer_ni = footer_ni.next(mf).unwrap() orelse break;1955 footer_ni = footer_ni.next(mf).unwrap() orelse break;
1940 }1956 }
1941 }1957 }
...@@ -2103,7 +2119,7 @@ fn ensureAdditionalHeaderCapacity(...@@ -2103,7 +2119,7 @@ fn ensureAdditionalHeaderCapacity(
2103 const old_offset, const old_size = cur_ni.location(mf).resolve(mf);2119 const old_offset, const old_size = cur_ni.location(mf).resolve(mf);
2104 const new_offset = old_offset - moving_offset + dest_offset;2120 const new_offset = old_offset - moving_offset + dest_offset;
2105 assert(cur_ni.alignment(mf).check(new_offset));2121 assert(cur_ni.alignment(mf).check(new_offset));
2106 try cur_ni.setLocation(mf, gpa, new_offset, old_size);2122 try cur_ni.setLocation(gpa, mf, new_offset, old_size);
2107 if (cur_ni == last_moving_ni) break;2123 if (cur_ni == last_moving_ni) break;
2108 cur_ni = cur_ni.next(mf).unwrap().?;2124 cur_ni = cur_ni.next(mf).unwrap().?;
2109 }2125 }
...@@ -2146,7 +2162,7 @@ fn removeNodesFromChildList(...@@ -2146,7 +2162,7 @@ fn removeNodesFromChildList(
21462162
2147 if (prev_oni.unwrap()) |prev_ni| {2163 if (prev_oni.unwrap()) |prev_ni| {
2148 assert(prev_ni.next(mf).unwrap().? == first_remove_ni);2164 assert(prev_ni.next(mf).unwrap().? == first_remove_ni);
2149 try prev_ni.setNext(gpa, next_oni, mf);2165 try prev_ni.setNext(gpa, mf, next_oni);
2150 } else {2166 } else {
2151 assert(parent_ni.first(mf).unwrap().? == first_remove_ni);2167 assert(parent_ni.first(mf).unwrap().? == first_remove_ni);
2152 parent_ni.get(mf).first = next_oni;2168 parent_ni.get(mf).first = next_oni;
...@@ -2185,11 +2201,11 @@ fn addNodesToChildListBefore(...@@ -2185,11 +2201,11 @@ fn addNodesToChildListBefore(
2185 };2201 };
21862202
2187 first_add_ni.get(mf).prev = prev_oni;2203 first_add_ni.get(mf).prev = prev_oni;
2188 try last_add_ni.setNext(gpa, next_oni, mf);2204 try last_add_ni.setNext(gpa, mf, next_oni);
21892205
2190 if (prev_oni.unwrap()) |prev_ni| {2206 if (prev_oni.unwrap()) |prev_ni| {
2191 assert(prev_ni.next(mf) == next_oni);2207 assert(prev_ni.next(mf) == next_oni);
2192 try prev_ni.setNext(gpa, .wrap(first_add_ni), mf);2208 try prev_ni.setNext(gpa, mf, .wrap(first_add_ni));
2193 } else {2209 } else {
2194 assert(parent_ni.first(mf) == next_oni);2210 assert(parent_ni.first(mf) == next_oni);
2195 parent_ni.get(mf).first = .wrap(first_add_ni);2211 parent_ni.get(mf).first = .wrap(first_add_ni);
...@@ -2630,7 +2646,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {...@@ -2630,7 +2646,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {
2630 for (1..n) |_| cur_ni = cur_ni.next(&mf).unwrap().?;2646 for (1..n) |_| cur_ni = cur_ni.next(&mf).unwrap().?;
2631 break :prev_oni .wrap(cur_ni);2647 break :prev_oni .wrap(cur_ni);
2632 };2648 };
2633 const new_ni = try parent_ni.addHeaderChildAfter(&mf, gpa, prev_oni, .{2649 const new_ni = try parent_ni.addHeaderChildAfter(gpa, &mf, prev_oni, .{
2634 .size = size,2650 .size = size,
2635 .alignment = alignment,2651 .alignment = alignment,
2636 });2652 });
...@@ -2638,7 +2654,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {...@@ -2638,7 +2654,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {
2638 break :new_ni new_ni;2654 break :new_ni new_ni;
2639 },2655 },
26402656
2641 .floating => try parent_ni.addFloatingChild(&mf, gpa, .{2657 .floating => try parent_ni.addFloatingChild(gpa, &mf, .{
2642 .size = size,2658 .size = size,
2643 .alignment = alignment,2659 .alignment = alignment,
2644 }),2660 }),
...@@ -2652,7 +2668,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {...@@ -2652,7 +2668,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {
2652 for (1..n) |_| cur_ni = cur_ni.prev(&mf).unwrap().?;2668 for (1..n) |_| cur_ni = cur_ni.prev(&mf).unwrap().?;
2653 break :next_oni .wrap(cur_ni);2669 break :next_oni .wrap(cur_ni);
2654 };2670 };
2655 const new_ni = try parent_ni.addFooterChildBefore(&mf, gpa, next_oni, .{2671 const new_ni = try parent_ni.addFooterChildBefore(gpa, &mf, next_oni, .{
2656 .size = size,2672 .size = size,
2657 .alignment = alignment,2673 .alignment = alignment,
2658 });2674 });
...@@ -2686,13 +2702,13 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {...@@ -2686,13 +2702,13 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {
2686 if (ni.first(&mf) == .none and smith.value(bool)) {2702 if (ni.first(&mf) == .none and smith.value(bool)) {
2687 // Since this is a leaf node, we can use `resizeLeaf`.2703 // Since this is a leaf node, we can use `resizeLeaf`.
2688 const new_size = alignment.forward(smith.valueWeighted(u64, initial_size_weights));2704 const new_size = alignment.forward(smith.valueWeighted(u64, initial_size_weights));
2689 try ni.resizeLeaf(&mf, gpa, new_size);2705 try ni.resizeLeaf(gpa, &mf, new_size);
2690 if (new_size == 0) {2706 if (new_size == 0) {
2691 node_info.initialized = false;2707 node_info.initialized = false;
2692 }2708 }
2693 } else {2709 } else {
2694 const min_size = alignment.forward(smith.valueWeighted(u64, initial_size_weights));2710 const min_size = alignment.forward(smith.valueWeighted(u64, initial_size_weights));
2695 try ni.ensureMinimumSize(&mf, gpa, min_size);2711 try ni.ensureMinimumSize(gpa, &mf, min_size);
2696 }2712 }
26972713
2698 if (ni.first(&mf) == .none) {2714 if (ni.first(&mf) == .none) {
...@@ -2718,7 +2734,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {...@@ -2718,7 +2734,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {
2718 const new_alignment = smith.valueWeighted(Alignment, alignment_weights);2734 const new_alignment = smith.valueWeighted(Alignment, alignment_weights);
2719 if (new_alignment.compare(.gt, ni.alignment(&mf))) {2735 if (new_alignment.compare(.gt, ni.alignment(&mf))) {
2720 _, const old_size = ni.location(&mf).resolve(&mf);2736 _, const old_size = ni.location(&mf).resolve(&mf);
2721 try ni.realign(&mf, gpa, new_alignment);2737 try ni.realign(gpa, &mf, new_alignment);
2722 if (ni.first(&mf) == .none and nodes.get(ni).?.initialized) {2738 if (ni.first(&mf) == .none and nodes.get(ni).?.initialized) {
2723 const slice = ni.slice(&mf);2739 const slice = ni.slice(&mf);
2724 @memmove(slice[slice.len - 4 ..][0..4], slice[old_size - 4 ..][0..4]);2740 @memmove(slice[slice.len - 4 ..][0..4], slice[old_size - 4 ..][0..4]);
src/link/Spork8.zig+3-4
...@@ -18,7 +18,6 @@ const Mir = @import("../codegen/spork8/Mir.zig");...@@ -18,7 +18,6 @@ const Mir = @import("../codegen/spork8/Mir.zig");
18const link = @import("../link.zig");18const link = @import("../link.zig");
19const Compilation = @import("../Compilation.zig");19const Compilation = @import("../Compilation.zig");
20const Liveness = @import("../Air/Liveness.zig");20const Liveness = @import("../Air/Liveness.zig");
21const dev = @import("../dev.zig");
22const Value = @import("../Value.zig");21const Value = @import("../Value.zig");
2322
24base: link.File,23base: link.File,
...@@ -89,7 +88,6 @@ pub fn updateFunc(...@@ -89,7 +88,6 @@ pub fn updateFunc(
89 func_index: InternPool.Index,88 func_index: InternPool.Index,
90 any_mir: *const codegen.AnyMir,89 any_mir: *const codegen.AnyMir,
91) !void {90) !void {
92 dev.check(.spork8_backend);
93 // This linker implementation only works with `std.lang.CompilerBackend.zsf_spork8`.91 // This linker implementation only works with `std.lang.CompilerBackend.zsf_spork8`.
94 const mir = &any_mir.spork8;92 const mir = &any_mir.spork8;
95 const zcu = pt.zcu;93 const zcu = pt.zcu;
...@@ -168,10 +166,11 @@ pub fn updateNav(spork8: *Spork8, pt: Zcu.PerThread, nav_index: InternPool.Nav.I...@@ -168,10 +166,11 @@ pub fn updateNav(spork8: *Spork8, pt: Zcu.PerThread, nav_index: InternPool.Nav.I
168 log.debug("updateNav {f}", .{nav.fqn.fmt(ip)});166 log.debug("updateNav {f}", .{nav.fqn.fmt(ip)});
169}167}
170168
171pub fn updateLineNumber(spork8: *Spork8, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {169pub fn updateLineNumber(spork8: *Spork8, pt: Zcu.PerThread, inst: InternPool.TrackedInst.Index, line: u32) !void {
172 _ = spork8;170 _ = spork8;
173 _ = pt;171 _ = pt;
174 _ = ti_id;172 _ = inst;
173 _ = line;
175}174}
176175
177pub fn deleteExport(176pub fn deleteExport(
src/link/Wasm.zig+4-15
...@@ -38,7 +38,6 @@ const Dwarf = @import("Dwarf.zig");...@@ -38,7 +38,6 @@ const Dwarf = @import("Dwarf.zig");
38const InternPool = @import("../InternPool.zig");38const InternPool = @import("../InternPool.zig");
39const Zcu = @import("../Zcu.zig");39const Zcu = @import("../Zcu.zig");
40const codegen = @import("../codegen.zig");40const codegen = @import("../codegen.zig");
41const dev = @import("../dev.zig");
42const link = @import("../link.zig");41const link = @import("../link.zig");
43const trace = @import("../tracy.zig").trace;42const trace = @import("../tracy.zig").trace;
44const wasi_libc = @import("../libs/wasi_libc.zig");43const wasi_libc = @import("../libs/wasi_libc.zig");
...@@ -1374,11 +1373,7 @@ pub const GlobalImport = extern struct {...@@ -1374,11 +1373,7 @@ pub const GlobalImport = extern struct {
1374 .__tls_base => @tagName(Unpacked.__tls_base),1373 .__tls_base => @tagName(Unpacked.__tls_base),
1375 .__tls_size => @tagName(Unpacked.__tls_size),1374 .__tls_size => @tagName(Unpacked.__tls_size),
1376 .object_global => |i| i.name(wasm).slice(wasm),1375 .object_global => |i| i.name(wasm).slice(wasm),
1377 inline .uav_obj, .uav_exe => |i| std.mem.print(1376 inline .uav_obj, .uav_exe => |i| std.mem.print(buf, "__anon_{d}", .{i}) catch unreachable,
1378 buf,
1379 "__anon_{d}",
1380 .{@backingInt(i.key(wasm).*)},
1381 ) catch unreachable,
1382 .nav_obj => |i| i.name(wasm),1377 .nav_obj => |i| i.name(wasm),
1383 .nav_exe => |i| i.name(wasm),1378 .nav_exe => |i| i.name(wasm),
1384 };1379 };
...@@ -1997,11 +1992,7 @@ pub const ObjectDataImport = extern struct {...@@ -1997,11 +1992,7 @@ pub const ObjectDataImport = extern struct {
1997 .__heap_base => @tagName(.__heap_base),1992 .__heap_base => @tagName(.__heap_base),
1998 .__heap_end => @tagName(.__heap_end),1993 .__heap_end => @tagName(.__heap_end),
1999 .__wasm_first_page_end => @tagName(.__wasm_first_page_end),1994 .__wasm_first_page_end => @tagName(.__wasm_first_page_end),
2000 inline .uav_exe, .uav_obj => |i| std.mem.print(1995 inline .uav_exe, .uav_obj => |i| std.mem.print(buf, "__anon_{d}", .{i}) catch unreachable,
2001 buf,
2002 "__anon_{d}",
2003 .{@backingInt(i.key(wasm).*)},
2004 ) catch unreachable,
2005 inline .nav_exe, .nav_obj => |i| i.name(wasm),1996 inline .nav_exe, .nav_obj => |i| i.name(wasm),
2006 };1997 };
2007 }1998 }
...@@ -3583,8 +3574,6 @@ pub fn updateFunc(...@@ -3583,8 +3574,6 @@ pub fn updateFunc(
3583 func_index: InternPool.Index,3574 func_index: InternPool.Index,
3584 any_mir: *const codegen.AnyMir,3575 any_mir: *const codegen.AnyMir,
3585) !void {3576) !void {
3586 dev.check(.wasm_backend);
3587
3588 // This linker implementation only works with codegen backend `.stage2_wasm`.3577 // This linker implementation only works with codegen backend `.stage2_wasm`.
3589 const mir = &any_mir.wasm;3578 const mir = &any_mir.wasm;
3590 const zcu = pt.zcu;3579 const zcu = pt.zcu;
...@@ -3736,11 +3725,11 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index...@@ -3736,11 +3725,11 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
3736 }3725 }
3737}3726}
37383727
3739pub fn updateLineNumber(wasm: *Wasm, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) link.Error!void {3728pub fn updateLineNumber(wasm: *Wasm, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index, line: u32) link.Error!void {
3740 const comp = wasm.base.comp;3729 const comp = wasm.base.comp;
3741 const diags = &comp.link_diags;3730 const diags = &comp.link_diags;
3742 if (wasm.dwarf) |*dw| {3731 if (wasm.dwarf) |*dw| {
3743 dw.updateLineNumber(pt.zcu, ti_id) catch |err| switch (err) {3732 dw.updateLineNumber(pt.zcu, ti_id, line) catch |err| switch (err) {
3744 error.OutOfMemory, error.Canceled, error.AlreadyReported => |e| return e,3733 error.OutOfMemory, error.Canceled, error.AlreadyReported => |e| return e,
3745 else => |e| return diags.fail("failed to update dwarf line numbers: {s}", .{@errorName(e)}),3734 else => |e| return diags.fail("failed to update dwarf line numbers: {s}", .{@errorName(e)}),
3746 };3735 };
src/main.zig+1-1
...@@ -36,7 +36,7 @@ const Module = @import("Module.zig");...@@ -36,7 +36,7 @@ const Module = @import("Module.zig");
3636
37test {37test {
38 _ = @import("codegen.zig");38 _ = @import("codegen.zig");
39 _ = @import("link/MappedFile.zig");39 _ = link.MappedFile;
40}40}
4141
42const thread_stack_size = 60 << 20;42const thread_stack_size = 60 << 20;
src/print_zir.zig+11-3
...@@ -1452,6 +1452,8 @@ const Writer = struct {...@@ -1452,6 +1452,8 @@ const Writer = struct {
1452 self.parent_decl_node = struct_decl.src_node;1452 self.parent_decl_node = struct_decl.src_node;
1453 defer self.parent_decl_node = prev_parent_decl_node;1453 defer self.parent_decl_node = prev_parent_decl_node;
14541454
1455 try stream.print(":{d}:{d} ", .{ struct_decl.src_line + 1, struct_decl.src_column + 1 });
1456
1455 const fields_hash = self.code.getAssociatedSrcHash(inst).?;1457 const fields_hash = self.code.getAssociatedSrcHash(inst).?;
1456 try stream.print("hash({x}) ", .{&fields_hash});1458 try stream.print("hash({x}) ", .{&fields_hash});
14571459
...@@ -1514,6 +1516,8 @@ const Writer = struct {...@@ -1514,6 +1516,8 @@ const Writer = struct {
1514 self.parent_decl_node = union_decl.src_node;1516 self.parent_decl_node = union_decl.src_node;
1515 defer self.parent_decl_node = prev_parent_decl_node;1517 defer self.parent_decl_node = prev_parent_decl_node;
15161518
1519 try stream.print(":{d}:{d} ", .{ union_decl.src_line + 1, union_decl.src_column + 1 });
1520
1517 const fields_hash = self.code.getAssociatedSrcHash(inst).?;1521 const fields_hash = self.code.getAssociatedSrcHash(inst).?;
1518 try stream.print("hash({x}) ", .{&fields_hash});1522 try stream.print("hash({x}) ", .{&fields_hash});
15191523
...@@ -1590,6 +1594,8 @@ const Writer = struct {...@@ -1590,6 +1594,8 @@ const Writer = struct {
1590 self.parent_decl_node = enum_decl.src_node;1594 self.parent_decl_node = enum_decl.src_node;
1591 defer self.parent_decl_node = prev_parent_decl_node;1595 defer self.parent_decl_node = prev_parent_decl_node;
15921596
1597 try stream.print(":{d}:{d} ", .{ enum_decl.src_line + 1, enum_decl.src_column + 1 });
1598
1593 const fields_hash = self.code.getAssociatedSrcHash(inst).?;1599 const fields_hash = self.code.getAssociatedSrcHash(inst).?;
1594 try stream.print("hash({x}) ", .{&fields_hash});1600 try stream.print("hash({x}) ", .{&fields_hash});
15951601
...@@ -1637,6 +1643,8 @@ const Writer = struct {...@@ -1637,6 +1643,8 @@ const Writer = struct {
1637 self.parent_decl_node = opaque_decl.src_node;1643 self.parent_decl_node = opaque_decl.src_node;
1638 defer self.parent_decl_node = prev_parent_decl_node;1644 defer self.parent_decl_node = prev_parent_decl_node;
16391645
1646 try stream.print(":{d}:{d} ", .{ opaque_decl.src_line + 1, opaque_decl.src_column + 1 });
1647
1640 try stream.print("{s}, ", .{@tagName(opaque_decl.name_strategy)});1648 try stream.print("{s}, ", .{@tagName(opaque_decl.name_strategy)});
1641 try self.writeCaptures(stream, opaque_decl.captures, opaque_decl.capture_names);1649 try self.writeCaptures(stream, opaque_decl.captures, opaque_decl.capture_names);
1642 try stream.writeAll(", ");1650 try stream.writeAll(", ");
...@@ -2216,10 +2224,10 @@ const Writer = struct {...@@ -2216,10 +2224,10 @@ const Writer = struct {
2216 try stream.print("{s} '{s}'", .{ @tagName(decl.kind), self.code.nullTerminatedString(decl.name) });2224 try stream.print("{s} '{s}'", .{ @tagName(decl.kind), self.code.nullTerminatedString(decl.name) });
2217 },2225 },
2218 }2226 }
2227 try stream.print(":{d}:{d}", .{ decl.src_line + 1, decl.src_column + 1 });
2228
2219 const src_hash = self.code.getAssociatedSrcHash(inst).?;2229 const src_hash = self.code.getAssociatedSrcHash(inst).?;
2220 try stream.print(" line({d}) column({d}) hash({x})", .{2230 try stream.print(" hash({x})", .{&src_hash});
2221 decl.src_line, decl.src_column, &src_hash,
2222 });
22232231
2224 {2232 {
2225 if (decl.type_body) |b| {2233 if (decl.type_body) |b| {
src/target.zig+5-1
...@@ -2,6 +2,7 @@ const builtin = @import("builtin");...@@ -2,6 +2,7 @@ const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const assert = std.debug.assert;3const assert = std.debug.assert;
44
5const dev = @import("dev.zig");
5const Type = @import("Type.zig");6const Type = @import("Type.zig");
6const AddressSpace = std.lang.AddressSpace;7const AddressSpace = std.lang.AddressSpace;
7const Alignment = @import("InternPool.zig").Alignment;8const Alignment = @import("InternPool.zig").Alignment;
...@@ -855,7 +856,10 @@ pub fn functionPointerMask(target: *const std.Target) ?u64 {...@@ -855,7 +856,10 @@ pub fn functionPointerMask(target: *const std.Target) ?u64 {
855856
856pub fn supportsTailCall(target: *const std.Target, backend: std.lang.CompilerBackend) bool {857pub fn supportsTailCall(target: *const std.Target, backend: std.lang.CompilerBackend) bool {
857 switch (backend) {858 switch (backend) {
858 .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target),859 .stage2_llvm => {
860 dev.check(.llvm_backend);
861 return @import("codegen/llvm.zig").supportsTailCall(target);
862 },
859 .stage2_c => return true,863 .stage2_c => return true,
860 else => return false,864 else => return false,
861 }865 }
test/incremental/change_reify_struct_field_type created+22
...@@ -0,0 +1,22 @@
1#update=initial version
2#file=main.zig
3fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{struct { tag: Enum }}, &.{.{}})) Enum {
4 return s.field.tag;
5}
6pub fn main(init: std.process.Init) !void {
7 try std.Io.File.stdout().writeStreamingAll(init.io, @tagName(getEnum(.{ .field = .{ .tag = .foo } })));
8}
9const Enum = enum { foo, bar };
10const std = @import("std");
11#expect_stdout="foo"
12#update=change field type
13#file=main.zig
14fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{Enum}, &.{.{}})) Enum {
15 return s.field;
16}
17pub fn main(init: std.process.Init) !void {
18 try std.Io.File.stdout().writeStreamingAll(init.io, @tagName(getEnum(.{ .field = .bar })));
19}
20const Enum = enum { foo, bar };
21const std = @import("std");
22#expect_stdout="bar"
test/incremental/no_change_preserves_tag_names deleted-18
...@@ -1,18 +0,0 @@
1#update=initial version
2#file=main.zig
3const std = @import("std");
4var some_enum: enum { first, second } = .first;
5const io = std.Io.Threaded.global_single_threaded.io();
6pub fn main() !void {
7 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
8}
9#expect_stdout="first"
10#update=no change
11#file=main.zig
12const std = @import("std");
13var some_enum: enum { first, second } = .first;
14const io = std.Io.Threaded.global_single_threaded.io();
15pub fn main() !void {
16 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
17}
18#expect_stdout="first"
test/incremental/tag_name created+27
...@@ -0,0 +1,27 @@
1#update=initial version
2#file=main.zig
3const std = @import("std");
4var some_enum: enum { first, second } = .first;
5const io = std.Io.Threaded.global_single_threaded.io();
6pub fn main() !void {
7 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
8}
9#expect_stdout="first"
10#update=no change
11#file=main.zig
12const std = @import("std");
13var some_enum: enum { first, second } = .first;
14const io = std.Io.Threaded.global_single_threaded.io();
15pub fn main() !void {
16 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
17}
18#expect_stdout="first"
19#update=swap fields
20#file=main.zig
21const std = @import("std");
22var some_enum: enum { second, first } = .first;
23const io = std.Io.Threaded.global_single_threaded.io();
24pub fn main() !void {
25 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
26}
27#expect_stdout="first"
test/src/Debugger.zig+101-71
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1b: *std.Build,1b: *std.Build,
2options: Options,2options: Options,
3root_step: *std.Build.Step,3root_step: *std.Build.Step,
4test_matrix: []const TestTarget,
45
5pub const Options = struct {6pub const Options = struct {
6 test_filters: []const []const u8,7 test_filters: []const []const u8,
...@@ -12,19 +13,20 @@ pub const Options = struct {...@@ -12,19 +13,20 @@ pub const Options = struct {
12 skip_libc: bool,13 skip_libc: bool,
13};14};
1415
15pub const Target = struct {16pub const TestTarget = struct {
16 resolved: std.Build.ResolvedTarget,17 target: std.Target.Query,
17 optimize_mode: std.builtin.Optimize = .debug,18 optimize_mode: std.builtin.Optimize = .debug,
18 link_libc: ?bool = null,19 link_libc: ?bool = null,
19 single_threaded: ?bool = null,20 single_threaded: ?bool = null,
20 pic: ?bool = null,21 pic: ?bool = null,
21 test_name_suffix: []const u8,22 linker: LinkerImpl,
22};23};
2324
24pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {25pub const LinkerImpl = enum { default, old, new };
26
27pub fn addTests(db: *Debugger) void {
25 db.addLldbTest(28 db.addLldbTest(
26 "basic",29 "basic",
27 target,
28 &.{30 &.{
29 .{31 .{
30 .path = "basic.zig",32 .path = "basic.zig",
...@@ -179,10 +181,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -179,10 +181,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
179 \\(lldb) breakpoint delete --force 1181 \\(lldb) breakpoint delete --force 1
180 \\1 breakpoints deleted; 0 breakpoint locations disabled.182 \\1 breakpoints deleted; 0 breakpoint locations disabled.
181 },183 },
184 .{},
182 );185 );
183 db.addLldbTest(186 db.addLldbTest(
184 "identifiers",187 "identifiers",
185 target,
186 &.{188 &.{
187 .{189 .{
188 .path = "identifiers.zig",190 .path = "identifiers.zig",
...@@ -214,10 +216,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -214,10 +216,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
214 \\(lldb) breakpoint delete --force 1216 \\(lldb) breakpoint delete --force 1
215 \\1 breakpoints deleted; 0 breakpoint locations disabled.217 \\1 breakpoints deleted; 0 breakpoint locations disabled.
216 },218 },
219 .{},
217 );220 );
218 db.addLldbTest(221 db.addLldbTest(
219 "types",222 "types",
220 target,
221 &.{223 &.{
222 .{224 .{
223 .path = "types.zig",225 .path = "types.zig",
...@@ -282,10 +284,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -282,10 +284,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
282 \\(lldb) breakpoint delete --force 1284 \\(lldb) breakpoint delete --force 1
283 \\1 breakpoints deleted; 0 breakpoint locations disabled.285 \\1 breakpoints deleted; 0 breakpoint locations disabled.
284 },286 },
287 .{},
285 );288 );
286 db.addLldbTest(289 db.addLldbTest(
287 "pointers",290 "pointers",
288 target,
289 &.{291 &.{
290 .{292 .{
291 .path = "pointers.zig",293 .path = "pointers.zig",
...@@ -419,10 +421,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -419,10 +421,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
419 \\(lldb) breakpoint delete --force 1421 \\(lldb) breakpoint delete --force 1
420 \\1 breakpoints deleted; 0 breakpoint locations disabled.422 \\1 breakpoints deleted; 0 breakpoint locations disabled.
421 },423 },
424 .{},
422 );425 );
423 db.addLldbTest(426 db.addLldbTest(
424 "strings",427 "strings",
425 target,
426 &.{428 &.{
427 .{429 .{
428 .path = "strings.zig",430 .path = "strings.zig",
...@@ -495,10 +497,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -495,10 +497,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
495 \\(lldb) breakpoint delete --force 1497 \\(lldb) breakpoint delete --force 1
496 \\1 breakpoints deleted; 0 breakpoint locations disabled.498 \\1 breakpoints deleted; 0 breakpoint locations disabled.
497 },499 },
500 .{},
498 );501 );
499 db.addLldbTest(502 db.addLldbTest(
500 "enums",503 "enums",
501 target,
502 &.{504 &.{
503 .{505 .{
504 .path = "enums.zig",506 .path = "enums.zig",
...@@ -557,10 +559,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -557,10 +559,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
557 \\(lldb) breakpoint delete --force 1559 \\(lldb) breakpoint delete --force 1
558 \\1 breakpoints deleted; 0 breakpoint locations disabled.560 \\1 breakpoints deleted; 0 breakpoint locations disabled.
559 },561 },
562 .{ .skip_new_linker = true }, // passes, but prints errors
560 );563 );
561 db.addLldbTest(564 db.addLldbTest(
562 "errors",565 "errors",
563 target,
564 &.{566 &.{
565 .{567 .{
566 .path = "errors.zig",568 .path = "errors.zig",
...@@ -627,10 +629,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -627,10 +629,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
627 \\(lldb) breakpoint delete --force 1629 \\(lldb) breakpoint delete --force 1
628 \\1 breakpoints deleted; 0 breakpoint locations disabled.630 \\1 breakpoints deleted; 0 breakpoint locations disabled.
629 },631 },
632 .{ .skip_new_linker = true },
630 );633 );
631 db.addLldbTest(634 db.addLldbTest(
632 "optionals",635 "optionals",
633 target,
634 &.{636 &.{
635 .{637 .{
636 .path = "optionals.zig",638 .path = "optionals.zig",
...@@ -681,10 +683,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -681,10 +683,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
681 \\(lldb) breakpoint delete --force 2683 \\(lldb) breakpoint delete --force 2
682 \\1 breakpoints deleted; 0 breakpoint locations disabled.684 \\1 breakpoints deleted; 0 breakpoint locations disabled.
683 },685 },
686 .{},
684 );687 );
685 db.addLldbTest(688 db.addLldbTest(
686 "unions",689 "unions",
687 target,
688 &.{690 &.{
689 .{691 .{
690 .path = "unions.zig",692 .path = "unions.zig",
...@@ -766,10 +768,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -766,10 +768,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
766 \\(lldb) breakpoint delete --force 1768 \\(lldb) breakpoint delete --force 1
767 \\1 breakpoints deleted; 0 breakpoint locations disabled.769 \\1 breakpoints deleted; 0 breakpoint locations disabled.
768 },770 },
771 .{ .skip_new_linker = true }, // passes, but prints errors
769 );772 );
770 db.addLldbTest(773 db.addLldbTest(
771 "storage",774 "storage",
772 target,
773 &.{775 &.{
774 .{776 .{
775 .path = "storage.zig",777 .path = "storage.zig",
...@@ -866,10 +868,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -866,10 +868,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
866 \\(lldb) breakpoint delete --force 1868 \\(lldb) breakpoint delete --force 1
867 \\1 breakpoints deleted; 0 breakpoint locations disabled.869 \\1 breakpoints deleted; 0 breakpoint locations disabled.
868 },870 },
871 .{ .skip_new_linker = true },
869 );872 );
870 db.addLldbTest(873 db.addLldbTest(
871 "if_blocks",874 "if_blocks",
872 target,
873 &.{875 &.{
874 .{876 .{
875 .path = "if_blocks.zig",877 .path = "if_blocks.zig",
...@@ -908,10 +910,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -908,10 +910,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
908 \\(lldb) breakpoint delete --force 1910 \\(lldb) breakpoint delete --force 1
909 \\1 breakpoints deleted; 0 breakpoint locations disabled.911 \\1 breakpoints deleted; 0 breakpoint locations disabled.
910 },912 },
913 .{},
911 );914 );
912 db.addLldbTest(915 db.addLldbTest(
913 "switch_blocks",916 "switch_blocks",
914 target,
915 &.{917 &.{
916 .{918 .{
917 .path = "switch_blocks.zig",919 .path = "switch_blocks.zig",
...@@ -953,10 +955,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -953,10 +955,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
953 \\(lldb) breakpoint delete --force 1955 \\(lldb) breakpoint delete --force 1
954 \\1 breakpoints deleted; 0 breakpoint locations disabled.956 \\1 breakpoints deleted; 0 breakpoint locations disabled.
955 },957 },
958 .{},
956 );959 );
957 db.addLldbTest(960 db.addLldbTest(
958 "step_single_stmt_loops",961 "step_single_stmt_loops",
959 target,
960 &.{962 &.{
961 .{963 .{
962 .path = "step_single_stmt_loops.zig",964 .path = "step_single_stmt_loops.zig",
...@@ -1371,10 +1373,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -1371,10 +1373,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
1371 \\(lldb) frame variable --show-all-children x1373 \\(lldb) frame variable --show-all-children x
1372 \\(u32) x = 121374 \\(u32) x = 12
1373 },1375 },
1376 .{},
1374 );1377 );
1375 db.addLldbTest(1378 db.addLldbTest(
1376 "inline_call",1379 "inline_call",
1377 target,
1378 &.{1380 &.{
1379 .{1381 .{
1380 .path = "root0.zig",1382 .path = "root0.zig",
...@@ -1944,10 +1946,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -1944,10 +1946,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
1944 \\ frame #1: inline_call`m1pfi(m1pai=89) at mod1.zig:23:151946 \\ frame #1: inline_call`m1pfi(m1pai=89) at mod1.zig:23:15
1945 \\ frame #2: inline_call`root0.main at root0.zig:41:151947 \\ frame #2: inline_call`root0.main at root0.zig:41:15
1946 },1948 },
1949 .{ .skip_new_linker = true },
1947 );1950 );
1948 db.addLldbTest(1951 db.addLldbTest(
1949 "link_object",1952 "link_object",
1950 target,
1951 &.{1953 &.{
1952 .{1954 .{
1953 .path = "main.zig",1955 .path = "main.zig",
...@@ -1983,10 +1985,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -1983,10 +1985,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
1983 \\(lldb) breakpoint delete --force 21985 \\(lldb) breakpoint delete --force 2
1984 \\1 breakpoints deleted; 0 breakpoint locations disabled.1986 \\1 breakpoints deleted; 0 breakpoint locations disabled.
1985 },1987 },
1988 .{},
1986 );1989 );
1987 db.addLldbTest(1990 db.addLldbTest(
1988 "hash_map",1991 "hash_map",
1989 target,
1990 &.{1992 &.{
1991 .{1993 .{
1992 .path = "main.zig",1994 .path = "main.zig",
...@@ -2052,10 +2054,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -2052,10 +2054,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
2052 \\(lldb) breakpoint delete --force 12054 \\(lldb) breakpoint delete --force 1
2053 \\1 breakpoints deleted; 0 breakpoint locations disabled.2055 \\1 breakpoints deleted; 0 breakpoint locations disabled.
2054 },2056 },
2057 .{ .skip_new_linker = true },
2055 );2058 );
2056 db.addLldbTest(2059 db.addLldbTest(
2057 "multi_array_list",2060 "multi_array_list",
2058 target,
2059 &.{2061 &.{
2060 .{2062 .{
2061 .path = "main.zig",2063 .path = "main.zig",
...@@ -2306,22 +2308,26 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -2306,22 +2308,26 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
2306 \\(lldb) breakpoint delete --force 12308 \\(lldb) breakpoint delete --force 1
2307 \\1 breakpoints deleted; 0 breakpoint locations disabled.2309 \\1 breakpoints deleted; 0 breakpoint locations disabled.
2308 },2310 },
2311 .{ .skip_new_linker = true },
2309 );2312 );
2310}2313}
23112314
2312const File = struct { import: ?[]const u8 = null, path: []const u8, source: []const u8 };2315const File = struct { import: ?[]const u8 = null, path: []const u8, source: []const u8 };
23132316
2317const TestOptions = struct {
2318 skip_new_linker: bool = false,
2319};
2320
2314fn addGdbTest(2321fn addGdbTest(
2315 db: *Debugger,2322 db: *Debugger,
2316 name: []const u8,2323 name: []const u8,
2317 target: *const Target,
2318 files: []const File,2324 files: []const File,
2319 commands: []const u8,2325 commands: []const u8,
2320 expected_output: []const []const u8,2326 expected_output: []const []const u8,
2327 options: TestOptions,
2321) void {2328) void {
2322 db.addTest(2329 db.addTest(
2323 name,2330 name,
2324 target,
2325 files,2331 files,
2326 &.{},2332 &.{},
2327 &.{2333 &.{
...@@ -2331,24 +2337,22 @@ fn addGdbTest(...@@ -2331,24 +2337,22 @@ fn addGdbTest(
2331 },2337 },
2332 "set remotetimeout 0",2338 "set remotetimeout 0",
2333 commands,2339 commands,
2334 &.{2340 &.{"--args"},
2335 "--args",
2336 },
2337 expected_output,2341 expected_output,
2342 options,
2338 );2343 );
2339}2344}
23402345
2341fn addLldbTest(2346fn addLldbTest(
2342 db: *Debugger,2347 db: *Debugger,
2343 name: []const u8,2348 name: []const u8,
2344 target: *const Target,
2345 files: []const File,2349 files: []const File,
2346 commands: []const u8,2350 commands: []const u8,
2347 expected_output: []const []const u8,2351 expected_output: []const []const u8,
2352 options: TestOptions,
2348) void {2353) void {
2349 db.addTest(2354 db.addTest(
2350 name,2355 name,
2351 target,
2352 files,2356 files,
2353 &.{.{ "LANG", "C.UTF-8" }}, // affects output formatting2357 &.{.{ "LANG", "C.UTF-8" }}, // affects output formatting
2354 &.{2358 &.{
...@@ -2358,10 +2362,9 @@ fn addLldbTest(...@@ -2358,10 +2362,9 @@ fn addLldbTest(
2358 },2362 },
2359 "settings set plugin.process.gdb-remote.packet-timeout 0",2363 "settings set plugin.process.gdb-remote.packet-timeout 0",
2360 commands,2364 commands,
2361 &.{2365 &.{"--"},
2362 "--",
2363 },
2364 expected_output,2366 expected_output,
2367 options,
2365 );2368 );
2366}2369}
23672370
...@@ -2373,7 +2376,6 @@ const success = 99;...@@ -2373,7 +2376,6 @@ const success = 99;
2373fn addTest(2376fn addTest(
2374 db: *Debugger,2377 db: *Debugger,
2375 name: []const u8,2378 name: []const u8,
2376 target: *const Target,
2377 files: []const File,2379 files: []const File,
2378 env: []const struct { []const u8, []const u8 },2380 env: []const struct { []const u8, []const u8 },
2379 db_argv1: []const []const u8,2381 db_argv1: []const []const u8,
...@@ -2381,57 +2383,85 @@ fn addTest(...@@ -2381,57 +2383,85 @@ fn addTest(
2381 commands: []const u8,2383 commands: []const u8,
2382 db_argv2: []const []const u8,2384 db_argv2: []const []const u8,
2383 expected_output: []const []const u8,2385 expected_output: []const []const u8,
2386 options: TestOptions,
2384) void {2387) void {
2385 if (db.options.test_filters.len > 0) {2388 if (db.options.test_filters.len > 0) {
2386 for (db.options.test_filters) |test_filter| {2389 for (db.options.test_filters) |test_filter| {
2387 if (std.mem.find(u8, name, test_filter) != null) break;2390 if (std.mem.find(u8, name, test_filter) != null) break;
2388 } else return;2391 } else return;
2389 }2392 }
2390 if (db.options.test_target_filters.len > 0) {
2391 const triple_txt = target.resolved.query.zigTriple(db.b.allocator) catch @panic("OOM");
2392 for (db.options.test_target_filters) |filter| {
2393 if (std.mem.find(u8, triple_txt, filter) != null) break;
2394 } else return;
2395 }
2396 const files_wf = db.b.addWriteFiles();
23972393
2398 const mod = db.b.createModule(.{2394 const wf = db.b.addWriteFiles();
2399 .target = target.resolved,2395 const root_source_file = wf.add(files[0].path, files[0].source);
2400 .root_source_file = files_wf.add(files[0].path, files[0].source),2396 var imports: std.array_hash_map.String(*std.Build.Module) = .empty;
2401 .optimize = target.optimize_mode,
2402 .link_libc = target.link_libc,
2403 .single_threaded = target.single_threaded,
2404 .pic = target.pic,
2405 .strip = false,
2406 });
2407 for (files[1..]) |file| {2397 for (files[1..]) |file| {
2408 const path = files_wf.add(file.path, file.source);2398 const path = wf.add(file.path, file.source);
2409 if (file.import) |import| mod.addImport(import, db.b.createModule(.{2399 if (file.import) |import| imports.putNoClobber(db.b.allocator, import, db.b.createModule(.{
2410 .root_source_file = path,2400 .root_source_file = path,
2411 }));2401 })) catch @panic("OOM");
2412 }2402 }
24132403 const commands_file = wf.add(
2414 const exe = db.b.addExecutable(.{
2415 .name = name,
2416 .root_module = mod,
2417 .use_llvm = false,
2418 .use_lld = false,
2419 });
2420
2421 const commands_wf = db.b.addWriteFiles();
2422 const run = std.Build.Step.Run.create(db.b, db.b.fmt("run {s} {s}", .{ name, target.test_name_suffix }));
2423 for (env) |env_var| run.setEnvironmentVariable(env_var[0], env_var[1]);
2424 run.addArgs(db_argv1);
2425 run.addFileArg(commands_wf.add(
2426 db.b.fmt("{s}.cmd", .{name}),2404 db.b.fmt("{s}.cmd", .{name}),
2427 db.b.fmt("{s}\n\n{s}\n\nquit {d}\n", .{ db_commands, commands, success }),2405 db.b.fmt("{s}\n\n{s}\n\nquit {d}\n", .{ db_commands, commands, success }),
2428 ));2406 );
2429 run.addArgs(db_argv2);2407
2430 run.addArtifactArg(exe);2408 for (db.test_matrix) |test_target| {
2431 for (expected_output) |expected| run.addCheck(.{ .expect_stdout_match = db.b.fmt("{s}\n", .{expected}) });2409 if (options.skip_new_linker and test_target.linker == .new) continue;
2432 run.addCheck(.{ .expect_term = .{ .exited = success } });2410
2433 run.setStdIn(.{ .bytes = "" });2411 const resolved_target = db.b.resolveTargetQuery(test_target.target);
2434 db.root_step.dependOn(&run.step);2412
2413 const target_str = db.b.fmt("{s}{s}{s}", .{
2414 resolved_target.query.zigTriple(db.b.allocator) catch @panic("OOM"),
2415 switch (test_target.linker) {
2416 .default, .old => "",
2417 .new => "-new-linker",
2418 },
2419 if (test_target.pic == true) "-pic" else "",
2420 });
2421
2422 if (db.options.test_target_filters.len > 0) {
2423 for (db.options.test_target_filters) |filter| {
2424 if (std.mem.find(u8, target_str, filter) != null) break;
2425 } else continue;
2426 }
2427
2428 const mod = db.b.createModule(.{
2429 .target = resolved_target,
2430 .root_source_file = root_source_file,
2431 .optimize = test_target.optimize_mode,
2432 .link_libc = test_target.link_libc,
2433 .single_threaded = test_target.single_threaded,
2434 .pic = test_target.pic,
2435 .strip = false,
2436 });
2437 for (imports.keys(), imports.values()) |import_name, import_mod|
2438 mod.addImport(import_name, import_mod);
2439
2440 const exe = db.b.addExecutable(.{
2441 .name = name,
2442 .root_module = mod,
2443 .use_llvm = false,
2444 .use_lld = false,
2445 });
2446 exe.use_new_linker = switch (test_target.linker) {
2447 .default => null,
2448 .old => false,
2449 .new => true,
2450 };
2451
2452 const run = std.Build.Step.Run.create(db.b, db.b.fmt("run {s} {s}", .{ name, target_str }));
2453 for (env) |env_var| run.setEnvironmentVariable(env_var[0], env_var[1]);
2454 run.addArgs(db_argv1);
2455 run.addFileArg(commands_file);
2456 run.addArgs(db_argv2);
2457 run.addArtifactArg(exe);
2458 for (expected_output) |expected| run.addCheck(.{
2459 .expect_stdout_match = db.b.fmt("{s}\n", .{expected}),
2460 });
2461 run.addCheck(.{ .expect_term = .{ .exited = success } });
2462 run.setStdIn(.{ .bytes = "" });
2463 db.root_step.dependOn(&run.step);
2464 }
2435}2465}
24362466
2437const Debugger = @This();2467const Debugger = @This();
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;
test/tests.zig+46-22
...@@ -2303,6 +2303,45 @@ const incremental_targets = &[_]IncrementalTarget{...@@ -2303,6 +2303,45 @@ const incremental_targets = &[_]IncrementalTarget{
2303 },2303 },
2304};2304};
23052305
2306const debugger_matrix: []const DebuggerContext.TestTarget = &.{
2307 .{
2308 .target = .{
2309 .cpu_arch = .x86_64,
2310 .os_tag = .linux,
2311 .abi = .none,
2312 },
2313 .pic = false,
2314 .linker = .old,
2315 },
2316 .{
2317 .target = .{
2318 .cpu_arch = .x86_64,
2319 .os_tag = .linux,
2320 .abi = .none,
2321 },
2322 .pic = true,
2323 .linker = .old,
2324 },
2325 .{
2326 .target = .{
2327 .cpu_arch = .x86_64,
2328 .os_tag = .linux,
2329 .abi = .none,
2330 },
2331 .pic = false,
2332 .linker = .new,
2333 },
2334 .{
2335 .target = .{
2336 .cpu_arch = .x86_64,
2337 .os_tag = .linux,
2338 .abi = .none,
2339 },
2340 .pic = true,
2341 .linker = .new,
2342 },
2343};
2344
2306fn compatible32bitArch(host: *const std.Target) ?std.Target.Cpu.Arch {2345fn compatible32bitArch(host: *const std.Target) ?std.Target.Cpu.Arch {
2307 return switch (host.os.tag) {2346 return switch (host.os.tag) {
2308 .freebsd => switch (host.cpu.arch) {2347 .freebsd => switch (host.cpu.arch) {
...@@ -3323,25 +3362,9 @@ pub fn addDebuggerTests(b: *std.Build, options: DebuggerContext.Options) ?*Step...@@ -3323,25 +3362,9 @@ pub fn addDebuggerTests(b: *std.Build, options: DebuggerContext.Options) ?*Step
3323 .b = b,3362 .b = b,
3324 .options = options,3363 .options = options,
3325 .root_step = step,3364 .root_step = step,
3365 .test_matrix = debugger_matrix,
3326 };3366 };
3327 context.addTestsForTarget(&.{3367 context.addTests();
3328 .resolved = b.resolveTargetQuery(.{
3329 .cpu_arch = .x86_64,
3330 .os_tag = .linux,
3331 .abi = .none,
3332 }),
3333 .pic = false,
3334 .test_name_suffix = "x86_64-linux",
3335 });
3336 context.addTestsForTarget(&.{
3337 .resolved = b.resolveTargetQuery(.{
3338 .cpu_arch = .x86_64,
3339 .os_tag = .linux,
3340 .abi = .none,
3341 }),
3342 .pic = true,
3343 .test_name_suffix = "x86_64-linux-pic",
3344 });
3345 return step;3368 return step;
3346}3369}
33473370
...@@ -3416,16 +3439,17 @@ pub fn addIncrementalTests(...@@ -3416,16 +3439,17 @@ pub fn addIncrementalTests(
34163439
3417 if (options.skip_llvm and test_target.backend == .llvm) continue;3440 if (options.skip_llvm and test_target.backend == .llvm) continue;
34183441
3419 const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM");3442 const target_str = b.fmt("{s}-{t}", .{
3443 resolved_target.query.zigTriple(b.allocator) catch @panic("OOM"),
3444 test_target.backend,
3445 });
34203446
3421 if (options.test_target_filters.len > 0) {3447 if (options.test_target_filters.len > 0) {
3422 for (options.test_target_filters) |filter| {3448 for (options.test_target_filters) |filter| {
3423 if (std.mem.find(u8, triple_txt, filter) != null) break;3449 if (std.mem.find(u8, target_str, filter) != null) break;
3424 } else continue;3450 } else continue;
3425 }3451 }
34263452
3427 const target_str = b.fmt("{s}-{t}", .{ triple_txt, test_target.backend });
3428
3429 const run = b.addRunArtifact(incr_check);3453 const run = b.addRunArtifact(incr_check);
3430 run.setName(b.fmt("incr-check {s} '{s}'", .{ target_str, entry.basename }));3454 run.setName(b.fmt("incr-check {s} '{s}'", .{ target_str, entry.basename }));
34313455
tools/incr-check.zig+7
...@@ -17,6 +17,7 @@ const usage =...@@ -17,6 +17,7 @@ const usage =
17 \\Debug Options:17 \\Debug Options:
18 \\ --preserve-tmp18 \\ --preserve-tmp
19 \\ --debug-log foo19 \\ --debug-log foo
20 \\ --debug-link-snapshot
20;21;
2122
22pub const std_options: std.Options = .{23pub const std_options: std.Options = .{
...@@ -60,6 +61,7 @@ pub fn main(init: std.process.Init) !void {...@@ -60,6 +61,7 @@ pub fn main(init: std.process.Init) !void {
60 var quiet: bool = false;61 var quiet: bool = false;
6162
62 var debug_log_args: std.ArrayList([]const u8) = .empty;63 var debug_log_args: std.ArrayList([]const u8) = .empty;
64 var debug_link_snapshot = false;
6365
64 var arg_it = try init.minimal.args.iterateAllocator(arena);66 var arg_it = try init.minimal.args.iterateAllocator(arena);
65 _ = arg_it.skip();67 _ = arg_it.skip();
...@@ -77,6 +79,8 @@ pub fn main(init: std.process.Init) !void {...@@ -77,6 +79,8 @@ pub fn main(init: std.process.Init) !void {
77 arena,79 arena,
78 arg_it.next() orelse badUsage("expected arg after --debug-log", .{}),80 arg_it.next() orelse badUsage("expected arg after --debug-log", .{}),
79 );81 );
82 } else if (std.mem.eql(u8, arg, "--debug-link-snapshot")) {
83 debug_link_snapshot = true;
80 } else if (std.mem.eql(u8, arg, "--preserve-tmp")) {84 } else if (std.mem.eql(u8, arg, "--preserve-tmp")) {
81 preserve_tmp = true;85 preserve_tmp = true;
82 } else if (std.mem.eql(u8, arg, "-fqemu")) {86 } else if (std.mem.eql(u8, arg, "-fqemu")) {
...@@ -173,6 +177,9 @@ pub fn main(init: std.process.Init) !void {...@@ -173,6 +177,9 @@ pub fn main(init: std.process.Init) !void {
173 for (debug_log_args.items) |arg| {177 for (debug_log_args.items) |arg| {
174 try child_args.appendSlice(arena, &.{ "--debug-log", arg });178 try child_args.appendSlice(arena, &.{ "--debug-log", arg });
175 }179 }
180 if (debug_link_snapshot) {
181 try child_args.append(arena, "--debug-link-snapshot");
182 }
176 for (case.modules) |mod| {183 for (case.modules) |mod| {
177 try child_args.appendSlice(arena, &.{ "--dep", mod.name });184 try child_args.appendSlice(arena, &.{ "--dep", mod.name });
178 }185 }