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
383383 src/link/ConstPool.zig
384384 src/link/Coff.zig
385385 src/link/Dwarf.zig
386 src/link/Dwarf2.zig
386387 src/link/Elf.zig
387388 src/link/Elf/Archive.zig
388389 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
781781any project compiled with Zig's LLVM backend (not recommended with the LLDB
782782fork, prefer vanilla LLDB with a version that matches the version of LLVM that
783783Zig 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
786787Put this line in `~/.lldbinit`:
787788
788789```
789command script import /path/to/zig/tools/lldb_pretty_printers.py
790command 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
790798```
791799
792800If you will be using Zig's LLVM backend (again, not recommended with the LLDB
......@@ -797,10 +805,9 @@ type category enable zig.lang
797805type category enable zig.std
798806```
799807
800If you will be debugging a Zig compiler built using Zig's LLVM backend (again,
801not recommended with the LLDB fork), you will also want this line:
808If you will be debugging a Zig compiler built using Zig's LLVM backend without
809using the LLDB fork, you will also want this line:
802810
803811```
804type category enable zig.stage2
812type category enable zig
805813```
806
ci/x86_64-linux-debug-llvm.sh+1-1
......@@ -53,7 +53,7 @@ stage3-debug/bin/zig build \
5353
5454stage3-debug/bin/zig build test docs \
5555 --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 \
5757 -Dlibc-test-path=$HOME/deps/libc-test-b95fe84 \
5858 -fqemu \
5959 --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 \
5353
5454stage3-debug/bin/zig build test docs \
5555 --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 \
5757 -fqemu \
5858 --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \
5959 -fwasmtime \
ci/x86_64-linux-release.sh+1-1
......@@ -61,7 +61,7 @@ stage3-release/bin/zig build \
6161
6262stage3-release/bin/zig build test docs \
6363 --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 \
6565 -Dlibc-test-path=$HOME/deps/libc-test-b95fe84 \
6666 -fqemu \
6767 --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
487487 @branchHint(.likely);
488488 return w.buffer[w.end..];
489489 }
490 try rebase(w, preserve, minimum_len);
490 try w.vtable.rebase(w, preserve, minimum_len);
491491 assert(w.buffer.len >= preserve + minimum_len);
492492 return w.buffer[w.end..];
493493}
......@@ -845,13 +845,10 @@ pub fn writeByte(w: *Writer, byte: u8) Error!void {
845845///
846846/// Asserts buffer capacity is at least `preserve`.
847847pub fn writeBytePreserve(w: *Writer, preserve: usize, byte: u8) Error!void {
848 if (w.buffer.len - w.end != 0) {
849 @branchHint(.likely);
850 w.buffer[w.end] = byte;
851 w.end += 1;
852 return;
848 if (w.buffer.len - w.end == 0) {
849 @branchHint(.unlikely);
850 try w.vtable.rebase(w, preserve -| 1, 1);
853851 }
854 try w.vtable.rebase(w, preserve -| 1, 1);
855852 w.buffer[w.end] = byte;
856853 w.end += 1;
857854}
lib/std/debug/Dwarf.zig+10-8
......@@ -387,18 +387,19 @@ fn scanAllFunctions(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!void {
387387 const next_offset = unit_header.header_length + unit_header.unit_length;
388388
389389 const version = try fr.takeInt(u16, endian);
390 if (version < 2 or version > 5) return bad();
391
392390 var address_size: u8 = undefined;
393391 var debug_abbrev_offset: u64 = undefined;
394 if (version >= 5) {
392 if (version == 5) {
395393 const unit_type = try fr.takeByte();
396394 if (unit_type != DW.UT.compile) return bad();
397395 address_size = try fr.takeByte();
398396 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
399 } else {
397 } else if (version >= 2 and version < 5) {
400398 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
401399 address_size = try fr.takeByte();
400 } else {
401 this_unit_offset += next_offset;
402 continue;
402403 }
403404
404405 const abbrev_table = try di.getAbbrevTable(gpa, debug_abbrev_offset);
......@@ -585,18 +586,19 @@ fn scanAllCompileUnits(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!voi
585586 const next_offset = unit_header.header_length + unit_header.unit_length;
586587
587588 const version = try fr.takeInt(u16, endian);
588 if (version < 2 or version > 5) return bad();
589
590589 var address_size: u8 = undefined;
591590 var debug_abbrev_offset: u64 = undefined;
592 if (version >= 5) {
591 if (version == 5) {
593592 const unit_type = try fr.takeByte();
594593 if (unit_type != UT.compile) return bad();
595594 address_size = try fr.takeByte();
596595 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
597 } else {
596 } else if (version >= 2 and version < 5) {
598597 debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
599598 address_size = try fr.takeByte();
599 } else {
600 this_unit_offset += next_offset;
601 continue;
600602 }
601603
602604 const abbrev_table = try di.getAbbrevTable(gpa, debug_abbrev_offset);
lib/std/debug/Dwarf/Unwind.zig+16-7
......@@ -362,8 +362,7 @@ pub const CommonInformationEntry = struct {
362362 if (aug_str.len == 0) break :aug .none;
363363 if (aug_str[0] == 'z') break :aug .lsb_z;
364364 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.
366 return bad();
365 return error.UnsupportedAugmentation;
367366 };
368367
369368 switch (aug_kind) {
......@@ -396,7 +395,7 @@ pub const CommonInformationEntry = struct {
396395 'R' => fde_pointer_enc = @bitCast(try aug_data.takeByte()),
397396 'S' => is_signal_frame = true,
398397 'B', 'G' => {},
399 else => return bad(),
398 else => return error.UnsupportedAugmentation,
400399 };
401400 break :aug .{ fde_pointer_enc, is_signal_frame };
402401 };
......@@ -502,7 +501,15 @@ pub fn prepare(
502501 const idx = unwind.cie_list.len;
503502 try unwind.cie_list.append(gpa, .{
504503 .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 },
506513 });
507514 errdefer _ = unwind.cie_list.pop().?;
508515 try VirtualMachine.populateCieLastRow(gpa, &unwind.cie_list.items(.cie)[idx], addr_size_bytes, endian);
......@@ -514,8 +521,10 @@ pub fn prepare(
514521 try r.discardAll(bytes_len);
515522 continue;
516523 }
517 const cie = unwind.findCie(fde_info.cie_offset) orelse return error.InvalidDebugInfo;
518 const fde: FrameDescriptionEntry = try .parse(section.vaddr + r.seek, try r.take(bytes_len), cie, endian);
524 const fde_vaddr = section.vaddr + r.seek;
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);
519528 try fde_list.append(gpa, .{
520529 .pc_begin = fde.pc_begin,
521530 .fde_offset = entry_offset,
......@@ -612,7 +621,7 @@ pub fn getFde(unwind: *const Unwind, fde_offset: u64, endian: Endian) !struct {
612621 .cie, .terminator => return bad(), // This is meant to be an FDE
613622 };
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();
616625 const fde: FrameDescriptionEntry = try .parse(
617626 section.vaddr + fde_offset + fde_reader.seek,
618627 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 {
340340 error.InvalidOperation,
341341 => return error.InvalidDebugInfo,
342342 error.UnsupportedAddrSize,
343 error.UnsupportedDwarfVersion,
344343 error.UnimplementedUserOpcode,
345344 => return error.UnsupportedDebugInfo,
346345 };
lib/std/debug/SelfInfo/MachO.zig-1
......@@ -578,7 +578,6 @@ const Module = struct {
578578 error.InvalidOperation,
579579 => return error.InvalidDebugInfo,
580580 error.UnsupportedAddrSize,
581 error.UnsupportedDwarfVersion,
582581 error.UnimplementedUserOpcode,
583582 => return error.UnsupportedDebugInfo,
584583 };
lib/std/dwarf/AT.zig+1
......@@ -225,6 +225,7 @@ pub const ZIG_padding = 0x2cce;
225225pub const ZIG_relative_decl = 0x2cd0;
226226pub const ZIG_decl_line_relative = 0x2cd1;
227227pub const ZIG_comptime_value = 0x2cd2;
228pub const ZIG_call_line_relative = 0x2cd3;
228229pub const ZIG_sentinel = 0x2ce2;
229230
230231// UPC extension.
lib/std/dwarf/TAG.zig+3-2
......@@ -40,8 +40,8 @@ pub const namelist = 0x2b;
4040pub const namelist_item = 0x2c;
4141pub const packed_type = 0x2d;
4242pub const subprogram = 0x2e;
43pub const template_type_param = 0x2f;
44pub const template_value_param = 0x30;
43pub const template_type_parameter = 0x2f;
44pub const template_value_parameter = 0x30;
4545pub const thrown_type = 0x31;
4646pub const try_block = 0x32;
4747pub const variant_part = 0x33;
......@@ -120,3 +120,4 @@ pub const PGI_interface_block = 0xA020;
120120// ZIG extensions.
121121pub const ZIG_padding = 0xfdb1;
122122pub const ZIG_comptime_value = 0xfdb2;
123pub const ZIG_lost_declaration = 0xfdb3;
lib/std/zig/AstGen.zig+42-6
......@@ -1884,7 +1884,8 @@ fn structInitExprAnon(
18841884
18851885 const payload_index = try addExtra(astgen, Zir.Inst.StructInitAnon{
18861886 .abs_node = node,
1887 .abs_line = astgen.source_line,
1887 .src_line = astgen.source_line,
1888 .src_column = astgen.source_column,
18881889 .fields_len = @intCast(struct_init.ast.fields.len),
18891890 });
18901891 const field_size = @typeInfo(Zir.Inst.StructInitAnon.Item).@"struct".field_names.len;
......@@ -1917,7 +1918,8 @@ fn structInitExprTyped(
19171918
19181919 const payload_index = try addExtra(astgen, Zir.Inst.StructInit{
19191920 .abs_node = node,
1920 .abs_line = astgen.source_line,
1921 .src_line = astgen.source_line,
1922 .src_column = astgen.source_column,
19211923 .fields_len = @intCast(struct_init.ast.fields.len),
19221924 });
19231925 const field_size = @typeInfo(Zir.Inst.StructInit.Item).@"struct".field_names.len;
......@@ -4846,9 +4848,13 @@ fn structDeclInner(
48464848 astgen.advanceSourceCursorToNode(node);
48474849
48484850 const decl_inst = try gz.reserveInstructionIndex();
4851 const src_line = astgen.source_line;
4852 const src_column = astgen.source_column;
48494853
48504854 if (container_decl.ast.members.len == 0 and maybe_backing_int_node == .none) {
48514855 try gz.setStruct(decl_inst, .{
4856 .src_line = src_line,
4857 .src_column = src_column,
48524858 .src_node = node,
48534859 .name_strat = name_strat,
48544860 .layout = layout,
......@@ -5003,6 +5009,8 @@ fn structDeclInner(
50035009 astgen.src_hasher.final(&fields_hash);
50045010
50055011 try gz.setStruct(decl_inst, .{
5012 .src_line = src_line,
5013 .src_column = src_column,
50065014 .src_node = node,
50075015 .name_strat = name_strat,
50085016 .layout = layout,
......@@ -5151,6 +5159,8 @@ fn unionDeclInner(
51515159 astgen.advanceSourceCursorToNode(node);
51525160
51535161 const decl_inst = try gz.reserveInstructionIndex();
5162 const src_line = astgen.source_line;
5163 const src_column = astgen.source_column;
51545164
51555165 var namespace: Scope.Namespace = .{
51565166 .parent = scope,
......@@ -5284,6 +5294,8 @@ fn unionDeclInner(
52845294 astgen.src_hasher.final(&fields_hash);
52855295
52865296 try gz.setUnion(decl_inst, .{
5297 .src_line = src_line,
5298 .src_column = src_column,
52875299 .src_node = node,
52885300 .name_strat = name_strat,
52895301 .kind = switch (layout) {
......@@ -5358,6 +5370,8 @@ fn containerDecl(
53585370 astgen.advanceSourceCursorToNode(node);
53595371
53605372 const decl_inst = try gz.reserveInstructionIndex();
5373 const src_line = astgen.source_line;
5374 const src_column = astgen.source_column;
53615375
53625376 var namespace: Scope.Namespace = .{
53635377 .parent = scope,
......@@ -5482,6 +5496,8 @@ fn containerDecl(
54825496 astgen.src_hasher.final(&fields_hash);
54835497
54845498 try gz.setEnum(decl_inst, .{
5499 .src_line = src_line,
5500 .src_column = src_column,
54855501 .src_node = node,
54865502 .name_strat = name_strat,
54875503 .tag_type_body_len = tag_type_body_len,
......@@ -5504,6 +5520,8 @@ fn containerDecl(
55045520 astgen.advanceSourceCursorToNode(node);
55055521
55065522 const decl_inst = try gz.reserveInstructionIndex();
5523 const src_line = astgen.source_line;
5524 const src_column = astgen.source_column;
55075525
55085526 var namespace: Scope.Namespace = .{
55095527 .parent = scope,
......@@ -5545,6 +5563,8 @@ fn containerDecl(
55455563 wip_decls.finish();
55465564
55475565 try gz.setOpaque(decl_inst, .{
5566 .src_line = src_line,
5567 .src_column = src_column,
55485568 .src_node = node,
55495569 .name_strat = name_strat,
55505570 .decls_len = scan_result.decls_len,
......@@ -9302,6 +9322,7 @@ fn builtinCall(
93029322 const field_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_attrs_ty } }, params[4], .struct_field_attrs);
93039323 const result = try gz.addExtendedPayloadSmall(.reify_struct, @backingInt(reify_name_strat), Zir.Inst.ReifyStruct{
93049324 .src_line = gz.astgen.source_line,
9325 .src_column = gz.astgen.source_column,
93059326 .node = node,
93069327 .layout = layout,
93079328 .backing_ty = backing_ty,
......@@ -9330,6 +9351,7 @@ fn builtinCall(
93309351 const field_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_attrs_ty } }, params[4], .union_field_attrs);
93319352 const result = try gz.addExtendedPayloadSmall(.reify_union, @backingInt(reify_name_strat), Zir.Inst.ReifyUnion{
93329353 .src_line = gz.astgen.source_line,
9354 .src_column = gz.astgen.source_column,
93339355 .node = node,
93349356 .layout = layout,
93359357 .arg_ty = arg_ty,
......@@ -9352,6 +9374,7 @@ fn builtinCall(
93529374 const field_values = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_values_ty } }, params[3], .enum_field_values);
93539375 const result = try gz.addExtendedPayloadSmall(.reify_enum, @backingInt(reify_name_strat), Zir.Inst.ReifyEnum{
93549376 .src_line = gz.astgen.source_line,
9377 .src_column = gz.astgen.source_column,
93559378 .node = node,
93569379 .tag_ty = tag_ty,
93579380 .mode = mode,
......@@ -9365,6 +9388,7 @@ fn builtinCall(
93659388 const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = spirv_type_options_ty } }, params[0], .type);
93669389 const result = try gz.addExtendedPayload(.reify_spirv_type, Zir.Inst.ReifySpirvType{
93679390 .src_line = gz.astgen.source_line,
9391 .src_column = gz.astgen.source_column,
93689392 .node = node,
93699393 .operand = operand,
93709394 });
......@@ -12392,6 +12416,8 @@ const GenZir = struct {
1239212416 }
1239312417
1239412418 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
12419 src_line: u32,
12420 src_column: u32,
1239512421 src_node: Ast.Node.Index,
1239612422 name_strat: Zir.Inst.NameStrategy,
1239712423 layout: std.lang.Type.ContainerLayout,
......@@ -12428,7 +12454,8 @@ const GenZir = struct {
1242812454 .fields_hash_1 = fields_hash_arr[1],
1242912455 .fields_hash_2 = fields_hash_arr[2],
1243012456 .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,
1243212459 .src_node = args.src_node,
1243312460 });
1243412461
......@@ -12461,6 +12488,8 @@ const GenZir = struct {
1246112488 }
1246212489
1246312490 fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
12491 src_line: u32,
12492 src_column: u32,
1246412493 src_node: Ast.Node.Index,
1246512494 name_strat: Zir.Inst.NameStrategy,
1246612495 kind: Zir.Inst.UnionDecl.Kind,
......@@ -12495,7 +12524,8 @@ const GenZir = struct {
1249512524 .fields_hash_1 = fields_hash_arr[1],
1249612525 .fields_hash_2 = fields_hash_arr[2],
1249712526 .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,
1249912529 .src_node = args.src_node,
1250012530 });
1250112531
......@@ -12530,6 +12560,8 @@ const GenZir = struct {
1253012560 }
1253112561
1253212562 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
12563 src_line: u32,
12564 src_column: u32,
1253312565 src_node: Ast.Node.Index,
1253412566 name_strat: Zir.Inst.NameStrategy,
1253512567 tag_type_body_len: ?u32,
......@@ -12563,7 +12595,8 @@ const GenZir = struct {
1256312595 .fields_hash_1 = fields_hash_arr[1],
1256412596 .fields_hash_2 = fields_hash_arr[2],
1256512597 .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,
1256712600 .src_node = args.src_node,
1256812601 });
1256912602
......@@ -12594,6 +12627,8 @@ const GenZir = struct {
1259412627 }
1259512628
1259612629 fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
12630 src_line: u32,
12631 src_column: u32,
1259712632 src_node: Ast.Node.Index,
1259812633 name_strat: Zir.Inst.NameStrategy,
1259912634 decls_len: u32,
......@@ -12615,7 +12650,8 @@ const GenZir = struct {
1261512650 args.decls.len);
1261612651
1261712652 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,
1261912655 .src_node = args.src_node,
1262012656 });
1262112657 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
lib/std/zig/Zir.zig+20-4
......@@ -3277,6 +3277,7 @@ pub const Inst = struct {
32773277
32783278 pub const ReifyStruct = struct {
32793279 src_line: u32,
3280 src_column: u32,
32803281 /// This node is absolute, because `reify` instructions are tracked across updates, and
32813282 /// this simplifies the logic for getting source locations for types.
32823283 node: Ast.Node.Index,
......@@ -3289,6 +3290,7 @@ pub const Inst = struct {
32893290
32903291 pub const ReifyUnion = struct {
32913292 src_line: u32,
3293 src_column: u32,
32923294 /// This node is absolute, because `reify` instructions are tracked across updates, and
32933295 /// this simplifies the logic for getting source locations for types.
32943296 node: Ast.Node.Index,
......@@ -3301,6 +3303,7 @@ pub const Inst = struct {
33013303
33023304 pub const ReifyEnum = struct {
33033305 src_line: u32,
3306 src_column: u32,
33043307 /// This node is absolute, because `reify` instructions are tracked across updates, and
33053308 /// this simplifies the logic for getting source locations for types.
33063309 node: Ast.Node.Index,
......@@ -3312,6 +3315,7 @@ pub const Inst = struct {
33123315
33133316 pub const ReifySpirvType = struct {
33143317 src_line: u32,
3318 src_column: u32,
33153319 /// This node is absolute, because `reify` instructions are tracked across updates, and
33163320 /// this simplifies the logic for getting source locations for types.
33173321 node: Ast.Node.Index,
......@@ -3509,6 +3513,7 @@ pub const Inst = struct {
35093513 fields_hash_2: u32,
35103514 fields_hash_3: u32,
35113515 src_line: u32,
3516 src_column: u32,
35123517 /// This node provides a new absolute baseline node for all instructions within this struct.
35133518 src_node: Ast.Node.Index,
35143519
......@@ -3664,6 +3669,7 @@ pub const Inst = struct {
36643669 fields_hash_2: u32,
36653670 fields_hash_3: u32,
36663671 src_line: u32,
3672 src_column: u32,
36673673 /// This node provides a new absolute baseline node for all instructions within this struct.
36683674 src_node: Ast.Node.Index,
36693675
......@@ -3701,6 +3707,7 @@ pub const Inst = struct {
37013707 fields_hash_2: u32,
37023708 fields_hash_3: u32,
37033709 src_line: u32,
3710 src_column: u32,
37043711 /// This node provides a new absolute baseline node for all instructions within this struct.
37053712 src_node: Ast.Node.Index,
37063713
......@@ -3756,6 +3763,7 @@ pub const Inst = struct {
37563763 /// 4. decl: Index, // for every decls_len; points to a `declaration` instruction
37573764 pub const OpaqueDecl = struct {
37583765 src_line: u32,
3766 src_column: u32,
37593767 /// This node provides a new absolute baseline node for all instructions within this struct.
37603768 src_node: Ast.Node.Index,
37613769
......@@ -3803,8 +3811,8 @@ pub const Inst = struct {
38033811 /// If this is an anonymous initialization (the operand is poison), this instruction becomes the owner of a type.
38043812 /// To resolve source locations, we need an absolute source node.
38053813 abs_node: Ast.Node.Index,
3806 /// Likewise, we need an absolute line number.
3807 abs_line: u32,
3814 src_line: u32,
3815 src_column: u32,
38083816 fields_len: u32,
38093817
38103818 pub const Item = struct {
......@@ -3823,8 +3831,8 @@ pub const Inst = struct {
38233831 /// This is an anonymous initialization, meaning this instruction becomes the owner of a type.
38243832 /// To resolve source locations, we need an absolute source node.
38253833 abs_node: Ast.Node.Index,
3826 /// Likewise, we need an absolute line number.
3827 abs_line: u32,
3834 src_line: u32,
3835 src_column: u32,
38283836 fields_len: u32,
38293837
38303838 pub const Item = struct {
......@@ -5318,6 +5326,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe
53185326 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
53195327 return .{
53205328 .src_line = extra.data.src_line,
5329 .src_column = extra.data.src_column,
53215330 .src_node = extra.data.src_node,
53225331 .name_strategy = small.name_strategy,
53235332 .captures = captures,
......@@ -5335,6 +5344,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe
53355344}
53365345pub const UnwrappedStructDecl = struct {
53375346 src_line: u32,
5347 src_column: u32,
53385348 src_node: Ast.Node.Index,
53395349 name_strategy: Inst.NameStrategy,
53405350
......@@ -5463,6 +5473,7 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl
54635473 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
54645474 return .{
54655475 .src_line = extra.data.src_line,
5476 .src_column = extra.data.src_column,
54665477 .src_node = extra.data.src_node,
54675478 .name_strategy = small.name_strategy,
54685479 .captures = captures,
......@@ -5479,6 +5490,7 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl
54795490}
54805491pub const UnwrappedUnionDecl = struct {
54815492 src_line: u32,
5493 src_column: u32,
54825494 src_node: Ast.Node.Index,
54835495 name_strategy: Inst.NameStrategy,
54845496
......@@ -5590,6 +5602,7 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {
55905602 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
55915603 return .{
55925604 .src_line = extra.data.src_line,
5605 .src_column = extra.data.src_column,
55935606 .src_node = extra.data.src_node,
55945607 .name_strategy = small.name_strategy,
55955608 .captures = captures,
......@@ -5604,6 +5617,7 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {
56045617}
56055618pub const UnwrappedEnumDecl = struct {
56065619 src_line: u32,
5620 src_column: u32,
56075621 src_node: Ast.Node.Index,
56085622 name_strategy: Inst.NameStrategy,
56095623
......@@ -5682,6 +5696,7 @@ pub fn getOpaqueDecl(zir: *const Zir, opaque_decl: Inst.Index) UnwrappedOpaqueDe
56825696 extra_index += decls_len;
56835697 return .{
56845698 .src_line = extra.data.src_line,
5699 .src_column = extra.data.src_column,
56855700 .src_node = extra.data.src_node,
56865701 .name_strategy = small.name_strategy,
56875702 .captures = captures,
......@@ -5691,6 +5706,7 @@ pub fn getOpaqueDecl(zir: *const Zir, opaque_decl: Inst.Index) UnwrappedOpaqueDe
56915706}
56925707pub const UnwrappedOpaqueDecl = struct {
56935708 src_line: u32,
5709 src_column: u32,
56945710 src_node: Ast.Node.Index,
56955711 name_strategy: Inst.NameStrategy,
56965712 captures: []const Inst.Capture,
lib/std/zig/llvm/Builder.zig+1-2
......@@ -3461,8 +3461,7 @@ pub const Global = struct {
34613461 const old_name = self.name(builder);
34623462 if (new_name == old_name) return;
34633463 const index = @backingInt(self.unwrap(builder));
3464 _ = builder.addGlobalAssumeCapacity(new_name, builder.globals.values()[index]);
3465 builder.globals.swapRemoveAt(index);
3464 builder.globals.setKey(index, new_name);
34663465 if (!old_name.isAnon()) return;
34673466 builder.next_unnamed_global = @fromBackingInt(@backingInt(builder.next_unnamed_global) - 1);
34683467 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,
21012101 .analysis_roots_buffer = undefined,
21022102 .analysis_roots_len = 0,
21032103 .codegen_task_pool = try .init(arena),
2104 .anon_name_counter = 0,
21042105 };
21052106 try zcu.init(gpa, io, options.thread_limit);
21062107 break :blk zcu;
......@@ -2383,6 +2384,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
23832384 comp.verbose_llvm_bc != null))
23842385 {
23852386 if (opt_zcu) |zcu| {
2387 dev.check(.llvm_backend);
23862388 zcu.llvm_object = try LlvmObject.create(arena, zcu);
23872389 }
23882390 }
......@@ -2829,6 +2831,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
28292831 }
28302832
28312833 const is_hit = man.hit(main_progress_node) catch |err| switch (err) {
2834 error.Canceled, error.OutOfMemory => |e| return e,
28322835 error.CacheCheckFailed => switch (man.diagnostic) {
28332836 .none => unreachable,
28342837 .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
28442847 });
28452848 },
28462849 },
2847 error.OutOfMemory, error.Canceled => |e| return e,
28482850 error.InvalidFormat => return comp.setMiscFailure(
28492851 .check_whole_cache,
28502852 "failed to check cache: invalid manifest file format",
......@@ -3283,8 +3285,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
32833285 .fuzz = comp.config.any_fuzz,
32843286 .lto = comp.config.lto,
32853287 }) catch |err| switch (err) {
3288 error.Canceled, error.OutOfMemory => |e| return e,
32863289 error.AlreadyReported => {},
3287 error.OutOfMemory => |e| return e,
32883290 };
32893291
32903292 if (zcu_obj_path) |path| {
......@@ -3293,8 +3295,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
32933295 // `link.Queue` has not called `prelink` because it knew we would want to send that
32943296 // final link input. It is *our* responsibility to call `prelink` now we're done.
32953297 comp.bin_file.?.prelink() catch |err| switch (err) {
3298 error.Canceled, error.OutOfMemory => |e| return e,
32963299 error.AlreadyReported => return,
3297 else => |e| return e,
32983300 };
32993301 }
33003302 }
......@@ -3308,8 +3310,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
33083310 };
33093311 // This is needed before reading the error flags.
33103312 lf.flush(arena, tid, comp.link_prog_node) catch |err| switch (err) {
3313 error.Canceled, error.OutOfMemory => |e| return e,
33113314 error.AlreadyReported => return,
3312 error.OutOfMemory, error.Canceled => |e| return e,
33133315 };
33143316 }
33153317}
......@@ -3709,8 +3711,15 @@ pub fn saveState(comp: *Compilation) !void {
37093711
37103712 // linker state
37113713 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 },
37123722 .wasm => {
3713 dev.check(link.File.Tag.wasm.devFeature());
37143723 const wasm = lf.cast(.wasm).?;
37153724 const is_obj = comp.config.output_mode == .Obj;
37163725 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
243243 var num_results: usize = 0;
244244 for (zcu.incremental_debug_state.types.keys()) |type_ip_index| {
245245 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);
247247 const success = switch (@as(u2, @intFromBool(anchor_start)) << 1 | @intFromBool(anchor_end)) {
248248 0b00 => std.mem.find(u8, ty_name, query) != null,
249249 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
347347 \\created on generation: {d}
348348 \\
349349 , .{
350 Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip),
350 Type.fromInterned(ip_index).containerTypeName(ip).fqn.fmt(ip),
351351 create_gen,
352352 });
353353 } 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 {
451451 .union_type,
452452 .enum_type,
453453 .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
456456 else => unreachable,
457457 }
src/InternPool.zig+54-6
......@@ -3207,9 +3207,10 @@ pub const LoadedStructType = struct {
32073207 captures: CaptureValue.Slice,
32083208 is_reified: bool,
32093209
3210 // TODO: the non-fqn will be needed by the new dwarf structure
32113210 /// The name of this struct type.
32123211 name: NullTerminatedString,
3212 /// The fully-qualified name of this struct type.
3213 fqn: NullTerminatedString,
32133214 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
32143215 /// Otherwise, or if this is a file's root struct type, this is `.none`.
32153216 name_nav: Nav.Index.Optional,
......@@ -3390,9 +3391,10 @@ pub const LoadedUnionType = struct {
33903391 captures: CaptureValue.Slice,
33913392 is_reified: bool,
33923393
3393 // TODO: the non-fqn will be needed by the new dwarf structure
33943394 /// The name of this union type.
33953395 name: NullTerminatedString,
3396 /// The fully-qualified name of this union type.
3397 fqn: NullTerminatedString,
33963398 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
33973399 /// Otherwise, this is `.none`.
33983400 name_nav: Nav.Index.Optional,
......@@ -3457,9 +3459,10 @@ pub const LoadedEnumType = struct {
34573459 owner_union: Index,
34583460 is_reified: bool,
34593461
3460 // TODO: the non-fqn will be needed by the new dwarf structure
34613462 /// The name of this enum type.
34623463 name: NullTerminatedString,
3464 /// The fully-qualified name of this enum type.
3465 fqn: NullTerminatedString,
34633466 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
34643467 /// Otherwise, this is `.none`.
34653468 name_nav: Nav.Index.Optional,
......@@ -3519,9 +3522,10 @@ pub const LoadedOpaqueType = struct {
35193522 zir_index: TrackedInst.Index,
35203523 captures: CaptureValue.Slice,
35213524
3522 // TODO: the non-fqn will be needed by the new dwarf structure
35233525 /// The name of this opaque type.
35243526 name: NullTerminatedString,
3527 /// The fully-qualified name of this opaque type.
3528 fqn: NullTerminatedString,
35253529 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
35263530 /// Otherwise, this is `.none`.
35273531 name_nav: Nav.Index.Optional,
......@@ -3607,6 +3611,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
36073611 .captures = captures,
36083612 .is_reified = extra.data.flags.any_captures == .reified,
36093613 .name = extra.data.name,
3614 .fqn = extra.data.fqn,
36103615 .name_nav = extra.data.name_nav,
36113616 .namespace = extra.data.namespace,
36123617 .layout = switch (extra.data.flags.layout) {
......@@ -3670,6 +3675,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
36703675 .captures = captures,
36713676 .is_reified = extra.data.bits.captures_len == .reified,
36723677 .name = extra.data.name,
3678 .fqn = extra.data.fqn,
36733679 .name_nav = extra.data.name_nav,
36743680 .namespace = extra.data.namespace,
36753681 .layout = .@"packed",
......@@ -3745,6 +3751,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
37453751 .captures = captures,
37463752 .is_reified = extra.data.flags.any_captures == .reified,
37473753 .name = extra.data.name,
3754 .fqn = extra.data.fqn,
37483755 .name_nav = extra.data.name_nav,
37493756 .namespace = extra.data.namespace,
37503757 .layout = switch (extra.data.flags.layout) {
......@@ -3800,6 +3807,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
38003807 .captures = captures,
38013808 .is_reified = extra.data.bits.captures_len == .reified,
38023809 .name = extra.data.name,
3810 .fqn = extra.data.fqn,
38033811 .name_nav = extra.data.name_nav,
38043812 .namespace = extra.data.namespace,
38053813 .layout = .@"packed",
......@@ -3880,6 +3888,7 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
38803888 .is_reified = extra.data.bits.captures_len == .reified,
38813889 .owner_union = owner_union,
38823890 .name = extra.data.name,
3891 .fqn = extra.data.fqn,
38833892 .name_nav = extra.data.name_nav,
38843893 .namespace = extra.data.namespace,
38853894 .int_tag_type = extra.data.int_tag_type,
......@@ -3906,6 +3915,7 @@ pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType {
39063915 .len = extra.data.captures_len,
39073916 },
39083917 .name = extra.data.name,
3918 .fqn = extra.data.fqn,
39093919 .name_nav = extra.data.name_nav,
39103920 .namespace = extra.data.namespace,
39113921 };
......@@ -5538,6 +5548,7 @@ pub const Tag = enum(u8) {
55385548 zir_index: TrackedInst.Index,
55395549
55405550 name: NullTerminatedString,
5551 fqn: NullTerminatedString,
55415552 name_nav: Nav.Index.Optional,
55425553 namespace: NamespaceIndex,
55435554
......@@ -5580,6 +5591,7 @@ pub const Tag = enum(u8) {
55805591 bits: Bits,
55815592
55825593 name: NullTerminatedString,
5594 fqn: NullTerminatedString,
55835595 name_nav: Nav.Index.Optional,
55845596 namespace: NamespaceIndex,
55855597
......@@ -5614,6 +5626,7 @@ pub const Tag = enum(u8) {
56145626 zir_index: TrackedInst.Index,
56155627
56165628 name: NullTerminatedString,
5629 fqn: NullTerminatedString,
56175630 name_nav: Nav.Index.Optional,
56185631 namespace: NamespaceIndex,
56195632 /// The enum that provides the list of field names and values.
......@@ -5673,6 +5686,7 @@ pub const Tag = enum(u8) {
56735686 bits: Bits,
56745687
56755688 name: NullTerminatedString,
5689 fqn: NullTerminatedString,
56765690 name_nav: Nav.Index.Optional,
56775691 namespace: NamespaceIndex,
56785692
......@@ -5708,6 +5722,7 @@ pub const Tag = enum(u8) {
57085722 bits: Bits,
57095723
57105724 name: NullTerminatedString,
5725 fqn: NullTerminatedString,
57115726 name_nav: Nav.Index.Optional,
57125727 namespace: NamespaceIndex,
57135728
......@@ -5735,6 +5750,7 @@ pub const Tag = enum(u8) {
57355750 captures_len: u32,
57365751
57375752 name: NullTerminatedString,
5753 fqn: NullTerminatedString,
57385754 name_nav: Nav.Index.Optional,
57395755 namespace: NamespaceIndex,
57405756 };
......@@ -8063,6 +8079,7 @@ pub fn getDeclaredStructType(
80638079 .want_layout = false,
80648080 },
80658081 .name = undefined, // set by `finish`
8082 .fqn = undefined, // set by `finish`
80668083 .name_nav = undefined, // set by `finish`
80678084 .namespace = undefined, // set by `finish`
80688085 .backing_int_type = .none,
......@@ -8086,6 +8103,7 @@ pub fn getDeclaredStructType(
80868103 .index = gop.put(),
80878104 .tid = tid,
80888105 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
8106 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "fqn").?,
80898107 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,
80908108 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
80918109 .field_names = undefined,
......@@ -8111,6 +8129,7 @@ pub fn getDeclaredStructType(
81118129 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
81128130 .zir_index = ini.zir_index,
81138131 .name = undefined, // set by `finish`
8132 .fqn = undefined, // set by `finish`
81148133 .name_nav = undefined, // set by `finish`
81158134 .namespace = undefined, // set by `finish`
81168135 .fields_len = ini.fields_len,
......@@ -8154,6 +8173,7 @@ pub fn getDeclaredStructType(
81548173 .index = gop.put(),
81558174 .tid = tid,
81568175 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
8176 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "fqn").?,
81578177 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,
81588178 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,
81598179 .field_names = undefined,
......@@ -8207,6 +8227,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe
82078227 .want_layout = false,
82088228 },
82098229 .name = undefined, // set by `finish`
8230 .fqn = undefined, // set by `finish`
82108231 .name_nav = undefined, // set by `finish`
82118232 .namespace = undefined, // set by `finish`
82128233 .backing_int_type = ini.packed_backing_int_type,
......@@ -8233,6 +8254,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe
82338254 .index = gop.put(),
82348255 .tid = tid,
82358256 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
8257 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "fqn").?,
82368258 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,
82378259 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
82388260 .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
82608282 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
82618283 .zir_index = ini.zir_index,
82628284 .name = undefined, // set by `finish`
8285 .fqn = undefined, // set by `finish`
82638286 .name_nav = undefined, // set by `finish`
82648287 .namespace = undefined, // set by `finish`
82658288 .fields_len = ini.fields_len,
......@@ -8305,6 +8328,7 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe
83058328 .index = gop.put(),
83068329 .tid = tid,
83078330 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
8331 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "fqn").?,
83088332 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,
83098333 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,
83108334 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
......@@ -8378,6 +8402,7 @@ pub fn getDeclaredUnionType(
83788402 .want_layout = false,
83798403 },
83808404 .name = undefined, // set by `finish`
8405 .fqn = undefined, // set by `finish`
83818406 .name_nav = undefined, // set by `finish`
83828407 .namespace = undefined, // set by `finish`
83838408 .backing_int_type = .none,
......@@ -8397,6 +8422,7 @@ pub fn getDeclaredUnionType(
83978422 .index = gop.put(),
83988423 .tid = tid,
83998424 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,
8425 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "fqn").?,
84008426 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,
84018427 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,
84028428 .field_names = undefined,
......@@ -8417,6 +8443,7 @@ pub fn getDeclaredUnionType(
84178443 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{
84188444 .zir_index = ini.zir_index,
84198445 .name = undefined, // set by `finish`
8446 .fqn = undefined, // set by `finish`
84208447 .name_nav = undefined, // set by `finish`
84218448 .namespace = undefined, // set by `finish`
84228449 .enum_tag_type = .none,
......@@ -8451,6 +8478,7 @@ pub fn getDeclaredUnionType(
84518478 .index = gop.put(),
84528479 .tid = tid,
84538480 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
8481 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "fqn").?,
84548482 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,
84558483 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
84568484 .field_names = undefined,
......@@ -8501,6 +8529,7 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per
85018529 .want_layout = false,
85028530 },
85038531 .name = undefined, // set by `finish`
8532 .fqn = undefined, // set by `finish`
85048533 .name_nav = undefined, // set by `finish`
85058534 .namespace = undefined, // set by `finish`
85068535 .backing_int_type = ini.packed_backing_int_type,
......@@ -8523,6 +8552,7 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per
85238552 .index = gop.put(),
85248553 .tid = tid,
85258554 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,
8555 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "fqn").?,
85268556 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,
85278557 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,
85288558 .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
85438573 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{
85448574 .zir_index = ini.zir_index,
85458575 .name = undefined, // set by `finish`
8576 .fqn = undefined, // set by `finish`
85468577 .name_nav = undefined, // set by `finish`
85478578 .namespace = undefined, // set by `finish`
85488579 .enum_tag_type = ini.enum_tag_type,
......@@ -8578,6 +8609,7 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per
85788609 .index = gop.put(),
85798610 .tid = tid,
85808611 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
8612 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "fqn").?,
85818613 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,
85828614 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
85838615 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
......@@ -8654,6 +8686,7 @@ pub fn getDeclaredEnumType(
86548686 .want_layout = false,
86558687 },
86568688 .name = undefined, // set by `finish`
8689 .fqn = undefined, // set by `finish`
86578690 .name_nav = undefined, // set by `finish`
86588691 .namespace = undefined, // set by `finish`
86598692 .int_tag_type = .none,
......@@ -8673,6 +8706,7 @@ pub fn getDeclaredEnumType(
86738706 .index = gop.put(),
86748707 .tid = tid,
86758708 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
8709 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "fqn").?,
86768710 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
86778711 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
86788712 .field_names = undefined,
......@@ -8729,6 +8763,7 @@ pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerT
87298763 .want_layout = false,
87308764 },
87318765 .name = undefined, // set by `finish`
8766 .fqn = undefined, // set by `finish`
87328767 .name_nav = undefined, // set by `finish`
87338768 .namespace = undefined, // set by `finish`
87348769 .int_tag_type = ini.int_tag_type,
......@@ -8750,6 +8785,7 @@ pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerT
87508785 .index = gop.put(),
87518786 .tid = tid,
87528787 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
8788 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "fqn").?,
87538789 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
87548790 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
87558791 .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
88288864 .want_layout = false,
88298865 },
88308866 .name = undefined, // set by `finish`
8867 .fqn = undefined, // set by `finish`
88318868 .name_nav = undefined, // set by `finish`
88328869 .namespace = undefined, // set by `finish`
88338870 .int_tag_type = .none,
......@@ -8849,6 +8886,7 @@ pub fn getGeneratedEnumTagType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu
88498886 .index = gop.put(),
88508887 .tid = tid,
88518888 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
8889 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "fqn").?,
88528890 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
88538891 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
88548892 .field_names = undefined,
......@@ -8880,6 +8918,7 @@ pub fn getDeclaredOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.P
88808918 .zir_index = ini.zir_index,
88818919 .captures_len = @intCast(ini.captures.len),
88828920 .name = undefined, // set by `finish`
8921 .fqn = undefined, // set by `finish`
88838922 .name_nav = undefined, // set by `finish`
88848923 .namespace = undefined, // set by `finish`
88858924 });
......@@ -8892,6 +8931,7 @@ pub fn getDeclaredOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.P
88928931 .index = gop.put(),
88938932 .tid = tid,
88948933 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?,
8934 .type_fqn_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "fqn").?,
88958935 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?,
88968936 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?,
88978937 .field_names = undefined,
......@@ -8906,6 +8946,7 @@ pub const WipContainerType = struct {
89068946 index: Index,
89078947 tid: Zcu.PerThread.Id,
89088948 type_name_index: u32,
8949 type_fqn_index: u32,
89098950 name_nav_index: u32,
89108951 namespace_index: u32,
89118952
......@@ -8923,6 +8964,7 @@ pub const WipContainerType = struct {
89238964 wip: WipContainerType,
89248965 ip: *InternPool,
89258966 type_name: NullTerminatedString,
8967 type_fqn: NullTerminatedString,
89268968 /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise.
89278969 /// This is also `.none` if we use `.parent` because we are the root struct type for a file.
89288970 name_nav: Nav.Index.Optional,
......@@ -8930,6 +8972,7 @@ pub const WipContainerType = struct {
89308972 const extra = ip.getLocalShared(wip.tid).extra.acquire();
89318973 const extra_items = extra.view().items(.@"0");
89328974 extra_items[wip.type_name_index] = @backingInt(type_name);
8975 extra_items[wip.type_fqn_index] = @backingInt(type_fqn);
89338976 extra_items[wip.name_nav_index] = @backingInt(name_nav);
89348977 }
89358978
......@@ -9503,6 +9546,7 @@ pub const GetFuncInstanceKey = struct {
95039546 is_noinline: bool,
95049547 generic_owner: Index,
95059548 inferred_error_set: bool,
9549 anon_name_counter: *u32,
95069550};
95079551
95089552pub fn getFuncInstance(
......@@ -9580,6 +9624,7 @@ pub fn getFuncInstance(
95809624 generic_owner,
95819625 func_index,
95829626 func_extra_index,
9627 arg.anon_name_counter,
95839628 );
95849629 return gop.put();
95859630}
......@@ -9731,6 +9776,7 @@ fn getFuncInstanceIes(
97319776 generic_owner,
97329777 func_index,
97339778 func_extra_index,
9779 arg.anon_name_counter,
97349780 );
97359781
97369782 func_gop.putFinal(func_index);
......@@ -9749,14 +9795,16 @@ fn finishFuncInstance(
97499795 generic_owner: Index,
97509796 func_index: Index,
97519797 func_extra_index: u32,
9798 anon_name_counter: *u32,
97529799) Allocator.Error!void {
97539800 const fn_owner_nav = ip.getNav(ip.funcDeclInfo(generic_owner).owner_nav);
97549801 const fn_namespace = fn_owner_nav.analysis.?.namespace;
97559802
97569803 // TODO: improve this name
9757 const nav_name = try ip.getOrPutStringFmt(gpa, io, tid, "{f}__anon_{d}", .{
9758 fn_owner_nav.name.fmt(ip), @backingInt(func_index),
9804 const nav_name = try ip.getOrPutStringFmt(gpa, io, tid, "{f}__func_{d}", .{
9805 fn_owner_nav.name.fmt(ip), anon_name_counter.*,
97599806 }, .no_embedded_nulls);
9807 anon_name_counter.* += 1;
97609808 const nav_fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, io, tid, nav_name);
97619809 const nav_index = try ip.createNav(gpa, io, tid, nav_name, nav_fqn, .{
97629810 .type = ip.typeOf(func_index),
src/Sema.zig+40-12
......@@ -403,6 +403,7 @@ pub const Block = struct {
403403 /// is always incorporated into the type name somehow.
404404 /// See `Sema.setTypeName`.
405405 type_name_ctx: InternPool.NullTerminatedString,
406 type_fqn_ctx: InternPool.NullTerminatedString,
406407
407408 /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block.
408409 /// Specifically, the given `Offset` is treated as relative to `block.src_base_inst`.
......@@ -531,6 +532,7 @@ pub const Block = struct {
531532 .need_debug_scope = parent.need_debug_scope,
532533 .src_base_inst = parent.src_base_inst,
533534 .type_name_ctx = parent.type_name_ctx,
535 .type_fqn_ctx = parent.type_fqn_ctx,
534536 };
535537 }
536538
......@@ -4782,7 +4784,7 @@ fn failWithBadStructFieldAccess(
47824784 const msg = try sema.errMsg(
47834785 field_src,
47844786 "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) },
47864788 );
47874789 errdefer msg.destroy(sema.gpa);
47884790 try sema.errNote(struct_ty.srcLoc(zcu), msg, "struct declared here", .{});
......@@ -4808,7 +4810,7 @@ fn failWithBadUnionFieldAccess(
48084810 const msg = try sema.errMsg(
48094811 field_src,
48104812 "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) },
48124814 );
48134815 errdefer msg.destroy(gpa);
48144816 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
52915293 .error_return_trace_index = parent_block.error_return_trace_index,
52925294 .src_base_inst = parent_block.src_base_inst,
52935295 .type_name_ctx = parent_block.type_name_ctx,
5296 .type_fqn_ctx = parent_block.type_fqn_ctx,
52945297 };
52955298
52965299 defer child_block.instructions.deinit(gpa);
......@@ -6773,7 +6776,8 @@ fn analyzeCall(
67736776 .instructions = .empty,
67746777 .inlining = &generic_inlining,
67756778 .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,
67776781 } else undefined;
67786782 defer if (any_generic_types) generic_block.instructions.deinit(gpa);
67796783
......@@ -7039,6 +7043,7 @@ fn analyzeCall(
70397043 .inferred_error_set = fn_zir_info.inferred_error_set,
70407044 .generic_owner = func_val.?.toIntern(),
70417045 .comptime_args = comptime_args,
7046 .anon_name_counter = &zcu.anon_name_counter,
70427047 });
70437048 if (zcu.comp.debugIncremental()) {
70447049 const nav = ip.indexToKey(func_instance).func.owner_nav;
......@@ -7308,7 +7313,8 @@ fn analyzeCall(
73087313 .runtime_loop = block.runtime_loop,
73097314 .runtime_index = block.runtime_index,
73107315 .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,
73127318 };
73137319
73147320 defer child_block.instructions.deinit(gpa);
......@@ -17314,6 +17320,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
1731417320 .error_return_trace_index = block.error_return_trace_index,
1731517321 .src_base_inst = block.src_base_inst,
1731617322 .type_name_ctx = block.type_name_ctx,
17323 .type_fqn_ctx = block.type_fqn_ctx,
1731717324 };
1731817325 defer child_block.instructions.deinit(sema.gpa);
1731917326
......@@ -17380,6 +17387,7 @@ fn zirTypeofPeer(
1738017387 .runtime_index = block.runtime_index,
1738117388 .src_base_inst = block.src_base_inst,
1738217389 .type_name_ctx = block.type_name_ctx,
17390 .type_fqn_ctx = block.type_fqn_ctx,
1738317391 };
1738417392 defer child_block.instructions.deinit(sema.gpa);
1738517393 // 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
1793917947 .comptime_reason = block.comptime_reason,
1794017948 .src_base_inst = block.src_base_inst,
1794117949 .type_name_ctx = block.type_name_ctx,
17950 .type_fqn_ctx = block.type_fqn_ctx,
1794217951 },
1794317952 };
1794417953 sema.post_hoc_blocks.putAssumeCapacityNoClobber(new_block_inst, labeled_block);
......@@ -25934,6 +25943,7 @@ fn addSafetyCheck(
2593425943 .comptime_reason = null,
2593525944 .src_base_inst = parent_block.src_base_inst,
2593625945 .type_name_ctx = parent_block.type_name_ctx,
25946 .type_fqn_ctx = parent_block.type_fqn_ctx,
2593725947 };
2593825948
2593925949 defer fail_block.instructions.deinit(gpa);
......@@ -26028,6 +26038,7 @@ fn addSafetyCheckUnwrapError(
2602826038 .comptime_reason = null,
2602926039 .src_base_inst = parent_block.src_base_inst,
2603026040 .type_name_ctx = parent_block.type_name_ctx,
26041 .type_fqn_ctx = parent_block.type_fqn_ctx,
2603126042 };
2603226043
2603326044 defer fail_block.instructions.deinit(gpa);
......@@ -26151,6 +26162,7 @@ fn addSafetyCheckCall(
2615126162 .comptime_reason = null,
2615226163 .src_base_inst = parent_block.src_base_inst,
2615326164 .type_name_ctx = parent_block.type_name_ctx,
26165 .type_fqn_ctx = parent_block.type_fqn_ctx,
2615426166 };
2615526167
2615626168 defer fail_block.instructions.deinit(gpa);
......@@ -34993,6 +35005,7 @@ pub fn analyzeMemoizedState(sema: *Sema, stage: InternPool.MemoizedStateStage) C
3499335005 .comptime_reason = null,
3499435006 .src_base_inst = std_type.typeDeclInst(zcu).?,
3499535007 .type_name_ctx = .empty,
35008 .type_fqn_ctx = .empty,
3499635009 };
3499735010 };
3499835011 defer block.instructions.deinit(gpa);
......@@ -35222,11 +35235,19 @@ pub fn setTypeName(
3522235235 io,
3522335236 pt.tid,
3522435237 "{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 },
3522635246 .no_embedded_nulls,
3522735247 ), .none);
35248 zcu.anon_name_counter += 1;
3522835249 },
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()),
3523035251 .func => {
3523135252 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse {
3523235253 return sema.failTransitive(.{ .lost_tracking = ip.funcZirBodyInst(sema.func_index) });
......@@ -35236,7 +35257,7 @@ pub fn setTypeName(
3523635257 var aw: std.Io.Writer.Allocating = .init(gpa);
3523735258 defer aw.deinit();
3523835259 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
3524135262 var arg_i: usize = 0;
3524235263 for (fn_info.param_body) |zir_inst| switch (zir_tags[@backingInt(zir_inst)]) {
......@@ -35271,8 +35292,13 @@ pub fn setTypeName(
3527135292 };
3527235293
3527335294 w.writeByte(')') catch return error.OutOfMemory;
35274 const name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls);
35275 wip.setName(ip, name, .none);
35295 wip.setName(ip, try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}{s}", .{
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);
3527635302 },
3527735303 .dbg_var => {
3527835304 // 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(
3528735313 } else {
3528835314 continue :strat .anon;
3528935315 };
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
3529135318 block.type_name_ctx.fmt(ip), var_name,
35292 }, .no_embedded_nulls);
35293 wip.setName(ip, name, .none);
35319 }, .no_embedded_nulls), try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
35320 block.type_fqn_ctx.fmt(ip), var_name,
35321 }, .no_embedded_nulls), .none);
3529435322 },
3529535323 }
3529635324}
src/Sema/type_resolution.zig+15-4
......@@ -187,7 +187,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
187187
188188 const tracy = trace(@src());
189189 defer tracy.end();
190 tracy.addText(struct_ty.containerTypeName(ip).toSlice(ip));
190 tracy.addText(struct_ty.containerTypeName(ip).fqn.toSlice(ip));
191191 tracy.addTextFmt("ip_index={d}", .{struct_ty.toIntern()});
192192
193193 assert(sema.owner.unwrap().type_layout == struct_ty.toIntern());
......@@ -207,6 +207,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
207207 .comptime_reason = undefined, // always set before using `block`
208208 .src_base_inst = struct_obj.zir_index,
209209 .type_name_ctx = struct_obj.name,
210 .type_fqn_ctx = struct_obj.fqn,
210211 };
211212 defer block.instructions.deinit(gpa);
212213
......@@ -613,7 +614,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
613614
614615 const tracy = trace(@src());
615616 defer tracy.end();
616 tracy.addText(struct_ty.containerTypeName(ip).toSlice(ip));
617 tracy.addText(struct_ty.containerTypeName(ip).fqn.toSlice(ip));
617618 tracy.addTextFmt("ip_index={d}", .{struct_ty.toIntern()});
618619
619620 assert(sema.owner.unwrap().struct_defaults == struct_ty.toIntern());
......@@ -653,6 +654,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
653654 .comptime_reason = undefined, // always set before using `block`
654655 .src_base_inst = struct_obj.zir_index,
655656 .type_name_ctx = struct_obj.name,
657 .type_fqn_ctx = struct_obj.fqn,
656658 };
657659 defer block.instructions.deinit(gpa);
658660
......@@ -727,7 +729,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
727729
728730 const tracy = trace(@src());
729731 defer tracy.end();
730 tracy.addText(union_ty.containerTypeName(ip).toSlice(ip));
732 tracy.addText(union_ty.containerTypeName(ip).fqn.toSlice(ip));
731733 tracy.addTextFmt("ip_index={d}", .{union_ty.toIntern()});
732734
733735 assert(sema.owner.unwrap().type_layout == union_ty.toIntern());
......@@ -747,6 +749,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
747749 .comptime_reason = undefined, // always set before using `block`
748750 .src_base_inst = union_obj.zir_index,
749751 .type_name_ctx = union_obj.name,
752 .type_fqn_ctx = union_obj.fqn,
750753 };
751754 defer block.instructions.deinit(gpa);
752755
......@@ -801,6 +804,13 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
801804 "@typeInfo({f}).@\"union\".tag_type.?",
802805 .{union_obj.name.fmt(ip)},
803806 .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,
804814 ), .none);
805815 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
806816 .parent = union_obj.namespace.toOptional(),
......@@ -1221,7 +1231,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {
12211231
12221232 const tracy = trace(@src());
12231233 defer tracy.end();
1224 tracy.addText(enum_ty.containerTypeName(ip).toSlice(ip));
1234 tracy.addText(enum_ty.containerTypeName(ip).fqn.toSlice(ip));
12251235 tracy.addTextFmt("ip_index={d}", .{enum_ty.toIntern()});
12261236
12271237 assert(sema.owner.unwrap().type_layout == enum_ty.toIntern());
......@@ -1248,6 +1258,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {
12481258 .comptime_reason = undefined, // always set before using `block`
12491259 .src_base_inst = tracked_inst,
12501260 .type_name_ctx = enum_obj.name,
1261 .type_fqn_ctx = enum_obj.fqn,
12511262 };
12521263 defer block.instructions.deinit(gpa);
12531264
src/Type.zig+48-25
......@@ -109,6 +109,20 @@ pub const Class = enum(u3) {
109109 /// Then, aggregates containing fully-comptime types may themselves be either fully-comptime or
110110 /// partially-comptime; see the doc comment on `.partially_comptime` for details.
111111 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 }
112126};
113127
114128/// 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
593607 .generic_poison => unreachable,
594608 },
595609 .struct_type => {
596 const name = ip.loadStructType(ty.toIntern()).name;
597 try writer.print("{f}", .{name.fmt(ip)});
610 const fqn = ip.loadStructType(ty.toIntern()).fqn;
611 try writer.print("{f}", .{fqn.fmt(ip)});
598612 },
599613 .tuple_type => |tuple| {
600614 if (tuple.types.len == 0) {
......@@ -611,16 +625,16 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari
611625 },
612626
613627 .union_type => {
614 const name = ip.loadUnionType(ty.toIntern()).name;
615 try writer.print("{f}", .{name.fmt(ip)});
628 const fqn = ip.loadUnionType(ty.toIntern()).fqn;
629 try writer.print("{f}", .{fqn.fmt(ip)});
616630 },
617631 .opaque_type => {
618 const name = ip.loadOpaqueType(ty.toIntern()).name;
619 try writer.print("{f}", .{name.fmt(ip)});
632 const fqn = ip.loadOpaqueType(ty.toIntern()).fqn;
633 try writer.print("{f}", .{fqn.fmt(ip)});
620634 },
621635 .enum_type => {
622 const name = ip.loadEnumType(ty.toIntern()).name;
623 try writer.print("{f}", .{name.fmt(ip)});
636 const fqn = ip.loadEnumType(ty.toIntern()).fqn;
637 try writer.print("{f}", .{fqn.fmt(ip)});
624638 },
625639 .spirv_type => {
626640 const info = ip.loadSpirvType(ty.toIntern());
......@@ -761,10 +775,7 @@ pub fn toValue(self: Type) Value {
761775///
762776/// * All other types contain some runtime state, so have runtime bits and a non-zero ABI size.
763777pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
764 return switch (ty.classify(zcu)) {
765 .no_possible_value, .one_possible_value, .fully_comptime => false,
766 .runtime, .partially_comptime => true,
767 };
778 return ty.classify(zcu).hasRuntimeBits();
768779}
769780
770781/// 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 {
21952206pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {
21962207 if (ty.toIntern() == .generic_poison_type) return false;
21972208 if (ty.zigTypeTag(zcu) == .error_union and ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) return false;
2198 return switch (ty.classify(zcu)) {
2199 .no_possible_value, .one_possible_value, .runtime => false,
2200 .partially_comptime, .fully_comptime => true,
2201 };
2209 return ty.classify(zcu).comptimeOnly();
22022210}
22032211
22042212pub fn isVector(ty: Type, zcu: *const Zcu) bool {
......@@ -2685,8 +2693,8 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
26852693 };
26862694 const inst = zir.instructions.get(@backingInt(info.inst));
26872695 return switch (inst.tag) {
2688 .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_line,
2689 .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, 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,
2697 .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.src_line,
26902698 .extended => switch (inst.data.extended.opcode) {
26912699 .struct_decl => zir.getStructDecl(info.inst).src_line,
26922700 .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
30123020 return pt.ptrType(field_ptr_info);
30133021}
30143022
3015pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTerminatedString {
3016 return switch (ip.indexToKey(ty.toIntern())) {
3017 .struct_type => ip.loadStructType(ty.toIntern()).name,
3018 .union_type => ip.loadUnionType(ty.toIntern()).name,
3019 .enum_type => ip.loadEnumType(ty.toIntern()).name,
3020 .opaque_type => ip.loadOpaqueType(ty.toIntern()).name,
3023pub fn containerTypeName(ty: Type, ip: *const InternPool) struct {
3024 name: InternPool.NullTerminatedString,
3025 fqn: InternPool.NullTerminatedString,
3026} {
3027 switch (ip.indexToKey(ty.toIntern())) {
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 },
30213044 else => unreachable,
3022 };
3045 }
30233046}
30243047
30253048pub fn destructurable(ty: Type, zcu: *const Zcu) bool {
src/Zcu.zig+121-81
......@@ -348,6 +348,9 @@ codegen_task_pool: CodegenTaskPool,
348348
349349generation: u32 = 0,
350350
351/// Only access from the Sema thread.
352anon_name_counter: u32,
353
351354pub const DependencyReason = struct {
352355 src: LazySrcLoc,
353356 /// Only populated if this is for a `.type_layout` unit.
......@@ -944,9 +947,9 @@ pub const Namespace = struct {
944947 tid: Zcu.PerThread.Id,
945948 name: InternPool.NullTerminatedString,
946949 ) !InternPool.NullTerminatedString {
947 const ns_name = Type.fromInterned(ns.owner_type).containerTypeName(ip);
948 if (name == .empty) return ns_name;
949 return ip.getOrPutStringFmt(gpa, io, tid, "{f}.{f}", .{ ns_name.fmt(ip), name.fmt(ip) }, .no_embedded_nulls);
950 const ns_fqn = Type.fromInterned(ns.owner_type).containerTypeName(ip).fqn;
951 if (name == .empty) return ns_fqn;
952 return ip.getOrPutStringFmt(gpa, io, tid, "{f}.{f}", .{ ns_fqn.fmt(ip), name.fmt(ip) }, .no_embedded_nulls);
950953 }
951954};
952955
......@@ -4234,7 +4237,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
42344237 const referencer = types.values()[type_idx];
42354238 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
42394242 // Queue any decls within this type which would be automatically analyzed.
42404243 // 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
42454248 const gop = try units.getOrPut(gpa, unit);
42464249 if (!gop.found_existing) {
42474250 refs_log.debug("type '{f}': ref comptime %{}", .{
4248 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
4251 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip),
42494252 @backingInt(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue),
42504253 });
42514254 gop.value_ptr.* = referencer;
......@@ -4279,7 +4282,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
42794282 const gop = try units.getOrPut(gpa, .wrap(.{ .nav_val = nav_id }));
42804283 if (!gop.found_existing) {
42814284 refs_log.debug("type '{f}': ref test %{}", .{
4282 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
4285 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip),
42834286 @backingInt(inst_info.inst),
42844287 });
42854288 gop.value_ptr.* = referencer;
......@@ -4302,7 +4305,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
43024305 const gop = try units.getOrPut(gpa, unit);
43034306 if (!gop.found_existing) {
43044307 refs_log.debug("type '{f}': ref named %{}", .{
4305 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
4308 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip),
43064309 @backingInt(inst_info.inst),
43074310 });
43084311 gop.value_ptr.* = referencer;
......@@ -4319,7 +4322,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
43194322 const gop = try units.getOrPut(gpa, unit);
43204323 if (!gop.found_existing) {
43214324 refs_log.debug("type '{f}': ref named %{}", .{
4322 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
4325 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip),
43234326 @backingInt(inst_info.inst),
43244327 });
43254328 gop.value_ptr.* = referencer;
......@@ -4382,7 +4385,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
43824385 if (!gop.found_existing) {
43834386 refs_log.debug("unit '{f}': ref type '{f}'", .{
43844387 zcu.fmtAnalUnit(unit),
4385 Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip),
4388 Type.fromInterned(ref.referenced).containerTypeName(ip).fqn.fmt(ip),
43864389 });
43874390 gop.value_ptr.* = .{
43884391 .referencer = unit,
......@@ -4495,7 +4498,7 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void
44954498 }
44964499 },
44974500 .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) }),
44994502 .func => |func| {
45004503 const nav = zcu.funcInfo(func).owner_nav;
45014504 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
45214524 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) });
45224525 },
45234526 .type_layout, .struct_defaults => |ip_index, tag| {
4524 const name = Type.fromInterned(ip_index).containerTypeName(ip);
4525 return writer.print("{t}('{f}')", .{ tag, name.fmt(ip) });
4527 const fqn = Type.fromInterned(ip_index).containerTypeName(ip).fqn;
4528 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) });
45264529 },
45274530 .func_ies => |ip_index| {
45284531 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)
45694572 if (allowed_arch == target.cpu.arch) break;
45704573 } else return .{ .bad_arch = cc.archs() },
45714574 }
4572 const backend_ok = switch (backend) {
4575 const backend_ok = ok: switch (backend) {
45734576 .stage1 => unreachable,
45744577 .other => unreachable,
45754578 _ => unreachable,
45764579
4577 .stage2_llvm => @import("codegen/llvm.zig").toLlvmCallConv(cc, target) != null,
4578 .stage2_c => ok: {
4580 .stage2_llvm => {
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);
45794586 if (target.cCallingConvention()) |default_c| {
45804587 if (cc.eql(default_c)) {
45814588 break :ok true;
......@@ -4633,81 +4640,114 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
46334640 else => false,
46344641 };
46354642 },
4636 .stage2_wasm => switch (cc) {
4637 .wasm_mvp => |opts| opts.incoming_stack_alignment == null,
4638 else => false,
4639 },
4640 .stage2_arm => switch (cc) {
4641 .arm_aapcs => |opts| opts.incoming_stack_alignment == null,
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,
4643 .stage2_wasm => {
4644 dev.check(.wasm_backend);
4645 break :ok switch (cc) {
4646 .wasm_mvp => |opts| opts.incoming_stack_alignment == null,
4647 else => false,
4648 };
46484649 },
4649 .stage2_aarch64 => switch (cc) {
4650 .aarch64_aapcs, .aarch64_aapcs_darwin, .naked => true,
4651 else => false,
4650 .stage2_arm => {
4651 dev.check(.arm_backend);
4652 break :ok switch (cc) {
4653 .arm_aapcs => |opts| opts.incoming_stack_alignment == null,
4654 .naked => true,
4655 else => false,
4656 };
46524657 },
4653 .stage2_x86 => switch (cc) {
4654 .x86_sysv,
4655 .x86_win,
4656 .x86_mingw,
4657 => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0,
4658 .naked => true,
4659 else => false,
4658 .stage2_x86_64 => {
4659 dev.check(.x86_64_backend);
4660 break :ok switch (cc) {
4661 .x86_64_sysv, .x86_64_win, .naked => true, // incoming stack alignment supported
4662 else => false,
4663 };
46604664 },
4661 .stage2_powerpc => switch (target.cpu.arch) {
4662 .powerpc, .powerpcle => switch (cc) {
4663 .powerpc_sysv,
4664 .powerpc_sysv_altivec,
4665 .powerpc_aix,
4666 .powerpc_aix_altivec,
4667 .naked,
4668 => true,
4665 .stage2_aarch64 => {
4666 dev.check(.aarch64_backend);
4667 break :ok switch (cc) {
4668 .aarch64_aapcs, .aarch64_aapcs_darwin, .naked => true,
46694669 else => false,
4670 },
4671 .powerpc64, .powerpc64le => switch (cc) {
4672 .powerpc64_elf,
4673 .powerpc64_elf_altivec,
4674 .powerpc64_elf_v2,
4675 .naked,
4676 => true,
4670 };
4671 },
4672 .stage2_x86 => {
4673 dev.check(.x86_backend);
4674 break :ok switch (cc) {
4675 .x86_sysv,
4676 .x86_win,
4677 .x86_mingw,
4678 => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0,
4679 .naked => true,
46774680 else => false,
4678 },
4679 else => unreachable,
4681 };
46804682 },
4681 .stage2_riscv64 => switch (cc) {
4682 .riscv64_lp64 => |opts| opts.incoming_stack_alignment == null,
4683 .naked => true,
4684 else => false,
4683 .stage2_powerpc => {
4684 dev.check(.powerpc_backend);
4685 break :ok switch (target.cpu.arch) {
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 };
46854705 },
4686 .stage2_sparc64 => switch (cc) {
4687 .sparc64_sysv => |opts| opts.incoming_stack_alignment == null,
4688 .naked => true,
4689 else => false,
4706 .stage2_riscv64 => {
4707 dev.check(.riscv64_backend);
4708 break :ok switch (cc) {
4709 .riscv64_lp64 => |opts| opts.incoming_stack_alignment == null,
4710 .naked => true,
4711 else => false,
4712 };
46904713 },
4691 .stage2_spirv => switch (cc) {
4692 .spirv_device, .spirv_kernel => true,
4693 .spirv_fragment, .spirv_vertex => target.os.tag == .vulkan or target.os.tag == .opengl,
4694 .spirv_task, .spirv_mesh => target.os.tag == .vulkan,
4695 else => false,
4714 .stage2_sparc64 => {
4715 dev.check(.sparc64_backend);
4716 break :ok switch (cc) {
4717 .sparc64_sysv => |opts| opts.incoming_stack_alignment == null,
4718 .naked => true,
4719 else => false,
4720 };
46964721 },
4697 .stage2_loongarch => switch (cc) {
4698 .loongarch64_lp64, .loongarch32_ilp32, .naked => true,
4699 else => false,
4722 .stage2_spirv => {
4723 dev.check(.spirv_backend);
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 };
47004730 },
4701 .zsf_spork8 => switch (cc) {
4702 .spork8, .naked => true,
4703 else => false,
4731 .stage2_loongarch => {
4732 dev.check(.loongarch_backend);
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 };
47044744 },
47054745 };
47064746 if (!backend_ok) return .{ .bad_backend = backend };
47074747 return .ok;
47084748}
47094749
4710pub const CodegenFailError = error{
4750pub const CodegenFailError = Io.Cancelable || error{
47114751 /// Indicates the error message has been already stored at `Zcu.failed_codegen`.
47124752 AlreadyReported,
47134753 OutOfMemory,
......@@ -4999,7 +5039,7 @@ fn addDependencyLoopErrorLine(
49995039 }),
50005040 .struct_defaults => |ty| try eb.printString(
50015041 "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)},
50035043 ),
50045044 } else switch (dep_node.unit.unwrap()) {
50055045 .@"comptime" => unreachable, // cannot be involved in a dependency loop
......@@ -5018,12 +5058,12 @@ fn addDependencyLoopErrorLine(
50185058 }),
50195059 .type_layout => |ty| try eb.printString("{f} depends on type '{f}' {s}", .{
50205060 fmt_source,
5021 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
5061 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip),
50225062 dep_node.reason.type_layout_reason.msg(),
50235063 }),
50245064 .struct_defaults => |ty| try eb.printString(
50255065 "{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) },
50275067 ),
50285068 };
50295069
......@@ -5065,10 +5105,10 @@ fn formatDependencyLoopSourceUnit(data: FormatAnalUnit, w: *Io.Writer) Io.Writer
50655105 else => try w.writeAll("'std.lang' declarations"),
50665106 },
50675107 .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),
50695109 }),
50705110 .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),
50725112 }),
50735113 .func => |func| try w.print("function '{f}'", .{
50745114 ip.getNav(zcu.funcInfo(func).owner_nav).fqn.fmt(ip),
......@@ -5118,7 +5158,7 @@ pub fn populateReferenceTrace(
51185158 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {
51195159 .@"comptime" => "comptime",
51205160 .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),
51225162 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
51235163 .memoized_state => null,
51245164 };
......@@ -5240,7 +5280,7 @@ pub const CodegenTaskPool = struct {
52405280 /// memory on AIR/MIR, we see a limit of around 10 MiB of AIR in-flight.
52415281 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
52455285 available_air_bytes: u32,
52465286
src/Zcu/PerThread.zig+75-24
......@@ -258,6 +258,8 @@ pub fn update(
258258 return;
259259 }
260260
261 try comp.link_queue.enqueueZcu(comp, pt.tid, .files_ready);
262
261263 if (comp.config.incremental) {
262264 const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);
263265 defer update_zir_refs_node.end();
......@@ -859,25 +861,63 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void {
859861 log.debug("tracking failed for %{d}", .{old_inst});
860862 tracked_inst.inst = .lost;
861863 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 });
862865 continue;
863866 };
864 tracked_inst.inst = InternPool.TrackedInst.MaybeLost.ZirIndex.wrap(new_inst);
867 tracked_inst.inst = .wrap(new_inst);
865868
866869 const old_zir = file.prev_zir.?.*;
867 const new_zir = file.zir.?;
868870 const old_tag = old_zir.instructions.items(.tag)[@backingInt(old_inst)];
869871 const old_data = old_zir.instructions.items(.data)[@backingInt(old_inst)];
870872
871 switch (old_tag) {
872 .declaration => {
873 const old_line = old_zir.getDeclaration(old_inst).src_line;
874 const new_line = new_zir.getDeclaration(new_inst).src_line;
875 if (old_line != new_line) {
876 comp.link_prog_node.increaseEstimatedTotalItems(1);
877 try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .debug_update_line_number = tracked_inst_index });
878 }
879 },
880 else => {},
873 const new_zir = file.zir.?;
874 const new_data = new_zir.instructions.items(.data)[@backingInt(new_inst)];
875
876 debug_update_line_number: {
877 const old_line, const new_line = switch (old_tag) {
878 .declaration => .{
879 old_zir.getDeclaration(old_inst).src_line,
880 new_zir.getDeclaration(new_inst).src_line,
881 },
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 } });
881921 }
882922
883923 if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {
......@@ -979,7 +1019,7 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void {
9791019/// Ensures that `zcu.fileRootType` on this `file_index` is populated (not `.none`). This implies
9801020/// that the file's namespace is scanned, discovering declarations.
9811021///
982/// Typical Zig compilations begin by claling this function on the root source file of the standard
1022/// Typical Zig compilations begin by calling this function on the root source file of the standard
9831023/// library, `lib/std/std.zig`. The resulting namespace scan discovers a `comptime` declaration in
9841024/// that file, which is queued for analysis, and everything goes from there.
9851025pub 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
10201060 };
10211061 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 );
10241069 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
10251070 .parent = .none,
10261071 .owner_type = wip.index,
......@@ -1261,6 +1306,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
12611306 // The comptime unit declares on the source of the corresponding `comptime` declaration.
12621307 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);
12641310 var block: Sema.Block = .{
12651311 .parent = null,
12661312 .sema = &sema,
......@@ -1276,7 +1322,10 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
12761322 } },
12771323 .src_base_inst = comptime_unit.zir_index,
12781324 .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),
12801329 }, .no_embedded_nulls),
12811330 };
12821331 defer block.instructions.deinit(gpa);
......@@ -1352,7 +1401,7 @@ pub fn ensureTypeLayoutUpToDate(
13521401 info.deps.clearRetainingCapacity();
13531402 }
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);
13561405 defer unit_tracking.end(zcu);
13571406
13581407 try zcu.analysis_in_progress.put(gpa, anal_unit, reason);
......@@ -1464,7 +1513,7 @@ pub fn ensureStructDefaultsUpToDate(
14641513 info.deps.clearRetainingCapacity();
14651514 }
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);
14681517 defer unit_tracking.end(zcu);
14691518
14701519 try zcu.analysis_in_progress.put(gpa, anal_unit, reason);
......@@ -1673,7 +1722,8 @@ fn analyzeNavVal(
16731722 .inlining = null,
16741723 .comptime_reason = undefined, // set below
16751724 .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,
16771727 };
16781728 defer block.instructions.deinit(gpa);
16791729
......@@ -2042,7 +2092,8 @@ fn analyzeNavType(
20422092 .inlining = null,
20432093 .comptime_reason = undefined, // set below
20442094 .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,
20462097 };
20472098 defer block.instructions.deinit(gpa);
20482099
......@@ -2983,11 +3034,11 @@ pub fn scanNamespace(
29833034
29843035 const tracy_trace = trace(@src());
29853036 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));
29873038 tracy_trace.addTextFmt("type_ip_index={d}", .{namespace.owner_type});
29883039
29893040 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),
29913042 null,
29923043 );
29933044 defer tracked_unit.end(zcu);
......@@ -3309,7 +3360,8 @@ fn analyzeFuncBodyInner(
33093360 .inlining = null,
33103361 .comptime_reason = null,
33113362 .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,
33133365 };
33143366 defer inner_block.instructions.deinit(gpa);
33153367
......@@ -4409,8 +4461,7 @@ pub fn runCodegen(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) Ru
44094461 comp.config.use_llvm,
44104462 )) {
44114463 else => unreachable, // assertion failure
4412 .stage2_llvm,
4413 => {},
4464 .stage2_llvm => {},
44144465 },
44154466 error.Canceled => |e| return e,
44164467 }
src/codegen.zig+7-9
......@@ -196,7 +196,7 @@ pub fn emitFunction(
196196 any_mir: *const AnyMir,
197197 w: *std.Io.Writer,
198198 debug_output: link.File.DebugInfoOutput,
199) (Error || std.Io.Writer.Error)!void {
199) link.EmitError!void {
200200 const zcu = pt.zcu;
201201 const func = zcu.funcInfo(func_index);
202202 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
......@@ -228,7 +228,7 @@ pub fn generateLazyFunction(
228228 atom_id: link.File.AtomId,
229229 w: *std.Io.Writer,
230230 debug_output: link.File.DebugInfoOutput,
231) (Error || std.Io.Writer.Error)!void {
231) link.EmitError!void {
232232 const zcu = pt.zcu;
233233 const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index|
234234 &zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result
......@@ -252,7 +252,7 @@ pub fn generateLazySymbol(
252252 w: *std.Io.Writer,
253253 debug_output: link.File.DebugInfoOutput,
254254 reloc_parent: link.File.RelocInfo.Parent,
255) (Error || std.Io.Writer.Error)!void {
255) link.EmitError!void {
256256 const tracy = trace(@src());
257257 defer tracy.end();
258258 tracy.addTextFmt("{t}, {f}", .{ lazy_sym.kind, Type.fromInterned(lazy_sym.ty).fmt(pt) });
......@@ -314,7 +314,7 @@ pub fn generateSymbol(
314314 val: Value,
315315 w: *std.Io.Writer,
316316 reloc_parent: link.File.RelocInfo.Parent,
317) (Error || std.Io.Writer.Error)!void {
317) link.EmitError!void {
318318 const tracy = trace(@src());
319319 defer tracy.end();
320320
......@@ -665,7 +665,7 @@ fn lowerPtr(
665665 w: *std.Io.Writer,
666666 reloc_parent: link.File.RelocInfo.Parent,
667667 prev_offset: u64,
668) (Error || std.Io.Writer.Error)!void {
668) link.EmitError!void {
669669 const zcu = pt.zcu;
670670 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
671671 const offset: u64 = prev_offset + ptr.byte_offset;
......@@ -723,7 +723,7 @@ fn lowerUavRef(
723723 w: *std.Io.Writer,
724724 reloc_parent: link.File.RelocInfo.Parent,
725725 offset: u64,
726) (Error || std.Io.Writer.Error)!void {
726) link.EmitError!void {
727727 const zcu = pt.zcu;
728728 const ip = &zcu.intern_pool;
729729 const comp = lf.comp;
......@@ -744,7 +744,6 @@ fn lowerUavRef(
744744 .c => unreachable,
745745 .spirv => unreachable,
746746 .wasm => {
747 dev.check(link.File.Tag.wasm.devFeature());
748747 const wasm = lf.cast(.wasm).?;
749748 assert(reloc_parent == .none);
750749 try wasm.addUavReloc(w.end, uav.val, uav.orig_ty, @intCast(offset));
......@@ -781,7 +780,7 @@ fn lowerNavRef(
781780 w: *std.Io.Writer,
782781 reloc_parent: link.File.RelocInfo.Parent,
783782 offset: u64,
784) (Error || std.Io.Writer.Error)!void {
783) link.EmitError!void {
785784 const zcu = pt.zcu;
786785 const ip = &zcu.intern_pool;
787786 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
......@@ -797,7 +796,6 @@ fn lowerNavRef(
797796 .c => unreachable,
798797 .spirv => unreachable,
799798 .wasm => {
800 dev.check(link.File.Tag.wasm.devFeature());
801799 const wasm = lf.cast(.wasm).?;
802800 assert(reloc_parent == .none);
803801 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 {
896896 }
897897}
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 {
900900 const zcu = isel.pt.zcu;
901901 const ip = &zcu.intern_pool;
902902 const gpa = zcu.gpa;
......@@ -8024,7 +8024,7 @@ fn emitLiteral(isel: *Select, bytes: []const u8) !void {
80248024 }
80258025}
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 {
80288028 @branchHint(.cold);
80298029 return isel.pt.zcu.codegenFail(isel.nav_index, format, args);
80308030}
......@@ -10618,7 +10618,7 @@ pub const Value = struct {
1061810618 vi: Value.Index,
1061910619 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 {
1062210622 const live_vi = isel.live_registers.getPtr(mat.ra);
1062310623 assert(live_vi.* == .allocating);
1062410624 var vi = mat.vi;
......@@ -11659,7 +11659,7 @@ fn use(isel: *Select, air_ref: Air.Inst.Ref) !Value.Index {
1165911659 return vi;
1166011660}
1166111661
11662fn fill(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, AlreadyReported }!bool {
11662fn fill(isel: *Select, dst_ra: Register.Alias) codegen.Error!bool {
1166311663 switch (dst_ra) {
1166411664 else => {},
1166511665 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
1169211692 return true;
1169311693}
1169411694
11695fn fillMemory(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, AlreadyReported }!bool {
11695fn fillMemory(isel: *Select, dst_ra: Register.Alias) codegen.Error!bool {
1169611696 const dst_live_vi = isel.live_registers.getPtr(dst_ra);
1169711697 const dst_vi = switch (dst_live_vi.*) {
1169811698 _ => |dst_vi| dst_vi,
src/codegen/c.zig+7-7
......@@ -6,7 +6,7 @@ const log = std.log.scoped(.c);
66const Allocator = mem.Allocator;
77const Writer = std.Io.Writer;
88
9const dev = @import("../dev.zig");
9const codegen = @import("../codegen.zig");
1010const link = @import("../link.zig");
1111const Zcu = @import("../Zcu.zig");
1212const Module = @import("../Module.zig");
......@@ -24,7 +24,7 @@ const BigIntLimb = std.math.big.Limb;
2424const BigInt = std.math.big.int;
2525
2626pub 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)) {
2828 inline false, true => |supports_legalize| &.init(.{
2929 // we don't currently ask zig1 to use safe optimization modes
3030 .expand_bit_cast_safe = supports_legalize,
......@@ -86,7 +86,7 @@ pub const Mir = struct {
8686 }
8787};
8888
89pub const Error = Writer.Error || Allocator.Error || error{AlreadyReported};
89pub const Error = codegen.Error || Writer.Error;
9090
9191pub const CType = @import("c/type.zig").CType;
9292
......@@ -2174,11 +2174,11 @@ pub fn genTagNameFn(
21742174 }
21752175
21762176 if (!zcu.comp.config.root_strip) try w.print("/* @tagName({f}) */\n", .{
2177 loaded_enum.name.fmt(ip),
2177 loaded_enum.fqn.fmt(ip),
21782178 });
21792179 try w.print("static {s} zig_tagName_{f}__{d}({s} tag) {{\n", .{
21802180 slice_const_u8_sentinel_0_type_name,
2181 fmtIdentUnsolo(loaded_enum.name.toSlice(ip)),
2181 fmtIdentUnsolo(loaded_enum.fqn.toSlice(ip)),
21822182 @backingInt(enum_ty.toIntern()),
21832183 enum_type_name,
21842184 });
......@@ -2251,7 +2251,7 @@ pub fn generate(
22512251 func_index: InternPool.Index,
22522252 air: *const Air,
22532253 liveness: *const ?Air.Liveness,
2254) @import("../codegen.zig").Error!Mir {
2254) codegen.Error!Mir {
22552255 const zcu = pt.zcu;
22562256 const gpa = zcu.gpa;
22572257
......@@ -6666,7 +6666,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
66666666 try f.writeCValue(w, local, .other);
66676667 try f.need_tag_name_funcs.put(gpa, enum_ty.toIntern(), {});
66686668 try w.print(" = zig_tagName_{f}__{d}(", .{
6669 fmtIdentUnsolo(enum_ty.containerTypeName(ip).toSlice(ip)),
6669 fmtIdentUnsolo(enum_ty.containerTypeName(ip).fqn.toSlice(ip)),
66706670 @backingInt(enum_ty.toIntern()),
66716671 });
66726672 try f.writeCValue(w, operand, .other);
src/codegen/c/type.zig+3-3
......@@ -1140,17 +1140,17 @@ pub const CType = union(enum) {
11401140 try w.print("_{f}", .{fmtZigType(field_ty, zcu)});
11411141 }
11421142 } else {
1143 const name = ty.containerTypeName(ip).toSlice(ip);
1143 const name = ty.containerTypeName(ip).fqn.toSlice(ip);
11441144 try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});
11451145 },
11461146 .@"opaque" => if (ty.toIntern() == .anyopaque_type) {
11471147 try w.writeAll("anyopaque");
11481148 } else {
1149 const name = ty.containerTypeName(ip).toSlice(ip);
1149 const name = ty.containerTypeName(ip).fqn.toSlice(ip);
11501150 try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});
11511151 },
11521152 .@"union", .@"enum" => {
1153 const name = ty.containerTypeName(ip).toSlice(ip);
1153 const name = ty.containerTypeName(ip).fqn.toSlice(ip);
11541154 try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});
11551155 },
11561156 }
src/codegen/llvm.zig+11-13
......@@ -10,7 +10,6 @@ const build_options = @import("build_options");
1010const Air = @import("../Air.zig");
1111const codegen = @import("../codegen.zig");
1212const Compilation = @import("../Compilation.zig");
13const dev = @import("../dev.zig");
1413const InternPool = @import("../InternPool.zig");
1514const link = @import("../link.zig");
1615const Module = @import("../Module.zig");
......@@ -155,12 +154,11 @@ pub const Object = struct {
155154 /// Values for `@llvm.used`.
156155 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
160159 const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type);
161160
162161 pub fn create(arena: Allocator, zcu: *Zcu) !Ptr {
163 dev.check(.llvm_backend);
164162 const comp = zcu.comp;
165163 const gpa = comp.gpa;
166164 const target = zcu.getTarget();
......@@ -348,7 +346,7 @@ pub const Object = struct {
348346 lto: std.zig.LtoMode,
349347 };
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 {
352350 const zcu = o.zcu;
353351 const comp = zcu.comp;
354352 const io = comp.io;
......@@ -1141,7 +1139,7 @@ pub const Object = struct {
11411139 }
11421140 }
11431141
1144 fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void {
1142 fn flushTypePool(o: *Object, pt: Zcu.PerThread) link.Error!void {
11451143 try o.type_pool.flushPending(pt, .{ .llvm = o });
11461144 }
11471145
......@@ -1304,7 +1302,7 @@ pub const Object = struct {
13041302 }, &o.builder);
13051303 }
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 {
13081306 _ = o.type_map.remove(ty);
13091307 try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success);
13101308 if (o.named_enum_map.get(ty)) |llvm_function| {
......@@ -1431,7 +1429,7 @@ pub const Object = struct {
14311429
14321430 pub fn getDebugType(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Metadata {
14331431 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);
14351433 return o.debug_types.items[@backingInt(index)];
14361434 }
14371435
......@@ -2893,7 +2891,7 @@ pub const Object = struct {
28932891 }
28942892 }
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)));
28972895 try o.type_map.put(o.gpa, t.toIntern(), ty);
28982896
28992897 o.builder.namedTypeSetBody(
......@@ -2983,7 +2981,7 @@ pub const Object = struct {
29832981 };
29842982
29852983 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)));
29872985 try o.type_map.put(o.gpa, t.toIntern(), ty);
29882986
29892987 o.builder.namedTypeSetBody(
......@@ -3011,7 +3009,7 @@ pub const Object = struct {
30113009 llvm_fields_len += 1;
30123010 }
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)));
30153013 try o.type_map.put(o.gpa, t.toIntern(), ty);
30163014
30173015 o.builder.namedTypeSetBody(
......@@ -4026,7 +4024,7 @@ pub const Object = struct {
40264024 // Dummy function type; `updateEnumTagNameFunction` will replace it with the correct type.
40274025 // TODO: change the builder API so we don't need to do this.
40284026 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)}),
40304028 toLlvmAddressSpace(.generic, zcu.getTarget()),
40314029 );
40324030 gop.value_ptr.* = llvm_function;
......@@ -4108,7 +4106,7 @@ pub const Object = struct {
41084106 }
41094107
41104108 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);
41124110 return o.lazy_abi_aligns.items[@backingInt(index)];
41134111 }
41144112
......@@ -4123,7 +4121,7 @@ pub const Object = struct {
41234121 // Dummy function type; `updateIsNamedEnumValue` will replace it with the correct type.
41244122 // TODO: change the builder API so we don't need to do this.
41254123 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)}),
41274125 toLlvmAddressSpace(.generic, zcu.getTarget()),
41284126 );
41294127 gop.value_ptr.* = llvm_function;
src/codegen/loongarch/Select.zig+8-8
......@@ -1020,7 +1020,7 @@ pub const Value = struct {
10201020 /// Defines a value with a location.
10211021 /// Returned location must be free-ed by caller.
10221022 /// 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 {
10241024 try vi.collectDefs(isel);
10251025 return vi.takeLocationMarkWritten(isel);
10261026 }
......@@ -2046,7 +2046,7 @@ pub const Value = struct {
20462046 if (!std.debug.runtime_safety) assert(@sizeOf(Mat) <= 32);
20472047 }
20482048
2049 const Error = error{ OutOfMemory, AlreadyReported };
2049 const Error = codegen.Error;
20502050
20512051 pub fn ra(mat: Value.Mat) Register.Alias {
20522052 return mat.location.register;
......@@ -2296,13 +2296,13 @@ pub const Value = struct {
22962296 };
22972297};
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 {
23002300 @branchHint(.cold);
23012301 wip_mir_log.debug("codegen error: " ++ format, args);
23022302 return isel.pt.zcu.codegenFail(isel.nav_index, format, args);
23032303}
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 {
23062306 @branchHint(.cold);
23072307 if (debug_trap_unimplemented_code) {
23082308 const gpa = isel.pt.zcu.gpa;
......@@ -2963,7 +2963,7 @@ pub fn verify(isel: *Select, check_values: bool) void {
29632963 }
29642964}
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 {
29672967 const zcu = isel.pt.zcu;
29682968 const ip = &zcu.intern_pool;
29692969 const gpa = zcu.gpa;
......@@ -5341,7 +5341,7 @@ fn forgetReg(isel: *Select, dst_reg: Register) error{ OutOfMemory, AlreadyReport
53415341
53425342/// Frees a register by moving it to another place.
53435343/// 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 {
53455345 if (!isRegisterAllocatable(dst_reg)) return false;
53465346 const dst_live_vi = isel.live_registers.getPtr(dst_reg);
53475347 const dst_vi = switch (dst_live_vi.*) {
......@@ -5377,7 +5377,7 @@ fn fillReg(isel: *Select, dst_reg: Register) error{ OutOfMemory, AlreadyReported
53775377/// Frees a set of register. If locked is true, these registers are then locked.
53785378/// Requires all registers to be unlocked.
53795379/// 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 {
53815381 tracking_log.debug("batch fill: {f}", .{fmtRegisterSet(regs)});
53825382 // lock free registers
53835383 var regs_it = regs.iterator();
......@@ -5419,7 +5419,7 @@ fn fillRegsBatch(isel: *Select, regs: RegisterSet, locking: bool) error{ OutOfMe
54195419
54205420/// Frees a register by moving it to stack.
54215421/// 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 {
54235423 if (!isRegisterAllocatable(dst_reg)) return false;
54245424 const dst_live_vi = isel.live_registers.getPtr(dst_reg);
54255425 const dst_vi = switch (dst_live_vi.*) {
src/codegen/riscv64/CodeGen.zig+3-3
......@@ -856,7 +856,7 @@ pub fn generateLazy(
856856 atom_index: link.File.AtomId,
857857 w: *std.Io.Writer,
858858 debug_output: link.File.DebugInfoOutput,
859) (codegen.Error || std.Io.Writer.Error)!void {
859) link.EmitError!void {
860860 _ = atom_index;
861861 const comp = bin_file.comp;
862862 const gpa = comp.gpa;
......@@ -8349,7 +8349,7 @@ fn wantSafety(func: *Func) bool {
83498349 };
83508350}
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 {
83538353 @branchHint(.cold);
83548354 const zcu = func.pt.zcu;
83558355 switch (func.owner) {
......@@ -8359,7 +8359,7 @@ fn fail(func: *const Func, comptime format: []const u8, args: anytype) error{ Ou
83598359 return error.AlreadyReported;
83608360}
83618361
8362fn failMsg(func: *const Func, msg: *ErrorMsg) error{ OutOfMemory, AlreadyReported } {
8362fn failMsg(func: *const Func, msg: *ErrorMsg) codegen.Error {
83638363 @branchHint(.cold);
83648364 const zcu = func.pt.zcu;
83658365 switch (func.owner) {
src/codegen/riscv64/Emit.zig+9-9
......@@ -13,7 +13,7 @@ prev_di_pc: usize,
1313code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,
1414relocs: std.ArrayList(Reloc) = .empty,
1515
16pub const Error = Lower.Error || std.Io.Writer.Error || error{
16pub const Error = Lower.Error || link.EmitError || error{
1717 EmitFail,
1818};
1919
......@@ -118,14 +118,14 @@ pub fn emitMir(emit: *Emit) Error!void {
118118 else => unreachable,
119119 .pseudo_dbg_prologue_end => {
120120 switch (emit.debug_output) {
121 .dwarf => |dw| {
121 inline .dwarf, .dwarf2 => |dw| {
122122 try dw.setPrologueEnd();
123123 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
124124 emit.prev_di_line, emit.prev_di_column,
125125 });
126126 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
127127 },
128 .none => {},
128 .eh_frame, .none => {},
129129 }
130130 },
131131 .pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine(
......@@ -134,14 +134,14 @@ pub fn emitMir(emit: *Emit) Error!void {
134134 ),
135135 .pseudo_dbg_epilogue_begin => {
136136 switch (emit.debug_output) {
137 .dwarf => |dw| {
137 inline .dwarf, .dwarf2 => |dw| {
138138 try dw.setEpilogueBegin();
139139 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
140140 emit.prev_di_line, emit.prev_di_column,
141141 });
142142 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
143143 },
144 .none => {},
144 .eh_frame, .none => {},
145145 }
146146 },
147147 .pseudo_dead => {},
......@@ -190,15 +190,14 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
190190 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
191191 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });
192192 switch (emit.debug_output) {
193 .dwarf => |dw| {
193 inline .dwarf, .dwarf2 => |dw| {
194194 if (column != emit.prev_di_column) try dw.setColumn(column);
195 if (delta_line == 0) return; // TODO: fix these edge cases.
196 try dw.advancePCAndLine(delta_line, delta_pc);
195 try dw.advanceLineAndPc(delta_line, delta_pc, false);
197196 emit.prev_di_line = line;
198197 emit.prev_di_column = column;
199198 emit.prev_di_pc = emit.w.end;
200199 },
201 .none => {},
200 .eh_frame, .none => {},
202201 }
203202}
204203
......@@ -209,6 +208,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {
209208 };
210209}
211210
211const codegen = @import("../../codegen.zig");
212212const link = @import("../../link.zig");
213213const log = std.log.scoped(.emit);
214214const mem = std.mem;
src/codegen/riscv64/Mir.zig+1-1
......@@ -111,7 +111,7 @@ pub fn emit(
111111 atom_index: link.File.AtomId,
112112 w: *std.Io.Writer,
113113 debug_output: link.File.DebugInfoOutput,
114) (codegen.Error || std.Io.Writer.Error)!void {
114) link.EmitError!void {
115115 _ = atom_index;
116116 const zcu = pt.zcu;
117117 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)
34503450 }
34513451}
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 {
34543454 @branchHint(.cold);
34553455 const zcu = self.pt.zcu;
34563456 const func = zcu.funcInfo(self.func_index);
......@@ -3458,7 +3458,7 @@ fn fail(self: *Self, comptime format: []const u8, args: anytype) error{ OutOfMem
34583458 return zcu.codegenFailMsg(func.owner_nav, msg);
34593459}
34603460
3461fn failMsg(self: *Self, msg: *ErrorMsg) error{ OutOfMemory, AlreadyReported } {
3461fn failMsg(self: *Self, msg: *ErrorMsg) codegen.Error {
34623462 @branchHint(.cold);
34633463 const zcu = self.pt.zcu;
34643464 const func = zcu.funcInfo(self.func_index);
src/codegen/sparc64/Emit.zig+9-9
......@@ -4,6 +4,7 @@
44const std = @import("std");
55const Endian = std.lang.Endian;
66const assert = std.debug.assert;
7const codegen = @import("../../codegen.zig");
78const link = @import("../../link.zig");
89const Zcu = @import("../../Zcu.zig");
910const ErrorMsg = Zcu.ErrorMsg;
......@@ -40,8 +41,7 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayList(M
4041/// instruction
4142code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,
4243
43const InnerError = std.Io.Writer.Error || error{
44 OutOfMemory,
44const InnerError = link.EmitError || error{
4545 EmitFail,
4646};
4747
......@@ -175,21 +175,21 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
175175
176176fn mirDebugPrologueEnd(emit: *Emit) !void {
177177 switch (emit.debug_output) {
178 .dwarf => |dbg_out| {
178 inline .dwarf, .dwarf2 => |dbg_out| {
179179 try dbg_out.setPrologueEnd();
180180 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
181181 },
182 .none => {},
182 .eh_frame, .none => {},
183183 }
184184}
185185
186186fn mirDebugEpilogueBegin(emit: *Emit) !void {
187187 switch (emit.debug_output) {
188 .dwarf => |dbg_out| {
188 inline .dwarf, .dwarf2 => |dbg_out| {
189189 try dbg_out.setEpilogueBegin();
190190 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
191191 },
192 .none => {},
192 .eh_frame, .none => {},
193193 }
194194}
195195
......@@ -496,13 +496,13 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {
496496 const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));
497497 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
498498 switch (emit.debug_output) {
499 .dwarf => |dbg_out| {
500 try dbg_out.advancePCAndLine(delta_line, delta_pc);
499 inline .dwarf, .dwarf2 => |dbg_out| {
500 try dbg_out.advanceLineAndPc(delta_line, delta_pc, false);
501501 emit.prev_di_line = line;
502502 emit.prev_di_column = column;
503503 emit.prev_di_pc = emit.w.end;
504504 },
505 else => {},
505 .eh_frame, .none => {},
506506 }
507507}
508508
src/codegen/sparc64/Mir.zig+1-1
......@@ -382,7 +382,7 @@ pub fn emit(
382382 atom_index: link.File.AtomId,
383383 w: *std.Io.Writer,
384384 debug_output: link.File.DebugInfoOutput,
385) (codegen.Error || std.Io.Writer.Error)!void {
385) link.EmitError!void {
386386 _ = atom_index;
387387 const zcu = pt.zcu;
388388 const func = zcu.funcInfo(func_index);
src/codegen/spirv/CodeGen.zig+3-9
......@@ -240,10 +240,7 @@ pub fn generate(
240240 };
241241 defer cg.deinit();
242242
243 cg.genNav(true) catch |err| switch (err) {
244 error.AlreadyReported => return error.AlreadyReported,
245 error.OutOfMemory => return error.OutOfMemory,
246 };
243 try cg.genNav(true);
247244
248245 return cg.serializeToMir(gpa);
249246}
......@@ -270,10 +267,7 @@ pub fn generateNav(
270267 };
271268 defer cg.deinit();
272269
273 cg.genNav(false) catch |err| switch (err) {
274 error.AlreadyReported => return error.AlreadyReported,
275 error.OutOfMemory => return error.OutOfMemory,
276 };
270 try cg.genNav(false);
277271
278272 return cg.serializeToMir(gpa);
279273}
......@@ -854,7 +848,7 @@ pub fn storageClass(cg: *const CodeGen, as: std.lang.AddressSpace) spec.StorageC
854848 };
855849}
856850
857const Error = error{ AlreadyReported, OutOfMemory };
851const Error = codegen.Error;
858852
859853pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
860854 const gpa = cg.gpa;
src/codegen/spork8/CodeGen.zig+15-27
......@@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator;
44const assert = std.debug.assert;
55
66const CodeGen = @This();
7const codegen = @import("../../codegen.zig");
78const link = @import("../../link.zig");
89const Spork8 = link.File.Spork8;
910const Zcu = @import("../../Zcu.zig");
......@@ -133,37 +134,20 @@ pub fn generate(
133134 _ = bin_file;
134135 const zcu = pt.zcu;
135136 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 = .{
139140 .gpa = gpa,
140141 .pt = pt,
141142 .air = air.*,
142143 .liveness = liveness.*.?,
143 .owner_nav = cg.owner_nav,
144 .owner_nav = func.owner_nav,
144145 .func_index = func_index,
145146 .mir_instructions = .empty,
146147 .mir_extra = .empty,
147148 };
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 {
167151 // Generate MIR for function body
168152 try cg.genBody(cg.air.getMainBody());
169153
......@@ -175,7 +159,11 @@ fn generateInner(cg: *CodeGen) InnerError!Mir {
175159 };
176160}
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 {
179167 const zcu = cg.pt.zcu;
180168 const ip = &zcu.intern_pool;
181169
......@@ -185,7 +173,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
185173 }
186174}
187175
188fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
176fn genInst(cg: *CodeGen, inst: Air.Inst.Index) codegen.Error!void {
189177 const air_tags = cg.air.instructions.items(.tag);
190178 return switch (air_tags[@backingInt(inst)]) {
191179 .inferred_alloc, .inferred_alloc_comptime => unreachable,
......@@ -444,17 +432,17 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
444432 };
445433}
446434
447fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
435fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) codegen.Error!void {
448436 _ = cg;
449437 _ = inst;
450438}
451439
452fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
440fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) codegen.Error!void {
453441 _ = inst;
454442 try cg.addTag(.halt);
455443}
456444
457fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
445fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) codegen.Error!void {
458446 const unwrapped_asm = cg.air.unwrapAsm(inst);
459447 const outputs = unwrapped_asm.outputs;
460448 // const inputs = unwrapped_asm.inputs;
......@@ -538,7 +526,7 @@ pub fn addTagImm8(cg: *CodeGen, tag: Mir.Inst.Tag, imm8: u8) error{OutOfMemory}!
538526 try cg.addInst(.{ .tag = tag, .data = .{ .imm8 = imm8 } });
539527}
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 {
542530 const zcu = cg.pt.zcu;
543531 const func = zcu.funcInfo(cg.func_index);
544532 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);
332332
333333const bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
334334
335const InnerError = error{
336 OutOfMemory,
335const InnerError = Error || error{
337336 /// An error occurred when trying to lower AIR to MIR.
338337 AlreadyReported,
339338 /// Compiler implementation could not handle a large integer.
......@@ -361,7 +360,7 @@ pub fn deinit(cg: *CodeGen) void {
361360 cg.* = undefined;
362361}
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 {
365364 const zcu = cg.pt.zcu;
366365 const func = zcu.funcInfo(cg.func_index);
367366 return zcu.codegenFail(func.owner_nav, fmt, args);
......@@ -760,11 +759,7 @@ fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
760759 return .{ .local = .{ .value = initial_index, .references = 1 } };
761760}
762761
763pub const Error = error{
764 OutOfMemory,
765 /// Indicates the error is already stored in Zcu `failed_codegen`.
766 AlreadyReported,
767};
762pub const Error = codegen.Error;
768763
769764pub fn generate(
770765 bin_file: *link.File,
src/codegen/x86_64/CodeGen.zig+20-25
......@@ -1072,20 +1072,12 @@ pub fn generate(
10721072 );
10731073 }
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) {
10761076 error.OutOfRegisters => return function.fail("ran out of registers (Zig compiler bug)", .{}),
10771077 else => |e| return e,
10781078 };
10791079
1080 // Drop them off at the rbrace.
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 });
1080 if (!mod.strip) _ = try function.asmPseudo(.pseudo_dbg_end_none);
10891081
10901082 try function.mir_extra.shrinkToLen(gpa);
10911083 try function.mir_string_bytes.shrinkToLen(gpa);
......@@ -1120,7 +1112,7 @@ pub fn generateLazy(
11201112 atom_id: link.File.AtomId,
11211113 w: *std.Io.Writer,
11221114 debug_output: link.File.DebugInfoOutput,
1123) codegen.Error!void {
1115) link.EmitError!void {
11241116 const gpa = pt.zcu.gpa;
11251117 // This function is for generating global code, so we use the root module.
11261118 const mod = pt.zcu.comp.root_mod;
......@@ -1228,18 +1220,18 @@ fn formatWipMir(data: FormatWipMirData, w: *Writer) Writer.Error!void {
12281220 switch (mir_inst.ops) {
12291221 else => unreachable,
12301222 .pseudo_dbg_prologue_end_none,
1231 .pseudo_dbg_epilogue_begin_none,
12321223 .pseudo_dbg_enter_block_none,
12331224 .pseudo_dbg_leave_block_none,
1225 .pseudo_dbg_end_none,
12341226 .pseudo_dbg_arg_none,
12351227 .pseudo_dbg_var_args_none,
12361228 .pseudo_dbg_var_none,
12371229 .pseudo_dead_none,
12381230 => {},
1239 .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column => try w.print(
1240 " {[line]d}, {[column]d}",
1241 mir_inst.data.line_column,
1242 ),
1231 .pseudo_dbg_line_stmt_line_column,
1232 .pseudo_dbg_line_line_column,
1233 .pseudo_dbg_epilogue_begin_line_column,
1234 => try w.print(" {[line]d}, {[column]d}", mir_inst.data.line_column),
12431235 .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try w.print(" {f}", .{
12441236 ip.getNav(ip.indexToKey(mir_inst.data.ip_index).func.owner_nav).name.fmt(ip),
12451237 }),
......@@ -2069,7 +2061,7 @@ fn gen(
20692061 self: *CodeGen,
20702062 zir: *const std.zig.Zir,
20712063 func_zir_inst: std.zig.Zir.Inst.Index,
2072 comptime_args: InternPool.Index.Slice,
2064 func: *const InternPool.Key.Func,
20732065 air_arg_count: u32,
20742066) InnerError!void {
20752067 const pt = self.pt;
......@@ -2150,7 +2142,7 @@ fn gen(
21502142
21512143 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
21552147 const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: {
21562148 var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1);
......@@ -2165,7 +2157,14 @@ fn gen(
21652157 }
21662158 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 });
21692168 const backpatch_stack_dealloc = try self.asmPlaceholder();
21702169 const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();
21712170 try self.asmRegister(.{ ._, .pop }, .rbp);
......@@ -2283,11 +2282,7 @@ fn gen(
22832282 .data = .{ .reg_list = frame_layout.save_reg_list },
22842283 });
22852284 }
2286 } else {
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 }
2285 } else try self.genMainBody(zir, func_zir_inst, func.comptime_args, air_arg_count);
22912286}
22922287
22932288fn genMainBody(
......@@ -182177,7 +182172,7 @@ fn resolveCallingConventionValues(
182177182172 return result;
182178182173}
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 {
182181182176 @branchHint(.cold);
182182182177 const zcu = cg.pt.zcu;
182183182178 return switch (cg.owner) {
src/codegen/x86_64/Emit.zig+209-192
......@@ -16,10 +16,8 @@ code_offset_mapping: std.ArrayList(u32),
1616relocs: std.ArrayList(Reloc),
1717table_relocs: std.ArrayList(TableReloc),
1818
19pub const Error = Lower.Error || error{
20 AlreadyReported,
19pub const Error = Lower.Error || codegen.Error || std.Io.Writer.Error || error{
2120 EmitFail,
22 NotFile,
2321} || std.posix.MMapError || std.posix.MRemapError || link.File.UpdateDebugInfoError;
2422
2523pub fn emitMir(emit: *Emit) Error!void {
......@@ -38,7 +36,7 @@ pub fn emitMir(emit: *Emit) Error!void {
3836 if (lowered_inst.prefix == .directive) {
3937 const start_offset: u32 = @intCast(emit.w.end);
4038 switch (emit.debug_output) {
41 .dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) {
39 inline .dwarf, .dwarf2, .eh_frame => |dwarf| switch (lowered_inst.encoding.mnemonic) {
4240 .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{
4341 .reg = lowered_inst.ops[0].reg.dwarfNum(),
4442 .off = lowered_inst.ops[1].imm.signed,
......@@ -460,204 +458,222 @@ pub fn emitMir(emit: *Emit) Error!void {
460458
461459 if (lowered.insts.len == 0) {
462460 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) {
464463 else => unreachable,
465 .pseudo => switch (mir_inst.ops) {
466 else => unreachable,
467 .pseudo_dbg_prologue_end_none => switch (emit.debug_output) {
468 .dwarf => |dwarf| try dwarf.setPrologueEnd(),
469 .none => {},
464 .pseudo_dbg_prologue_end_none => switch (emit.debug_output) {
465 inline .dwarf, .dwarf2 => |dwarf| {
466 try dwarf.setPrologueEnd();
467 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
468 emit.prev_di_loc.line, emit.prev_di_loc.column,
469 });
470470 },
471 .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePCAndLine(.{
472 .line = mir_inst.data.line_column.line,
473 .column = mir_inst.data.line_column.column,
474 .is_stmt = true,
475 }),
476 .pseudo_dbg_line_line_column => try emit.dbgAdvancePCAndLine(.{
477 .line = mir_inst.data.line_column.line,
478 .column = mir_inst.data.line_column.column,
479 .is_stmt = false,
480 }),
481 .pseudo_dbg_epilogue_begin_none => switch (emit.debug_output) {
482 .dwarf => |dwarf| {
471 .eh_frame, .none => {},
472 },
473 .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvanceLineAndPc(.{
474 .line = mir_inst.data.line_column.line,
475 .column = mir_inst.data.line_column.column,
476 .is_stmt = true,
477 }),
478 .pseudo_dbg_line_line_column => try emit.dbgAdvanceLineAndPc(.{
479 .line = mir_inst.data.line_column.line,
480 .column = mir_inst.data.line_column.column,
481 .is_stmt = false,
482 }),
483 .pseudo_dbg_epilogue_begin_line_column => {
484 switch (emit.debug_output) {
485 inline .dwarf, .dwarf2 => |dwarf| {
483486 try dwarf.setEpilogueBegin();
484487 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
485488 emit.prev_di_loc.line, emit.prev_di_loc.column,
486489 });
487 try emit.dbgAdvancePCAndLine(emit.prev_di_loc);
488490 },
489 .none => {},
490 },
491 .pseudo_dbg_enter_block_none => switch (emit.debug_output) {
492 .dwarf => |dwarf| {
493 log.debug("mirDbgEnterBlock (line={d}, col={d})", .{
494 emit.prev_di_loc.line, emit.prev_di_loc.column,
495 });
496 try dwarf.enterBlock(emit.w.end);
497 },
498 .none => {},
491 .eh_frame, .none => {},
492 }
493 try emit.dbgAdvanceLineAndPc(.{
494 .line = mir_inst.data.line_column.line,
495 .column = mir_inst.data.line_column.column,
496 });
497 },
498 .pseudo_dbg_enter_block_none => switch (emit.debug_output) {
499 inline .dwarf, .dwarf2 => |dwarf| {
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);
499504 },
500 .pseudo_dbg_leave_block_none => switch (emit.debug_output) {
501 .dwarf => |dwarf| {
502 log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{
503 emit.prev_di_loc.line, emit.prev_di_loc.column,
504 });
505 try dwarf.leaveBlock(emit.w.end);
506 },
507 .none => {},
505 .eh_frame, .none => {},
506 },
507 .pseudo_dbg_leave_block_none => switch (emit.debug_output) {
508 inline .dwarf, .dwarf2 => |dwarf| {
509 log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{
510 emit.prev_di_loc.line, emit.prev_di_loc.column,
511 });
512 try dwarf.leaveBlock(emit.w.end);
508513 },
509 .pseudo_dbg_enter_inline_func => switch (emit.debug_output) {
510 .dwarf => |dwarf| {
511 log.debug("mirDbgEnterInline (line={d}, col={d})", .{
512 emit.prev_di_loc.line, emit.prev_di_loc.column,
513 });
514 try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column);
515 },
516 .none => {},
514 .eh_frame, .none => {},
515 },
516 .pseudo_dbg_enter_inline_func => switch (emit.debug_output) {
517 inline .dwarf, .dwarf2 => |dwarf| {
518 log.debug("mirDbgEnterInline (line={d}, col={d})", .{
519 emit.prev_di_loc.line, emit.prev_di_loc.column,
520 });
521 try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column);
517522 },
518 .pseudo_dbg_leave_inline_func => switch (emit.debug_output) {
519 .dwarf => |dwarf| {
520 log.debug("mirDbgLeaveInline (line={d}, col={d})", .{
521 emit.prev_di_loc.line, emit.prev_di_loc.column,
522 });
523 try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end);
524 },
525 .none => {},
523 .eh_frame, .none => {},
524 },
525 .pseudo_dbg_leave_inline_func => switch (emit.debug_output) {
526 inline .dwarf, .dwarf2 => |dwarf| {
527 log.debug("mirDbgLeaveInline (line={d}, col={d})", .{
528 emit.prev_di_loc.line, emit.prev_di_loc.column,
529 });
530 try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end);
526531 },
527 .pseudo_dbg_arg_none,
528 .pseudo_dbg_arg_i_s,
529 .pseudo_dbg_arg_i_u,
530 .pseudo_dbg_arg_i_64,
531 .pseudo_dbg_arg_ro,
532 .pseudo_dbg_arg_fa,
533 .pseudo_dbg_arg_m,
534 .pseudo_dbg_var_none,
535 .pseudo_dbg_var_i_s,
536 .pseudo_dbg_var_i_u,
537 .pseudo_dbg_var_i_64,
538 .pseudo_dbg_var_ro,
539 .pseudo_dbg_var_fa,
540 .pseudo_dbg_var_m,
541 => switch (emit.debug_output) {
542 .dwarf => |dwarf| {
543 var loc_buf: [2]link.File.Dwarf.Loc = undefined;
544 const loc: link.File.Dwarf.Loc = loc: switch (mir_inst.ops) {
532 .eh_frame, .none => {},
533 },
534 .pseudo_dbg_end_none => try emit.dbgAdvanceLineAndPc(.{
535 .line = emit.prev_di_loc.line,
536 .column = emit.prev_di_loc.column,
537 .end = true,
538 }),
539 .pseudo_dbg_arg_none,
540 .pseudo_dbg_arg_i_s,
541 .pseudo_dbg_arg_i_u,
542 .pseudo_dbg_arg_i_64,
543 .pseudo_dbg_arg_ro,
544 .pseudo_dbg_arg_fa,
545 .pseudo_dbg_arg_m,
546 .pseudo_dbg_var_none,
547 .pseudo_dbg_var_i_s,
548 .pseudo_dbg_var_i_u,
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) {
545629 else => unreachable,
546 .pseudo_dbg_arg_none, .pseudo_dbg_var_none => .empty,
630 .pseudo_dbg_arg_none,
547631 .pseudo_dbg_arg_i_s,
548632 .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,
549640 .pseudo_dbg_var_i_s,
550641 .pseudo_dbg_var_i_u,
551 => .{ .stack_value = stack_value: {
552 loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.i.i)) {
553 .signed => |s| .{ .consts = s },
554 .unsigned => |u| .{ .constu = u },
555 };
556 break :stack_value &loc_buf[0];
557 } },
558 .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => .{ .stack_value = stack_value: {
559 loc_buf[0] = .{ .constu = mir_inst.data.i64 };
560 break :stack_value &loc_buf[0];
561 } },
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,
642 .pseudo_dbg_var_i_64,
643 .pseudo_dbg_var_ro,
644 .pseudo_dbg_var_fa,
645 .pseudo_dbg_var_m,
646 .pseudo_dbg_var_val,
647 => .local_var,
648 },
649 local.name.toSlice(&emit.lower.mir),
650 .fromInterned(local.type),
651 loc,
652 );
654653 },
655 .pseudo_dbg_var_args_none => switch (emit.debug_output) {
656 .dwarf => |dwarf| try dwarf.genVarArgsDebugInfo(),
657 .none => {},
654 .eh_frame, .none => local_index += 1,
655 },
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 );
658669 },
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 => {},
660675 },
676 .pseudo_dead_none => {},
661677 }
662678 }
663679 }
......@@ -971,22 +987,23 @@ const TableReloc = struct {
971987const Loc = struct {
972988 line: u32,
973989 column: u32,
974 is_stmt: bool,
990 is_stmt: ?bool = null,
991 end: bool = false,
975992};
976993
977fn dbgAdvancePCAndLine(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 });
994fn dbgAdvanceLineAndPc(emit: *Emit, loc: Loc) Error!void {
981995 switch (emit.debug_output) {
982 .dwarf => |dwarf| {
983 if (loc.is_stmt != emit.prev_di_loc.is_stmt) try dwarf.negateStmt();
996 inline .dwarf, .dwarf2 => |dwarf| {
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();
9841001 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);
9861003 emit.prev_di_loc = loc;
9871004 emit.prev_di_pc = emit.w.end;
9881005 },
989 .none => {},
1006 .eh_frame, .none => {},
9901007 }
9911008}
9921009
src/codegen/x86_64/Lower.zig+2-1
......@@ -314,11 +314,12 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
314314 .pseudo_dbg_prologue_end_none,
315315 .pseudo_dbg_line_stmt_line_column,
316316 .pseudo_dbg_line_line_column,
317 .pseudo_dbg_epilogue_begin_none,
317 .pseudo_dbg_epilogue_begin_line_column,
318318 .pseudo_dbg_enter_block_none,
319319 .pseudo_dbg_leave_block_none,
320320 .pseudo_dbg_enter_inline_func,
321321 .pseudo_dbg_leave_inline_func,
322 .pseudo_dbg_end_none,
322323 .pseudo_dbg_arg_none,
323324 .pseudo_dbg_arg_i_s,
324325 .pseudo_dbg_arg_i_u,
src/codegen/x86_64/Mir.zig+27-21
......@@ -1519,30 +1519,33 @@ pub const Inst = struct {
15191519 /// Uses `bytes` payload.
15201520 pseudo_cfi_escape_bytes,
15211521
1522 /// End of prologue
1522 /// End of prologue.
15231523 /// Uses `none` payload.
15241524 pseudo_dbg_prologue_end_none,
1525 /// Update debug line with is_stmt register set
1525 /// Update debug line with is_stmt register set.
15261526 /// Uses `line_column` payload.
15271527 pseudo_dbg_line_stmt_line_column,
1528 /// Update debug line with is_stmt register clear
1528 /// Update debug line with is_stmt register clear.
15291529 /// Uses `line_column` payload.
15301530 pseudo_dbg_line_line_column,
1531 /// Start of epilogue
1532 /// Uses `none` payload.
1533 pseudo_dbg_epilogue_begin_none,
1534 /// Start of lexical block
1531 /// Start of epilogue.
1532 /// Uses `line_column` payload.
1533 pseudo_dbg_epilogue_begin_line_column,
1534 /// Start of lexical block.
15351535 /// Uses `none` payload.
15361536 pseudo_dbg_enter_block_none,
1537 /// End of lexical block
1537 /// End of lexical block.
15381538 /// Uses `none` payload.
15391539 pseudo_dbg_leave_block_none,
1540 /// Start of inline function
1540 /// Start of inline function.
15411541 /// Uses `ip_index` payload.
15421542 pseudo_dbg_enter_inline_func,
1543 /// End of inline function
1543 /// End of inline function.
15441544 /// Uses `ip_index` payload.
15451545 pseudo_dbg_leave_inline_func,
1546 /// End of function.
1547 /// Uses `none` payload.
1548 pseudo_dbg_end_none,
15461549 /// Local argument.
15471550 /// Uses `none` payload.
15481551 pseudo_dbg_arg_none,
......@@ -1978,7 +1981,7 @@ pub fn emit(
19781981 atom_id: link.File.AtomId,
19791982 w: *std.Io.Writer,
19801983 debug_output: link.File.DebugInfoOutput,
1981) codegen.Error!void {
1984) link.EmitError!void {
19821985 const zcu = pt.zcu;
19831986 const comp = zcu.comp;
19841987 const gpa = comp.gpa;
......@@ -1986,7 +1989,7 @@ pub fn emit(
19861989 const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?;
19871990 const nav = func.owner_nav;
19881991 const mod = zcu.navFileScope(nav).mod.?;
1989 var e: Emit = .{
1992 var em: Emit = .{
19901993 .lower = .{
19911994 .target = &mod.resolved_target.result,
19921995 .allocator = gpa,
......@@ -2006,7 +2009,8 @@ pub fn emit(
20062009 .column = func.lbrace_column,
20072010 .is_stmt = switch (debug_output) {
20082011 .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,
20102014 },
20112015 },
20122016 .prev_di_pc = 0,
......@@ -2015,11 +2019,12 @@ pub fn emit(
20152019 .relocs = .empty,
20162020 .table_relocs = .empty,
20172021 };
2018 defer e.deinit();
2019 e.emitMir() catch |err| switch (err) {
2020 error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, e.lower.err_msg.?),
2022 defer em.deinit();
2023 em.emitMir() catch |err| switch (err) {
2024 error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, em.lower.err_msg.?),
20212025 error.InvalidInstruction, error.CannotEncode => return zcu.codegenFail(nav, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),
20222026 else => return zcu.codegenFail(nav, "emit MIR failed: {s}", .{@errorName(err)}),
2027 error.AlreadyReported, error.Canceled, error.WriteFailed => |e| return e,
20232028 };
20242029}
20252030
......@@ -2031,12 +2036,12 @@ pub fn emitLazy(
20312036 atom_id: link.File.AtomId,
20322037 w: *std.Io.Writer,
20332038 debug_output: link.File.DebugInfoOutput,
2034) codegen.Error!void {
2039) link.EmitError!void {
20352040 const zcu = pt.zcu;
20362041 const comp = zcu.comp;
20372042 const gpa = comp.gpa;
20382043 const mod = comp.root_mod;
2039 var e: Emit = .{
2044 var em: Emit = .{
20402045 .lower = .{
20412046 .target = &mod.resolved_target.result,
20422047 .allocator = gpa,
......@@ -2058,11 +2063,12 @@ pub fn emitLazy(
20582063 .relocs = .empty,
20592064 .table_relocs = .empty,
20602065 };
2061 defer e.deinit();
2062 e.emitMir() catch |err| switch (err) {
2063 error.LowerFail, error.EmitFail => return zcu.codegenFailTypeMsg(lazy_sym.ty, e.lower.err_msg.?),
2066 defer em.deinit();
2067 em.emitMir() catch |err| switch (err) {
2068 error.LowerFail, error.EmitFail => return zcu.codegenFailTypeMsg(lazy_sym.ty, em.lower.err_msg.?),
20642069 error.InvalidInstruction, error.CannotEncode => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),
20652070 else => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s}", .{@errorName(err)}),
2071 error.AlreadyReported, error.Canceled, error.WriteFailed => |e| return e,
20662072 };
20672073}
20682074
src/crash_report.zig-1
......@@ -215,7 +215,6 @@ const Sema = @import("Sema.zig");
215215const Zcu = @import("Zcu.zig");
216216const link = @import("link.zig");
217217const InternPool = @import("InternPool.zig");
218const dev = @import("dev.zig");
219218const print_zir = @import("print_zir.zig");
220219
221220const build_options = @import("build_options");
src/dev.zig-1
......@@ -227,7 +227,6 @@ pub const Env = enum {
227227 else => Env.sema.supports(feature),
228228 },
229229 .@"x86_64-windows" => switch (feature) {
230 .build_command,
231230 .stdio_listen,
232231 .incremental,
233232 .legalize,
src/link.zig+109-48
......@@ -26,9 +26,10 @@ const target_util = @import("target.zig");
2626const codegen = @import("codegen.zig");
2727const crash_report = @import("crash_report.zig");
2828
29pub const ConstPool = @import("link/ConstPool.zig");
2930pub const LdScript = @import("link/LdScript.zig");
31pub const MappedFile = @import("link/MappedFile.zig");
3032pub const Queue = @import("link/Queue.zig");
31pub const ConstPool = @import("link/ConstPool.zig");
3233
3334pub const aarch64 = @import("link/aarch64.zig");
3435pub const loongarch = @import("link/loongarch.zig");
......@@ -38,6 +39,7 @@ pub const Error = Allocator.Error || Io.Cancelable || error{
3839 /// instance in `Compilation.link_diags`.
3940 AlreadyReported,
4041};
42pub const EmitError = Error || Io.Writer.Error;
4143
4244pub const Diags = struct {
4345 /// Stored here so that function definitions can distinguish between
......@@ -95,7 +97,6 @@ pub const Diags = struct {
9597 return switch (msg.source_location) {
9698 .none => try bundle.addString(msg.msg),
9799 .wasm => |sl| {
98 dev.check(.wasm_linker);
99100 const wasm = base.?.cast(.wasm).?;
100101 return sl.string(msg.msg, bundle, wasm);
101102 },
......@@ -394,8 +395,6 @@ pub const Diags = struct {
394395 }
395396};
396397
397pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version;
398
399398pub const File = struct {
400399 tag: Tag,
401400
......@@ -653,7 +652,6 @@ pub const File = struct {
653652 base.file = try emit.root_dir.handle.openFile(io, emit.sub_path, .{ .mode = .read_write });
654653 },
655654 .elf2, .coff2 => if (base.file == null) {
656 dev.checkAny(&.{ .elf2_linker, .coff2_linker });
657655 const mf = if (base.cast(.elf2)) |elf|
658656 &elf.mf
659657 else if (base.cast(.coff2)) |coff|
......@@ -757,6 +755,8 @@ pub const File = struct {
757755
758756 pub const DebugInfoOutput = union(enum) {
759757 dwarf: *Dwarf.WipNav,
758 eh_frame: *Dwarf2.WipNav,
759 dwarf2: *Dwarf2.WipNav.Debug,
760760 none,
761761 };
762762 pub const UpdateDebugInfoError = Dwarf.UpdateError;
......@@ -791,9 +791,31 @@ pub const File = struct {
791791 }
792792 }
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
794816 /// Asserts that the ZCU is not using the LLVM backend.
795817 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);
797819 const nav = pt.zcu.intern_pool.getNav(nav_index);
798820 assert(nav.resolved.?.value != .none);
799821
......@@ -809,30 +831,17 @@ pub const File = struct {
809831
810832 /// Never called when LLVM is codegenning the ZCU.
811833 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);
813835 switch (base.tag) {
814836 .lld => unreachable,
815837 else => {},
816 inline .elf, .c => |tag| {
838 inline .elf, .elf2, .c, .coff2 => |tag| {
817839 dev.check(tag.devFeature());
818840 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateContainerType(pt, ty, success);
819841 },
820842 }
821843 }
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
836845 /// The active tag of `mir` is determined by the backend used for the module this function is in.
837846 /// Never called when LLVM is codegenning the ZCU.
838847 fn updateFunc(
......@@ -844,7 +853,7 @@ pub const File = struct {
844853 /// take ownership of an embedded slice and replace it with `&.{}` in `mir`.
845854 mir: *codegen.AnyMir,
846855 ) Error!void {
847 assert(base.comp.zcu.?.llvm_object == null);
856 assert(pt.zcu.llvm_object == null);
848857 switch (base.tag) {
849858 .lld => unreachable,
850859 .plan9 => unreachable,
......@@ -858,23 +867,49 @@ pub const File = struct {
858867 /// On an incremental update, fixup the line number of all `Nav`s at the given `TrackedInst`, because
859868 /// its line number has changed. The ZIR instruction `ti_id` has tag `.declaration`.
860869 /// Never called when LLVM is codegenning the ZCU.
861 fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) Error!void {
862 assert(base.comp.zcu.?.llvm_object == null);
870 fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index, line: u32) Error!void {
871 assert(pt.zcu.llvm_object == null);
863872 {
864873 const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?;
865874 const file = pt.zcu.fileByIndex(ti.file);
866875 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 }
868891 }
869
870892 switch (base.tag) {
871893 .lld => unreachable,
872 .spirv => {},
873894 .plan9 => unreachable,
874 .elf2, .coff2 => {},
895 .spirv => {},
896 .coff2 => {},
875897 inline else => |tag| {
876898 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);
878913 },
879914 }
880915 }
......@@ -984,7 +1019,7 @@ pub const File = struct {
9841019 pt: Zcu.PerThread,
9851020 export_indices: []const Zcu.Export.Index,
9861021 ) Error!void {
987 assert(base.comp.zcu.?.llvm_object == null);
1022 assert(pt.zcu.llvm_object == null);
9881023
9891024 crash_report.LinkerOp.start(base, pt.tid);
9901025 defer crash_report.LinkerOp.stop(base, pt.tid);
......@@ -1019,7 +1054,7 @@ pub const File = struct {
10191054 /// the block/atom.
10201055 /// Never called when LLVM is codegenning the ZCU.
10211056 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
10241059 switch (base.tag) {
10251060 .lld => unreachable,
......@@ -1042,7 +1077,7 @@ pub const File = struct {
10421077 decl_val: InternPool.Index,
10431078 decl_align: InternPool.Alignment,
10441079 ) Error!SymbolId {
1045 assert(base.comp.zcu.?.llvm_object == null);
1080 assert(pt.zcu.llvm_object == null);
10461081
10471082 switch (base.tag) {
10481083 .lld => unreachable,
......@@ -1308,7 +1343,7 @@ pub const File = struct {
13081343 };
13091344 }
13101345
1311 pub fn devFeature(tag: Tag) dev.Feature {
1346 fn devFeature(tag: Tag) dev.Feature {
13121347 return @field(dev.Feature, @tagName(tag) ++ "_linker");
13131348 }
13141349 };
......@@ -1391,6 +1426,7 @@ pub const File = struct {
13911426 pub const SpirV = @import("link/SpirV.zig");
13921427 pub const Wasm = @import("link/Wasm.zig");
13931428 pub const Dwarf = @import("link/Dwarf.zig");
1429 pub const Dwarf2 = @import("link/Dwarf2.zig");
13941430};
13951431
13961432pub const PrelinkTask = union(enum) {
......@@ -1413,6 +1449,9 @@ pub const PrelinkTask = union(enum) {
14131449 load_dso: Path,
14141450};
14151451pub 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,
14161455 /// Write the constant value for a Decl to the output file.
14171456 link_nav: InternPool.Nav.Index,
14181457 /// Write the machine code for a function to the output file.
......@@ -1424,7 +1463,11 @@ pub const ZcuTask = union(enum) {
14241463 ty: InternPool.Index,
14251464 success: bool,
14261465 },
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,
14281471};
14291472
14301473pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
......@@ -1616,6 +1659,16 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void
16161659 var timer = comp.startTimer();
16171660
16181661 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 },
16191672 .link_nav => |nav_index| nav: {
16201673 const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
16211674 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
16611714 break :nav ip.indexToKey(func).func.owner_nav;
16621715 },
16631716 .debug_update_container_type => |container_update| nav: {
1664 const name = Type.fromInterned(container_update.ty).containerTypeName(ip).toSlice(ip);
1665 const ty_prog_node = comp.link_prog_node.start(name, 0);
1717 const fqn = Type.fromInterned(container_update.ty).containerTypeName(ip).fqn.toSlice(ip);
1718 const ty_prog_node = comp.link_prog_node.start(fqn, 0);
16661719 defer ty_prog_node.end();
1667 if (zcu.llvm_object) |llvm_object| {
1668 llvm_object.updateContainerType(pt, container_update.ty, container_update.success) catch |err| switch (err) {
1669 error.OutOfMemory => diags.setAllocFailure(),
1670 };
1671 } else {
1720 (if (zcu.llvm_object) |llvm_object|
1721 llvm_object.updateContainerType(pt, container_update.ty, container_update.success)
1722 else if (comp.bin_file) |lf|
1723 lf.updateContainerType(pt, container_update.ty, container_update.success)) catch |err| switch (err) {
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) {
16721734 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) {
16741736 error.OutOfMemory => diags.setAllocFailure(),
1675 error.Canceled => io.recancel(),
1676 error.AlreadyReported => {},
1737 else => |e| log.err("update line number failed: {s}", .{@errorName(e)}),
16771738 };
16781739 }
16791740 }
16801741 break :nav null;
16811742 },
1682 .debug_update_line_number => |ti| nav: {
1683 const nav_prog_node = comp.link_prog_node.start("Update line number", 0);
1743 .lost_tracking => |ti| nav: {
1744 const nav_prog_node = comp.link_prog_node.start("Lost tracking", 0);
16841745 defer nav_prog_node.end();
16851746 if (pt.zcu.llvm_object == null) {
16861747 if (comp.bin_file) |lf| {
1687 lf.updateLineNumber(pt, ti) catch |err| switch (err) {
1748 lf.lostTracking(pt, ti) catch |err| switch (err) {
16881749 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)}),
16901751 };
16911752 }
16921753 }
src/link/C.zig+19-18
......@@ -209,7 +209,7 @@ pub fn addConst(
209209 pt: Zcu.PerThread,
210210 pool_index: link.ConstPool.Index,
211211 val: InternPool.Index,
212) Allocator.Error!void {
212) link.Error!void {
213213 const zcu = pt.zcu;
214214 const gpa = zcu.comp.gpa;
215215 assert(zcu.intern_pool.typeOf(val) == .type_type);
......@@ -310,7 +310,7 @@ pub fn updateConst(
310310 pt: Zcu.PerThread,
311311 index: link.ConstPool.Index,
312312 val: InternPool.Index,
313) Allocator.Error!void {
313) link.Error!void {
314314 const zcu = pt.zcu;
315315 const gpa = zcu.comp.gpa;
316316
......@@ -498,7 +498,7 @@ pub fn updateFunc(
498498 pt: Zcu.PerThread,
499499 func_index: InternPool.Index,
500500 mir: *AnyMir,
501) Allocator.Error!void {
501) link.Error!void {
502502 const zcu = pt.zcu;
503503 const gpa = zcu.gpa;
504504 const nav = zcu.funcInfo(func_index).owner_nav;
......@@ -536,11 +536,7 @@ pub fn updateFunc(
536536 try c.type_pool.flushPending(pt, .{ .c = c });
537537}
538538
539pub fn updateNav(
540 c: *C,
541 pt: Zcu.PerThread,
542 nav_index: InternPool.Nav.Index,
543) Allocator.Error!void {
539pub fn updateNav(c: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void {
544540 const tracy = trace(@src());
545541 defer tracy.end();
546542
......@@ -603,7 +599,8 @@ pub fn updateNav(
603599 const start = aw.written().len;
604600 codegen.genDeclFwd(&dg, &aw.writer) catch |err| switch (err) {
605601 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,
607604 };
608605 break :fwd_decl .{
609606 .start = @intCast(start),
......@@ -617,7 +614,8 @@ pub fn updateNav(
617614 const start = aw.written().len;
618615 codegen.genDecl(&dg, &aw.writer) catch |err| switch (err) {
619616 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,
621619 };
622620 break :code .{
623621 .start = @intCast(start),
......@@ -655,7 +653,7 @@ fn updateUav(
655653 pt: Zcu.PerThread,
656654 val: Value,
657655 rendered_decl: *RenderedDecl,
658) Allocator.Error!void {
656) link.Error!void {
659657 const tracy = trace(@src());
660658 defer tracy.end();
661659
......@@ -691,7 +689,8 @@ fn updateUav(
691689 .init_val = val,
692690 }) catch |err| switch (err) {
693691 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,
695694 };
696695 break :fwd_decl .{
697696 .start = @intCast(start),
......@@ -710,7 +709,8 @@ fn updateUav(
710709 .init_val = val,
711710 }) catch |err| switch (err) {
712711 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,
714714 };
715715 break :code .{
716716 .start = @intCast(start),
......@@ -721,12 +721,13 @@ fn updateUav(
721721 rendered_decl.ctype_deps = try c.addCTypeDependencies(pt, &dg.ctype_deps);
722722}
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 {
725725 // The C backend does not currently emit "#line" directives. Even if it did, it would not be
726726 // capable of updating those line numbers without re-generating the entire declaration.
727727 _ = c;
728728 _ = pt;
729729 _ = ti_id;
730 _ = line;
730731}
731732
732733pub 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
11441145 for (need_never_tail_funcs.keys()) |fn_nav| {
11451146 codegen.genLazyCallModifierFn(&lazy_dg, fn_nav, .never_tail, &lazy_decls_aw.writer) catch |err| switch (err) {
11461147 error.WriteFailed => return error.OutOfMemory,
1147 error.OutOfMemory => |e| return e,
1148 error.Canceled, error.OutOfMemory => |e| return e,
11481149 error.AlreadyReported => unreachable,
11491150 };
11501151 }
11511152 for (need_never_inline_funcs.keys()) |fn_nav| {
11521153 codegen.genLazyCallModifierFn(&lazy_dg, fn_nav, .never_inline, &lazy_decls_aw.writer) catch |err| switch (err) {
11531154 error.WriteFailed => return error.OutOfMemory,
1154 error.OutOfMemory => |e| return e,
1155 error.Canceled, error.OutOfMemory => |e| return e,
11551156 error.AlreadyReported => unreachable,
11561157 };
11571158 }
......@@ -1343,7 +1344,7 @@ fn addCTypeDependencies(
13431344 c: *C,
13441345 pt: Zcu.PerThread,
13451346 deps: *const codegen.CType.Dependencies,
1346) Allocator.Error!CTypeDependencies {
1347) link.Error!CTypeDependencies {
13471348 const gpa = pt.zcu.comp.gpa;
13481349
13491350 try c.bigint_types.ensureUnusedCapacity(gpa, deps.bigint.count());
......@@ -1399,7 +1400,7 @@ fn addCTypeDependencies(
13991400 };
14001401}
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 {
14031404 const gpa = pt.zcu.comp.gpa;
14041405 var index = old_uavs_len;
14051406 while (index < c.uavs.count()) : (index += 1) {
src/link/Coff.zig+190-155
......@@ -13,7 +13,7 @@ const codegen = @import("../codegen.zig");
1313const Compilation = @import("../Compilation.zig");
1414const InternPool = @import("../InternPool.zig");
1515const link = @import("../link.zig");
16const MappedFile = @import("MappedFile.zig");
16const MappedFile = link.MappedFile;
1717const target_util = @import("../target.zig");
1818const Type = @import("../Type.zig");
1919const Value = @import("../Value.zig");
......@@ -536,7 +536,7 @@ pub const Member = struct {
536536 const new_size = Alignment.@"4".forward(old_size + name.len + 1);
537537 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);
540540 const name_table_slice = Node.known.longnames_member.slice(&coff.mf);
541541 const name_slice = name_table_slice[@intCast(old_size)..][0 .. name.len + 1];
542542 @memcpy(name_slice[0..name.len], name);
......@@ -1666,7 +1666,7 @@ fn create(
16661666 .global_pending_index = 0,
16671667 .navs = .empty,
16681668 .uavs = .empty,
1669 .lazy = .initFill(.{
1669 .lazy = comptime .initFill(.{
16701670 .map = .empty,
16711671 .pending_index = 0,
16721672 }),
......@@ -1840,13 +1840,13 @@ fn initHeaders(
18401840 coff.nodes.appendAssumeCapacity(.file);
18411841
18421842 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, .{
18441844 .alignment = coff.mf.flags.block_size,
18451845 }));
18461846 coff.nodes.appendAssumeCapacity(.header);
18471847
18481848 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), .{
18501850 .size = std.coff.archive_signature.len,
18511851 .alignment = .@"4",
18521852 }) == Node.known.signature);
......@@ -1879,7 +1879,7 @@ fn initHeaders(
18791879 const zcu_member = zcu_mi.get(coff);
18801880 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, .{
18831883 .size = @sizeOf(std.coff.Header),
18841884 .alignment = .@"4",
18851885 }) == Node.known.coff_header);
......@@ -1894,13 +1894,13 @@ fn initHeaders(
18941894 // no other members then the last linker member (longnames) needs to expand
18951895 // to fill the padding at the end of the file.
18961896 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, .{});
18981898 coff.nodes.appendAssumeCapacity(.placeholder);
18991899 }
19001900
19011901 return;
19021902 } else parent: {
1903 assert(try header_ni.addOnlyHeaderChild(&coff.mf, gpa, .{
1903 assert(try header_ni.addOnlyHeaderChild(gpa, &coff.mf, .{
19041904 .size = if (is_image) msdos_stub.len + std.coff.pe_signature.len else 0,
19051905 .alignment = .@"4",
19061906 }) == Node.known.signature);
......@@ -1913,12 +1913,12 @@ fn initHeaders(
19131913
19141914 // TODO: Not ideal to have this many placeholder nodes - use two distinct `Node.known` types?
19151915 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, .{});
19171917 coff.nodes.appendAssumeCapacity(.placeholder);
19181918 if (placeholder_ni == Node.known.zcu_member) break;
19191919 }
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), .{
19221922 .size = @sizeOf(std.coff.Header),
19231923 .alignment = .@"4",
19241924 }) == Node.known.coff_header);
......@@ -1949,7 +1949,7 @@ fn initHeaders(
19491949 }
19501950
19511951 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), .{
19531953 .size = optional_header_size,
19541954 .alignment = .@"4",
19551955 }));
......@@ -2060,7 +2060,7 @@ fn initHeaders(
20602060 }
20612061
20622062 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), .{
20642064 .size = data_directories_size,
20652065 .alignment = .@"4",
20662066 }));
......@@ -2075,7 +2075,7 @@ fn initHeaders(
20752075 }
20762076
20772077 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), .{
20792079 .alignment = .@"4",
20802080 }));
20812081 coff.nodes.appendAssumeCapacity(.section_table);
......@@ -2084,13 +2084,13 @@ fn initHeaders(
20842084
20852085 if (!is_image) {
20862086 // 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), .{
20882088 .alignment = .@"2",
20892089 .moved = true,
20902090 });
20912091 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), .{
20942094 .size = @sizeOf(u32),
20952095 .resized = true,
20962096 });
......@@ -2143,7 +2143,7 @@ fn initHeaders(
21432143 coff.mf.flags.block_size,
21442144 .{ .read = true, .initialized = true },
21452145 )).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, .{
21472147 .alignment = .@"4",
21482148 });
21492149 coff.nodes.appendAssumeCapacity(.import_directory_table);
......@@ -2154,7 +2154,7 @@ fn initHeaders(
21542154 .{ .read = true, .initialized = true },
21552155 )).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), .{
21582158 .size = @sizeOf(std.coff.ExportDirectoryTable) + file_name.len + 1,
21592159 .moved = true,
21602160 });
......@@ -2165,7 +2165,7 @@ fn initHeaders(
21652165 @memcpy(table_slice[name_index..][0..file_name.len], file_name[0..file_name.len]);
21662166 @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, .{
21692169 .alignment = .of(std.coff.ExportAddressTableEntry),
21702170 .moved = true,
21712171 });
......@@ -2181,19 +2181,19 @@ fn initHeaders(
21812181 export_address_table_sym.section_number =
21822182 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, .{
21852185 .alignment = .of(std.coff.ExportNamePointerTableEntry),
21862186 .moved = true,
21872187 });
21882188 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, .{
21912191 .alignment = .of(std.coff.ExportOrdinalTableEntry),
21922192 .moved = true,
21932193 });
21942194 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, .{
21972197 .alignment = .of(u8),
21982198 .moved = true,
21992199 });
......@@ -2286,7 +2286,7 @@ pub fn initBuiltins(coff: *Coff) !void {
22862286 const list_len_si = try coff.globalSymbol(.{ .name = list.global, .type = .data });
22872287 const list_len_sym = list_len_si.get(coff);
22882288 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, .{
22902290 .size = addr_info.size,
22912291 }));
22922292 coff.nodes.appendAssumeCapacity(.{ .builtin = list_len_si });
......@@ -2307,7 +2307,7 @@ pub fn initBuiltins(coff: *Coff) !void {
23072307 const list_end_si = coff.addSymbolAssumeCapacity();
23082308 const list_end_sym = list_end_si.get(coff);
23092309 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, .{
23112311 .size = addr_info.size,
23122312 }));
23132313 coff.nodes.appendAssumeCapacity(.{ .builtin = list_end_si });
......@@ -2723,7 +2723,7 @@ fn getOrPutSymbolName(coff: *Coff, name: []const u8, opt_string: ?String) !Symbo
27232723 const string_index = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf)[1];
27242724 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);
27272727 const slice = coff.symbol_table.strings_ni.slice(&coff.mf);
27282728 @memcpy(slice[@intCast(string_index)..][0..name.len], name);
27292729 slice[@intCast(string_index + name.len)] = 0;
......@@ -2948,7 +2948,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind,
29482948 const comp = coff.base.comp;
29492949 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), .{
29522952 .size = @sizeOf(std.coff.ArchiveMemberHeader),
29532953 .alignment = .@"2",
29542954 .moved = true,
......@@ -2960,7 +2960,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind,
29602960 .first_linker, .second_linker, .longnames, .coff => .@"4",
29612961 else => .@"2",
29622962 };
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), .{
29642964 .alignment = content_align,
29652965 .size = content_align.forward(size),
29662966 .resized = size > 0,
......@@ -2989,7 +2989,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind,
29892989 const old_size = Node.known.second_linker_member.location(&coff.mf).resolve(&coff.mf)[1];
29902990 const old_header_size = new_num_members * @sizeOf(u32);
29912991 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
29942994 const slice = Node.known.second_linker_member.slice(&coff.mf);
29952995 @memmove(
......@@ -3060,7 +3060,7 @@ fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void {
30603060 {
30613061 const old_header_size: usize = @intCast(@sizeOf(u32) + @backingInt(mfli) * @sizeOf(u32));
30623062 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
30653065 const slice = Node.known.first_linker_member.slice(&coff.mf);
30663066 @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 {
30743074 const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr());
30753075 const old_header_size = 2 * @sizeOf(u32) + num_members * @sizeOf(u32) + @backingInt(mfli) * @sizeOf(u16);
30763076 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
30793079 const old_needs_sort = coff.pending_members.get(Member.Index.second) != null;
30803080 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 {
31083108 coff.member_prog_node.increaseEstimatedTotalItems(1);
31093109}
31103110
3111fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
3111fn flushSymbolTableEntry(coff: *Coff, index: u32) !void {
31123112 assert(!coff.isImage());
31133113 const gpa = coff.base.comp.gpa;
31143114
......@@ -3119,7 +3119,6 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
31193119 assert(sym.ni != .none or sym.gmi != .none);
31203120
31213121 const entry = coff.symbolTableEntryPtr(sti.*) orelse entry: {
3122 var buf: [15]u8 = undefined;
31233122 const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType =
31243123 if (sym.gmi != .none) blk: {
31253124 const name = sym.gmi.name(coff);
......@@ -3148,21 +3147,22 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
31483147 };
31493148 },
31503149 .uav => |umi| {
3151 var w = Io.Writer.fixed(&buf);
3152 w.print("__anon_{x}", .{umi.uavValue(coff)}) catch unreachable;
3150 var name_buf: [std.fmt.count("__anon_{d}", .{std.math.maxInt(u32)})]u8 = undefined;
3151 const name = std.mem.print(&name_buf, "__anon_{d}", .{umi}) catch unreachable;
31533152 break :blk .{
3154 try coff.getOrPutSymbolName(w.buffered(), null),
3153 try coff.getOrPutSymbolName(name, null),
31553154 0,
31563155 .NULL,
31573156 };
31583157 },
31593158 inline .lazy_code, .lazy_const_data => |mi, tag| {
31603159 const lazy_sym = mi.lazySymbol(coff);
3161 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{
3162 @tagName(lazy_sym.kind),
3163 Type.fromInterned(lazy_sym.ty).fmt(pt),
3164 });
3165 defer gpa.free(name);
3160 var name_buf: [
3161 std.fmt.count("__lazy_const_data_{d}", .{std.math.maxInt(u32)})
3162 ]u8 = undefined;
3163 const name = std.mem.print(&name_buf, "__lazy_{t}_{d}", .{
3164 lazy_sym.kind, mi,
3165 }) catch unreachable;
31663166
31673167 const string = try coff.getOrPutString(name);
31683168 break :blk .{
......@@ -3181,7 +3181,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
31813181 const new_num_symbols = old_num_symbols + 1 + num_aux_symbols;
31823182 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
31863186 sti.* = .wrap(old_num_symbols);
31873187 si.flushSymbolTableIndex(coff);
......@@ -3317,7 +3317,7 @@ fn flushInputSection(coff: *Coff, isi: Node.InputSection.Index) !void {
33173317 try fr.seekTo(file_loc.offset);
33183318 var nw: MappedFile.Node.Writer = undefined;
33193319 const si = isi.symbol(coff);
3320 si.node(coff).writer(&coff.mf, gpa, &nw);
3320 si.node(coff).writer(gpa, &coff.mf, &nw);
33213321 defer nw.deinit();
33223322 log.debug("flushInputSection({f}{f}, {s}, {d}, n{d})", .{
33233323 path,
......@@ -3345,12 +3345,12 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S
33453345 const section_table_len = section_index + 1;
33463346 coff.targetStore(&coff_header.number_of_sections, section_table_len);
33473347 try Node.known.section_table.resizeLeaf(
3348 &coff.mf,
33493348 gpa,
3349 &coff.mf,
33503350 @sizeOf(std.coff.SectionHeader) * section_table_len,
33513351 );
33523352
3353 const ni = try coff.sectionParent().addFloatingChild(&coff.mf, gpa, .{
3353 const ni = try coff.sectionParent().addFloatingChild(gpa, &coff.mf, .{
33543354 .alignment = coff.mf.flags.block_size,
33553355 .moved = true,
33563356 .bubbles_moved = false,
......@@ -3486,7 +3486,7 @@ fn pseudoSectionMapIndex(
34863486
34873487 try coff.nodes.ensureUnusedCapacity(gpa, 1);
34883488 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 });
34903490 const si = coff.addSymbolAssumeCapacity();
34913491 pseudo_section_gop.value_ptr.* = si;
34923492 const sym = si.get(coff);
......@@ -3560,7 +3560,7 @@ fn objectSectionMapIndex(
35603560 }
35613561 }
35623562 }
3563 const ni = try parent_ni.addHeaderChildAfter(&coff.mf, gpa, prev_oni, .{
3563 const ni = try parent_ni.addHeaderChildAfter(gpa, &coff.mf, prev_oni, .{
35643564 .alignment = alignment,
35653565 });
35663566 const si = coff.addSymbolAssumeCapacity();
......@@ -3579,13 +3579,13 @@ fn objectSectionMapIndex(
35793579 const parent_alignment = parent_ni.alignment(&coff.mf);
35803580 if (alignment.compare(.gt, parent_alignment)) {
35813581 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);
35833583 }
35843584
35853585 const old_alignment = sym.ni.unwrap().?.alignment(&coff.mf);
35863586 if (alignment.compare(.gt, old_alignment)) {
35873587 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);
35893589 }
35903590
35913591 try coff.verifyParentSectionAttributes(
......@@ -3742,9 +3742,9 @@ fn addRelocAssumeCapacity(
37423742 coff.targetStore(&aux_ptr.number_of_relocations, new_num_relocations);
37433743
37443744 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);
37463746 } 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, .{
37483748 .size = new_size,
37493749 .alignment = .@"2",
37503750 .moved = true,
......@@ -4094,7 +4094,7 @@ fn loadObject(
40944094 {
40954095 // TODO: This should be deferred to an idle task (but resize it here!)
40964096 var nw: MappedFile.Node.Writer = undefined;
4097 member.content_ni.writer(&coff.mf, gpa, &nw);
4097 member.content_ni.writer(gpa, &coff.mf, &nw);
40984098 defer nw.deinit();
40994099
41004100 try fr.seekTo(fl.offset);
......@@ -4653,7 +4653,7 @@ fn loadObject(
46534653 if (section.parent_si == .null) continue;
46544654
46554655 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, .{
46574657 .size = alignment.forward(section.header.size_of_raw_data),
46584658 .alignment = alignment,
46594659 .moved = true,
......@@ -5064,7 +5064,9 @@ fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) Loa
50645064 offset: u32,
50655065 iami: ?InputArchive.Member.Index,
50665066 }) = .empty;
5067 defer members.deinit(gpa);
50675068 var symbol_member_indices: std.ArrayList(u32) = .empty;
5069 defer symbol_member_indices.deinit(gpa);
50685070
50695071 const iai: InputArchive.Index = @fromBackingInt(@intCast(coff.input_archives.items.len));
50705072 (try coff.input_archives.addOne(gpa)).* = .{
......@@ -5447,7 +5449,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
54475449 const sec_si = try coff.navSection(zcu, nav.resolved.?);
54485450 try coff.nodes.ensureUnusedCapacity(gpa, 1);
54495451 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, .{
54515453 .alignment = .fromIp(zcu.navAlignment(nav_index)),
54525454 .moved = true,
54535455 });
......@@ -5469,7 +5471,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
54695471
54705472 {
54715473 var nw: MappedFile.Node.Writer = undefined;
5472 ni.writer(&coff.mf, gpa, &nw);
5474 ni.writer(gpa, &coff.mf, &nw);
54735475 defer nw.deinit();
54745476 codegen.generateSymbol(
54755477 &coff.base,
......@@ -5486,8 +5488,26 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
54865488 }
54875489
54885490 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);
54905492 }
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 };
54915511}
54925512
54935513pub fn lowerUav(
......@@ -5558,7 +5578,7 @@ fn updateFuncInner(
55585578 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);
55595579 const mod = zcu.navFileScope(func.owner_nav).mod.?;
55605580 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, .{
55625582 .alignment = switch (nav.resolved.?.@"align") {
55635583 .none => switch (mod.optimize_mode) {
55645584 .debug,
......@@ -5587,7 +5607,7 @@ fn updateFuncInner(
55875607 };
55885608
55895609 var nw: MappedFile.Node.Writer = undefined;
5590 ni.writer(&coff.mf, gpa, &nw);
5610 ni.writer(gpa, &coff.mf, &nw);
55915611 defer nw.deinit();
55925612 codegen.emitFunction(
55935613 &coff.base,
......@@ -5603,10 +5623,13 @@ fn updateFuncInner(
56035623 };
56045624 si.get(coff).extra.size = @intCast(nw.interface.end);
56055625 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);
56065629}
56075630
56085631pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void {
5609 coff.flushLazy(pt, .{
5632 coff.genLazyInner(pt, .{
56105633 .kind = .const_data,
56115634 .index = @intCast(coff.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return),
56125635 }) catch |err| switch (err) {
......@@ -5863,8 +5886,8 @@ pub fn flush(
58635886
58645887 const number_of_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);
58655888 coff.symbol_table.ni.resizeLeaf(
5866 &coff.mf,
58675889 comp.gpa,
5890 &coff.mf,
58685891 number_of_symbols * std.coff.Symbol.sizeOf(),
58695892 ) catch |err| switch (err) {
58705893 else => |e| return e,
......@@ -5919,22 +5942,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
59195942 };
59205943 break :task;
59215944 }
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 }
59385945 if (coff.pending_input) |pending_iami| {
59395946 const name_slice = pending_iami.member(coff).name.toSlice(coff);
59405947 const sub_prog_node = coff.input_prog_node.start(
......@@ -5983,33 +5990,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
59835990 };
59845991 break :task;
59855992 }
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 };
60135993 if (coff.symbol_table.pending_symbol_index < coff.symbol_table.symbols.count()) {
60145994 defer coff.symbol_table.pending_symbol_index += 1;
60155995 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 {
60256005 defer sub_prog_node.end();
60266006 coff.flushSymbolTableEntry(
60276007 coff.symbol_table.pending_symbol_index,
6028 .{ .zcu = comp.zcu.?, .tid = tid },
60296008 ) catch |err| switch (err) {
60306009 error.OutOfMemory => return error.OutOfMemory,
60316010 else => |e| return comp.link_diags.fail(
......@@ -6038,12 +6017,10 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
60386017 }
60396018
60406019 if (coff.section_merge_pending_index < coff.section_merges.count()) return true;
6041 if (coff.pending_uavs.count() > 0) return true;
60426020 if (coff.pending_input != null) return true;
60436021 if (coff.exports_complete and coff.globals.count() > coff.global_pending_index) return true;
60446022 assert(!coff.exports_complete or coff.inputs_complete);
60456023 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;
60476024 if (coff.symbol_table.pending_symbol_index < coff.symbol_table.symbols.count()) return true;
60486025 return false;
60496026}
......@@ -6077,17 +6054,18 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
60776054 };
60786055 break :task;
60796056 }
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;
60816059 const clean_moved = ni.cleanMoved(&coff.mf);
60826060 const clean_resized = ni.cleanResized(&coff.mf);
6083 if (clean_moved or clean_resized) {
6084 const sub_prog_node =
6085 coff.idleProgNode(tid, coff.mf.update_prog_node, coff.getNode(ni));
6086 defer sub_prog_node.end();
6087 if (clean_moved) try coff.flushMoved(ni);
6088 if (clean_resized) try coff.flushResized(ni);
6089 break :task;
6090 } else coff.mf.update_prog_node.completeOne();
6061 const clean_next_moved = ni.cleanNextMoved(&coff.mf);
6062 if (!clean_moved and !clean_resized and !clean_next_moved) continue;
6063 const sub_prog_node =
6064 coff.idleProgNode(tid, coff.mf.update_prog_node, coff.getNode(ni));
6065 defer sub_prog_node.end();
6066 if (clean_moved) try coff.flushMoved(ni);
6067 if (clean_resized) try coff.flushResized(ni);
6068 break :task;
60916069 }
60926070 while (coff.pending_members.pop()) |pending_mi| {
60936071 const sub_prog_node = coff.idleProgNode(
......@@ -6153,7 +6131,27 @@ fn idleProgNode(
61536131 }, 0);
61546132}
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(
61576155 coff: *Coff,
61586156 pt: Zcu.PerThread,
61596157 umi: Node.UavMapIndex,
......@@ -6175,7 +6173,7 @@ fn flushUav(
61756173 try coff.nodes.ensureUnusedCapacity(gpa, 1);
61766174 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);
61776175 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, .{
61796177 .alignment = .fromIp(uav_align),
61806178 .moved = true,
61816179 });
......@@ -6204,7 +6202,7 @@ fn flushUav(
62046202 };
62056203
62066204 var nw: MappedFile.Node.Writer = undefined;
6207 ni.writer(&coff.mf, gpa, &nw);
6205 ni.writer(gpa, &coff.mf, &nw);
62086206 defer nw.deinit();
62096207 codegen.generateSymbol(
62106208 &coff.base,
......@@ -6311,7 +6309,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
63116309 .{ name, imp_match }
63126310 else name: {
63136311 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});
63156313 defer gpa.free(imp_name);
63166314 break :name .{ coff.getOrPutStringAssumeCapacity(imp_name), true };
63176315 };
......@@ -6468,19 +6466,19 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
64686466 if (!gop.found_existing) {
64696467 errdefer _ = coff.import_table.entries.pop();
64706468 try coff.import_table.ni.resizeLeaf(
6471 &coff.mf,
64726469 gpa,
6470 &coff.mf,
64736471 @sizeOf(std.coff.ImportDirectoryEntry) * (gop.index + 2),
64746472 );
64756473 const import_hint_name_table_len =
64766474 import_hint_name_align.forward(lib_name.len + ".dll".len + 1);
64776475 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, .{
64796477 .size = addr_info.size * 2,
64806478 .alignment = addr_info.alignment,
64816479 .moved = true,
64826480 });
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, .{
64846482 .size = addr_info.size * 2,
64856483 .alignment = addr_info.alignment,
64866484 .moved = true,
......@@ -6494,7 +6492,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
64946492 import_address_table_sym.section_number =
64956493 coff.getNode(idata_section_ni).object_section.symbol(coff).get(coff).section_number;
64966494 }
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, .{
64986496 .size = import_hint_name_table_len,
64996497 .alignment = import_hint_name_align,
65006498 .moved = true,
......@@ -6550,9 +6548,9 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
65506548 gop.value_ptr.len = import_symbol_index + 1;
65516549 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);
65546552 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
65576555 const opt_imp_name = import.name.toSlice(coff);
65586556 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 {
65606558 gop.value_ptr.hint_name_len = @intCast(
65616559 import_hint_name_align.forward(import_hint_name_index + 2 + imp_name.len + 1),
65626560 );
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);
65646562 break :blk import_hint_name_index;
65656563 } else null;
65666564
......@@ -6635,7 +6633,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
66356633 else => |tag| @panic(@tagName(tag)),
66366634 .AMD64 => {
66376635 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, .{
66396637 .alignment = alignment,
66406638 .size = alignment.forward(init.len),
66416639 });
......@@ -6773,7 +6771,31 @@ fn flushSpecialSymbol(coff: *Coff, pending: SpecialSymbol) !SpecialSymbol {
67736771 };
67746772}
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 {
67776799 const zcu = pt.zcu;
67786800 const gpa = zcu.gpa;
67796801
......@@ -6788,7 +6810,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
67886810 .code => .text,
67896811 .const_data => .rdata,
67906812 };
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 });
67926814 coff.nodes.appendAssumeCapacity(switch (lazy.kind) {
67936815 .code => .{ .lazy_code = @fromBackingInt(@intCast(lmr.index)) },
67946816 .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(lmr.index)) },
......@@ -6808,7 +6830,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
68086830
68096831 var required_alignment: InternPool.Alignment = .none;
68106832 var nw: MappedFile.Node.Writer = undefined;
6811 ni.writer(&coff.mf, gpa, &nw);
6833 ni.writer(gpa, &coff.mf, &nw);
68126834 defer nw.deinit();
68136835 codegen.generateLazySymbol(
68146836 &coff.base,
......@@ -7356,7 +7378,7 @@ fn updateExportInner(
73567378 pt: Zcu.PerThread,
73577379 export_index: Zcu.Export.Index,
73587380 alias_syms: *std.array_hash_map.Auto(Symbol.Index, Symbol.Index),
7359) !void {
7381) Error!void {
73607382 const zcu = pt.zcu;
73617383 const gpa = zcu.gpa;
73627384 const ip = &zcu.intern_pool;
......@@ -7380,6 +7402,8 @@ fn updateExportInner(
73807402 exported_si,
73817403 }),
73827404 }
7405
7406 try coff.genPending(pt);
73837407 while (try coff.resolve(pt.tid)) {}
73847408 while (try coff.idle(pt.tid)) {}
73857409
......@@ -7444,7 +7468,7 @@ fn updateExportInner(
74447468 if (new_name_table_size > std.math.maxInt(@FieldType(ExportTable.Entry, "name_index")))
74457469 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
74497473 const name_table_slice = coff.export_table.name_table_ni.slice(&coff.mf);
74507474 @memcpy(name_table_slice[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]);
......@@ -7468,20 +7492,20 @@ fn updateExportInner(
74687492 // TODO: These should all be resized ahead of time to fit all exports
74697493 // after https://github.com/ziglang/zig/issues/23616
74707494 try coff.export_table.export_address_table_si.node(coff).resizeLeaf(
7471 &coff.mf,
74727495 gpa,
7496 &coff.mf,
74737497 export_count * @sizeOf(std.coff.ExportAddressTableEntry),
74747498 );
74757499
74767500 try coff.export_table.name_pointer_table_ni.resizeLeaf(
7477 &coff.mf,
74787501 gpa,
7502 &coff.mf,
74797503 export_count * @sizeOf(std.coff.ExportNamePointerTableEntry),
74807504 );
74817505
74827506 try coff.export_table.ordinal_table_ni.resizeLeaf(
7483 &coff.mf,
74847507 gpa,
7508 &coff.mf,
74857509 export_count * @sizeOf(std.coff.ExportOrdinalTableEntry),
74867510 );
74877511
......@@ -7519,17 +7543,19 @@ fn updateExportInner(
75197543 }
75207544}
75217545
7522fn dumpStderr(coff: *Coff, tid: Zcu.PerThread.Id) !void {
7546fn dumpStderr(coff: *Coff, tid: Zcu.PerThread.Id) Io.File.Writer.Error!void {
75237547 const comp = coff.base.comp;
75247548 const io = comp.io;
75257549 var buffer: [512]u8 = undefined;
75267550 const stderr = try io.lockStderr(&buffer, null);
75277551 defer io.unlockStderr();
75287552 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 };
75307556}
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 {
75337559 if (coff.options.enable_link_snapshots) {
75347560 try coff.printNode(tid, w, .root, 0);
75357561 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
75447570 return .disabled;
75457571}
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 {
75487574 const sym = si.get(coff);
75497575 try w.print("{d:0>6}@{d:0>2} {x:08} n{d:0>8} | {s}\n", .{
75507576 si,
......@@ -7560,7 +7586,7 @@ fn printSymbol(
75607586 w: *Io.Writer,
75617587 tid: Zcu.PerThread.Id,
75627588 si: Symbol.Index,
7563) !void {
7589) Io.Writer.Error!void {
75647590 const sym = si.get(coff);
75657591 try w.print("{d:0>6}@{d:0>2} {x:08} {s} {s} {s} n{d:0>8}+{x:08}:{s: <26} | {x:08} ", .{
75667592 si,
......@@ -7622,7 +7648,7 @@ fn printNodeName(
76227648 w: *std.Io.Writer,
76237649 tid: Zcu.PerThread.Id,
76247650 node: Node,
7625) !void {
7651) Io.Writer.Error!void {
76267652 switch (node) {
76277653 else => {},
76287654 .image_section => |si| try w.print("({s})", .{
......@@ -7702,7 +7728,7 @@ pub fn printNode(
77027728 w: *Io.Writer,
77037729 ni: MappedFile.Node.Index,
77047730 indent: usize,
7705) !void {
7731) Io.Writer.Error!void {
77067732 const node = coff.getNode(ni);
77077733 try w.splatByteAll(' ', indent);
77087734 try w.writeAll(@tagName(node));
......@@ -7710,12 +7736,13 @@ pub fn printNode(
77107736 {
77117737 const mf_node = &coff.mf.nodes.items[@backingInt(ni)];
77127738 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", .{
77147740 @backingInt(ni),
77157741 off,
77167742 size,
77177743 mf_node.flags.alignment.toByteUnits(),
77187744 mf_node.flags.position,
7745 if (mf_node.flags.bubbles_moved) " bubbles_moved" else "",
77197746 if (mf_node.flags.moved) " moved" else "",
77207747 if (mf_node.flags.resized) " resized" else "",
77217748 if (mf_node.flags.has_content) " has_content" else "",
......@@ -7730,22 +7757,30 @@ pub fn printNode(
77307757 }
77317758 return;
77327759 }
7733 const file_loc = ni.fileLocation(&coff.mf, false);
7734 if (file_loc.size == 0) return;
7735 var address = file_loc.offset;
7760 const start_address: usize, const end_address: usize = file_loc: {
7761 const file_loc = ni.fileLocation(&coff.mf, false);
7762 break :file_loc .{ @intCast(file_loc.offset), @intCast(file_loc.offset + file_loc.size) };
7763 };
7764 var address = start_address;
77367765 const line_len = 0x10;
7737 var line_it = std.mem.window(
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) {
7766 while (true) : (address = @min(std.mem.alignForward(usize, address + 1, line_len), end_address)) {
77447767 try w.splatByteAll(' ', indent + 1);
7745 try w.print("{x:0>8} ", .{address});
7746 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});
7747 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);
7748 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');
7768 try w.print("{x:0>8}", .{address});
7769 if (address == end_address) break try w.writeByte('\n');
7770 try w.splatByteAll(' ', 2);
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 });
77497784 try w.writeByte('\n');
77507785 }
77517786}
src/link/ConstPool.zig+38-12
......@@ -45,10 +45,22 @@ pub const Index = enum(u32) {
4545};
4646
4747pub const User = union(enum) {
48 dwarf: *@import("Dwarf.zig"),
48 elf: *@import("Dwarf.zig"),
49 elf2: *@import("Elf2.zig"),
50 macho: *@import("Dwarf.zig"),
4951 c: *@import("C.zig"),
5052 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
5264 /// Inform the debug info implementation that the new constant `val` was added to the pool at
5365 /// the given index (which equals the current pool length) due to a `get` call. It is guaranteed
5466 /// that there will eventually be a call to either `updateConst` or `updateConstIncomplete`
......@@ -58,9 +70,12 @@ pub const User = union(enum) {
5870 pt: Zcu.PerThread,
5971 index: Index,
6072 val: InternPool.Index,
61 ) Allocator.Error!void {
73 ) link.Error!void {
6274 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 },
6479 }
6580 }
6681
......@@ -73,9 +88,12 @@ pub const User = union(enum) {
7388 pt: Zcu.PerThread,
7489 index: Index,
7590 val: InternPool.Index,
76 ) Allocator.Error!void {
91 ) link.Error!void {
7792 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 },
7997 }
8098 }
8199
......@@ -89,9 +107,12 @@ pub const User = union(enum) {
89107 pt: Zcu.PerThread,
90108 index: Index,
91109 val: InternPool.Index,
92 ) Allocator.Error!void {
110 ) link.Error!void {
93111 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 },
95116 }
96117 }
97118};
......@@ -128,12 +149,12 @@ pub fn updateContainerType(
128149 user: User,
129150 container_ty: InternPool.Index,
130151 success: bool,
131) Allocator.Error!void {
152) link.Error!void {
132153 if (success) {
133154 const gpa = pt.zcu.comp.gpa;
134155 try pool.complete_containers.put(gpa, container_ty, {});
135156 } else {
136 _ = pool.complete_containers.fetchSwapRemove(container_ty);
157 _ = pool.complete_containers.swapRemove(container_ty);
137158 }
138159 var opt_dep = pool.container_deps.get(container_ty);
139160 while (opt_dep) |dep| : (opt_dep = dep.ptr(pool).next.unwrap()) {
......@@ -143,7 +164,7 @@ pub fn updateContainerType(
143164
144165/// After this is called, there may be a constant for which debug information (complete or not) has
145166/// 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 {
147168 const zcu = pt.zcu;
148169 const ip = &zcu.intern_pool;
149170 const gpa = zcu.comp.gpa;
......@@ -160,13 +181,16 @@ pub fn get(pool: *ConstPool, pt: Zcu.PerThread, user: User, val: InternPool.Inde
160181 }
161182 return index;
162183}
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 {
164188 while (pool.pending.pop()) |pending_ty| {
165189 try pool.update(pt, user, pending_ty);
166190 }
167191}
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 {
170194 const zcu = pt.zcu;
171195 const ip = &zcu.intern_pool;
172196 const val = index.val(pool);
......@@ -285,6 +309,8 @@ fn registerTypeDeps(pool: *ConstPool, root: Index, ty: Type, zcu: *const Zcu) Al
285309const std = @import("std");
286310const Allocator = std.mem.Allocator;
287311
312const dev = @import("../dev.zig");
288313const InternPool = @import("../InternPool.zig");
314const link = @import("../link.zig");
289315const Type = @import("../Type.zig");
290316const Zcu = @import("../Zcu.zig");
src/link/Dwarf.zig+135-121
......@@ -122,7 +122,7 @@ const DebugFrame = struct {
122122 uleb128Bytes(1) + 1,
123123 } + switch (target.cpu.arch) {
124124 .x86_64 => len: {
125 dev.check(.x86_64_backend);
125 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
126126 const Register = @import("../codegen/x86_64/bits.zig").Register;
127127 break :len uleb128Bytes(1) + sleb128Bytes(-8) + uleb128Bytes(Register.rip.dwarfNum()) +
128128 1 + uleb128Bytes(Register.rsp.dwarfNum()) + sleb128Bytes(-1) +
......@@ -1626,15 +1626,25 @@ pub const WipNav = struct {
16261626 wip_nav.any_children = true;
16271627 }
16281628
1629 pub fn advancePCAndLine(wip_nav: *WipNav, delta_line: i33, delta_pc: u64) Allocator.Error!void {
1630 return wip_nav.advancePCAndLineWriterError(delta_line, delta_pc) catch |err| switch (err) {
1629 pub fn advanceLineAndPc(
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) {
16311640 error.WriteFailed => error.OutOfMemory,
16321641 };
16331642 }
1634 fn advancePCAndLineWriterError(
1643 fn advanceLineAndPcWriterError(
16351644 wip_nav: *WipNav,
16361645 delta_line: i33,
16371646 delta_pc: u64,
1647 end: bool,
16381648 ) Writer.Error!void {
16391649 const dlw = &wip_nav.debug_line.writer;
16401650
......@@ -1654,20 +1664,30 @@ pub const WipNav = struct {
16541664 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
16551665 header.maximum_operations_per_instruction + delta_op;
16561666 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: {
1658 try dlw.writeByte(DW.LNS.advance_pc);
1659 try dlw.writeUleb128(op_advance);
1667 const remaining_op_advance: u8 = @intCast(if (end or
1668 op_advance >= 2 * max_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);
16601676 break :remaining 0;
16611677 } else if (op_advance >= max_op_advance) remaining: {
16621678 try dlw.writeByte(DW.LNS.const_add_pc);
16631679 break :remaining op_advance - max_op_advance;
16641680 } else op_advance);
16651681
1666 if (remaining_delta_line == 0 and remaining_op_advance == 0)
1667 try dlw.writeByte(DW.LNS.copy)
1668 else
1682 if (remaining_delta_line != 0 or remaining_op_advance != 0) {
1683 assert(!end);
16691684 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +
16701685 (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);
16711691 }
16721692
16731693 pub fn setColumn(wip_nav: *WipNav, column: u32) Allocator.Error!void {
......@@ -1990,7 +2010,7 @@ pub const WipNav = struct {
19902010 try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
19912011 }
19922012 } = .{ .wip_nav = wip_nav };
1993 try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end);
2013 try adapter.writer().writeUleb128(counter.dw.fullCount());
19942014 try loc.write(adapter);
19952015 }
19962016
......@@ -2032,7 +2052,7 @@ pub const WipNav = struct {
20322052 try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0);
20332053 }
20342054 } = .{ .wip_nav = wip_nav };
2035 try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end);
2055 try adapter.writer().writeUleb128(counter.dw.fullCount());
20362056 try loc.write(adapter);
20372057 }
20382058
......@@ -2072,7 +2092,7 @@ pub const WipNav = struct {
20722092 assert(value.typeOf(wip_nav.pt.zcu).comptimeOnly(wip_nav.pt.zcu));
20732093 }
20742094 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());
20762096 return dwarf.values.items[@backingInt(index)];
20772097 }
20782098
......@@ -2105,20 +2125,20 @@ pub const WipNav = struct {
21052125 const size = ty.abiSize(wip_nav.pt.zcu);
21062126 try diw.writeUleb128(size);
21072127 if (size == 0) return;
2108 const old_end = wip_nav.debug_info.writer.end;
2128 const old_end = diw.end;
21092129 try codegen.generateSymbol(
21102130 wip_nav.dwarf.bin_file,
21112131 wip_nav.pt,
21122132 val,
2113 &wip_nav.debug_info.writer,
2133 diw,
21142134 .{ .debug_output = .{ .dwarf = wip_nav } },
21152135 );
2116 if (old_end + size != wip_nav.debug_info.writer.end) {
2136 if (old_end + size != diw.end) {
21172137 std.debug.print("{f} [{}]: {} != {}\n", .{
21182138 ty.fmt(wip_nav.pt),
21192139 ty.toIntern(),
21202140 size,
2121 wip_nav.debug_info.writer.end - old_end,
2141 diw.end - old_end,
21222142 });
21232143 unreachable;
21242144 }
......@@ -2182,7 +2202,7 @@ pub const WipNav = struct {
21822202 wip_nav: *WipNav,
21832203 abbrev_code: struct {
21842204 decl: AbbrevCode,
2185 generic_decl: AbbrevCode,
2205 decl_specification: AbbrevCode,
21862206 decl_instance: AbbrevCode,
21872207 },
21882208 nav: *const InternPool.Nav,
......@@ -2196,11 +2216,11 @@ pub const WipNav = struct {
21962216
21972217 const orig_entry = wip_nav.entry;
21982218 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: {
22002220 const parent_type: Type = .fromInterned(zcu.namespacePtr(analysis.namespace).owner_type);
22012221 const decl_gop = try dwarf.decls.getOrPut(dwarf.gpa, analysis.zir_index);
22022222 errdefer _ = if (!decl_gop.found_existing) dwarf.decls.pop();
2203 const was_generic_decl = decl_gop.found_existing and
2223 const was_specification = decl_gop.found_existing and
22042224 switch (try dwarf.debug_info.declAbbrevCode(wip_nav.unit, decl_gop.value_ptr.*)) {
22052225 .null,
22062226 .decl_alias,
......@@ -2222,9 +2242,9 @@ pub const WipNav = struct {
22222242 .decl_extern_nullary_func,
22232243 .decl_extern_func,
22242244 => false,
2225 .generic_decl_var,
2226 .generic_decl_const,
2227 .generic_decl_func,
2245 .decl_specification_var,
2246 .decl_specification_const,
2247 .decl_specification_func,
22282248 => true,
22292249
22302250 // This comes from a decl which was previously generated as an incomplete value
......@@ -2235,11 +2255,11 @@ pub const WipNav = struct {
22352255 else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}),
22362256 };
22372257 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.*);
22392259 decl_gop.value_ptr.* = orig_entry;
22402260 break :parent_info .{ parent_type, false };
22412261 } else {
2242 if (was_generic_decl)
2262 if (was_specification)
22432263 dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(decl_gop.value_ptr.*).clear()
22442264 else
22452265 decl_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
......@@ -2248,8 +2268,8 @@ pub const WipNav = struct {
22482268 }
22492269 } else .{ null, false };
22502270
2251 try wip_nav.abbrevCode(if (is_generic_decl) abbrev_code.generic_decl else abbrev_code.decl);
2252 try wip_nav.refType((if (is_generic_decl) null else parent_type) orelse
2271 try wip_nav.abbrevCode(if (is_specification) abbrev_code.decl_specification else abbrev_code.decl);
2272 try wip_nav.refType((if (is_specification) null else parent_type) orelse
22532273 .fromInterned(zcu.fileRootType(file)));
22542274 assert(diw.end == DebugInfo.declEntryLineOff(dwarf));
22552275 try diw.writeInt(u32, decl.src_line + 1, dwarf.endian);
......@@ -2257,14 +2277,14 @@ pub const WipNav = struct {
22572277 try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
22582278 try wip_nav.strp(nav.name.toSlice(ip));
22592279
2260 if (!is_generic_decl) return;
2261 const generic_decl_entry = wip_nav.entry;
2262 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, generic_decl_entry, dwarf, wip_nav.debug_info.written());
2280 if (!is_specification) return;
2281 const specification_entry = wip_nav.entry;
2282 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, specification_entry, dwarf, wip_nav.debug_info.written());
22632283 wip_nav.debug_info.clearRetainingCapacity();
22642284 wip_nav.entry = orig_entry;
22652285 try wip_nav.abbrevCode(abbrev_code.decl_instance);
22662286 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);
22682288 }
22692289};
22702290
......@@ -2278,10 +2298,9 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
22782298
22792299pub fn init(lf: *link.File, format: DW.Format) Dwarf {
22802300 const comp = lf.comp;
2281 const gpa = comp.gpa;
22822301 const target = &comp.root_mod.resolved_target.result;
22832302 return .{
2284 .gpa = gpa,
2303 .gpa = comp.gpa,
22852304 .bin_file = lf,
22862305 .format = format,
22872306 .address_size = switch (target.ptrBitWidth()) {
......@@ -2566,7 +2585,7 @@ pub fn initWipNav(
25662585 pt: Zcu.PerThread,
25672586 nav_index: InternPool.Nav.Index,
25682587 sym_index: link.File.SymbolId,
2569) error{ OutOfMemory, AlreadyReported }!WipNav {
2588) link.Error!WipNav {
25702589 return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) {
25712590 error.OutOfMemory => error.OutOfMemory,
25722591 else => |e| pt.zcu.codegenFail(nav_index, "failed to init dwarf: {s}", .{@errorName(e)}),
......@@ -2661,11 +2680,11 @@ fn initWipNavInner(
26612680 const diw = &wip_nav.debug_info.writer;
26622681 try wip_nav.declCommon(if (func_type.param_types.len > 0 or func_type.is_var_args) .{
26632682 .decl = .decl_extern_func,
2664 .generic_decl = .generic_decl_func,
2683 .decl_specification = .decl_specification_func,
26652684 .decl_instance = .decl_instance_extern_func,
26662685 } else .{
26672686 .decl = .decl_extern_nullary_func,
2668 .generic_decl = .generic_decl_func,
2687 .decl_specification = .decl_specification_func,
26692688 .decl_instance = .decl_instance_extern_nullary_func,
26702689 }, &nav, inst_info.file, &decl);
26712690 try wip_nav.strp(@"extern".name.toSlice(ip));
......@@ -2686,7 +2705,7 @@ fn initWipNavInner(
26862705 .func => |func| if (func.owner_nav != nav_index) {
26872706 try wip_nav.declCommon(.{
26882707 .decl = .decl_alias,
2689 .generic_decl = .generic_decl_const,
2708 .decl_specification = .decl_specification_const,
26902709 .decl_instance = .decl_instance_alias,
26912710 }, &nav, inst_info.file, &decl);
26922711 try wip_nav.refNav(func.owner_nav);
......@@ -2739,7 +2758,7 @@ fn initWipNavInner(
27392758 const diw = &wip_nav.debug_info.writer;
27402759 try wip_nav.declCommon(.{
27412760 .decl = .decl_func,
2742 .generic_decl = .generic_decl_func,
2761 .decl_specification = .decl_specification_func,
27432762 .decl_instance = .decl_instance_func,
27442763 }, &nav, inst_info.file, &decl);
27452764 try wip_nav.strp(switch (decl.linkage) {
......@@ -2774,7 +2793,7 @@ fn initWipNavInner(
27742793 try dlw.writeByte(DW.LNS.set_column);
27752794 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);
27782797 } else {
27792798 try dlw.writeUleb128(1 + @backingInt(dwarf.address_size));
27802799 try dlw.writeByte(DW.LNE.set_address);
......@@ -2791,17 +2810,17 @@ fn initWipNavInner(
27912810 try dlw.writeByte(DW.LNS.set_column);
27922811 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);
27952814 }
27962815 },
27972816 else => {
27982817 const diw = &wip_nav.debug_info.writer;
27992818 try wip_nav.declCommon(.{
28002819 .decl = .decl_var,
2801 .generic_decl = switch (decl.kind) {
2820 .decl_specification = switch (decl.kind) {
28022821 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
2803 .@"const" => .generic_decl_const,
2804 .@"var" => .generic_decl_var,
2822 .@"const" => .decl_specification_const,
2823 .@"var" => .decl_specification_var,
28052824 },
28062825 .decl_instance = .decl_instance_var,
28072826 }, &nav, inst_info.file, &decl);
......@@ -2983,19 +3002,13 @@ fn finishWipNavWriterError(
29833002 log.debug("finishWipNav({f})", .{nav.fqn.fmt(ip)});
29843003
29853004 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;
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 }
3005 try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.written());
29933006 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());
29963009}
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 {
29993012 return updateComptimeNavInner(dwarf, pt, nav_index) catch |err| switch (err) {
30003013 error.OutOfMemory => error.OutOfMemory,
30013014 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
30543067 const loaded_struct = ip.loadStructType(nav_val.toIntern());
30553068 if (nav_index.toOptional() == loaded_struct.name_nav) {
30563069 // 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());
3058 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
3070 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
3071 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
30593072 return;
30603073 }
30613074 break :tag .alias;
......@@ -3064,8 +3077,8 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
30643077 const loaded_enum = ip.loadEnumType(nav_val.toIntern());
30653078 if (nav_index.toOptional() == loaded_enum.name_nav) {
30663079 // 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());
3068 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
3080 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
3081 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
30693082 return;
30703083 }
30713084 break :tag .alias;
......@@ -3074,8 +3087,8 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
30743087 const loaded_union = ip.loadUnionType(nav_val.toIntern());
30753088 if (nav_index.toOptional() == loaded_union.name_nav) {
30763089 // 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());
3078 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
3090 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
3091 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
30793092 return;
30803093 }
30813094 break :tag .alias;
......@@ -3084,8 +3097,8 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
30843097 const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
30853098 if (nav_index.toOptional() == loaded_opaque.name_nav) {
30863099 // 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());
3088 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
3100 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
3101 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
30893102 return;
30903103 }
30913104 break :tag .alias;
......@@ -3168,7 +3181,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
31683181 .alias => {
31693182 try wip_nav.declCommon(.{
31703183 .decl = .decl_alias,
3171 .generic_decl = .generic_decl_const,
3184 .decl_specification = .decl_specification_const,
31723185 .decl_instance = .decl_instance_alias,
31733186 }, &nav, inst_info.file, &decl);
31743187 try wip_nav.refType(nav_val.toType());
......@@ -3176,7 +3189,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
31763189 .@"var" => {
31773190 try wip_nav.declCommon(.{
31783191 .decl = .decl_var,
3179 .generic_decl = .generic_decl_var,
3192 .decl_specification = .decl_specification_var,
31803193 .decl_instance = .decl_instance_var,
31813194 }, &nav, inst_info.file, &decl);
31823195 try wip_nav.strp(switch (decl.linkage) {
......@@ -3196,19 +3209,19 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
31963209 const has_comptime_state = nav_ty.comptimeOnly(zcu);
31973210 try wip_nav.declCommon(if (has_runtime_bits and has_comptime_state) .{
31983211 .decl = .decl_const_runtime_bits_comptime_state,
3199 .generic_decl = .generic_decl_const,
3212 .decl_specification = .decl_specification_const,
32003213 .decl_instance = .decl_instance_const_runtime_bits_comptime_state,
32013214 } else if (has_comptime_state) .{
32023215 .decl = .decl_const_comptime_state,
3203 .generic_decl = .generic_decl_const,
3216 .decl_specification = .decl_specification_const,
32043217 .decl_instance = .decl_instance_const_comptime_state,
32053218 } else if (has_runtime_bits) .{
32063219 .decl = .decl_const_runtime_bits,
3207 .generic_decl = .generic_decl_const,
3220 .decl_specification = .decl_specification_const,
32083221 .decl_instance = .decl_instance_const_runtime_bits,
32093222 } else .{
32103223 .decl = .decl_const,
3211 .generic_decl = .generic_decl_const,
3224 .decl_specification = .decl_specification_const,
32123225 .decl_instance = .decl_instance_const,
32133226 }, &nav, inst_info.file, &decl);
32143227 try wip_nav.strp(switch (decl.linkage) {
......@@ -3232,11 +3245,11 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
32323245 } else true;
32333246 try wip_nav.declCommon(if (is_nullary) .{
32343247 .decl = .decl_nullary_func_generic,
3235 .generic_decl = .generic_decl_func,
3248 .decl_specification = .decl_specification_func,
32363249 .decl_instance = .decl_instance_nullary_func_generic,
32373250 } else .{
32383251 .decl = .decl_func_generic,
3239 .generic_decl = .generic_decl_func,
3252 .decl_specification = .decl_specification_func,
32403253 .decl_instance = .decl_instance_func_generic,
32413254 }, &nav, inst_info.file, &decl);
32423255 try wip_nav.refType(.fromInterned(func_type.return_type));
......@@ -3254,14 +3267,14 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
32543267 .func_alias => |owner_nav| {
32553268 try wip_nav.declCommon(.{
32563269 .decl = .decl_alias,
3257 .generic_decl = .generic_decl_const,
3270 .decl_specification = .decl_specification_const,
32583271 .decl_instance = .decl_instance_alias,
32593272 }, &nav, inst_info.file, &decl);
32603273 try wip_nav.refNav(owner_nav);
32613274 },
32623275 }
32633276 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());
32653278}
32663279
32673280pub fn updateContainerType(
......@@ -3270,7 +3283,7 @@ pub fn updateContainerType(
32703283 ty: InternPool.Index,
32713284 success: bool,
32723285) !void {
3273 try dwarf.const_pool.updateContainerType(pt, .{ .dwarf = dwarf }, ty, success);
3286 try dwarf.const_pool.updateContainerType(pt, dwarf.constPoolUser(), ty, success);
32743287}
32753288/// Should only be called by the `link.ConstPool` implementation.
32763289pub 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
33743387 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file_index);
33753388 try wip_nav.abbrevCode(.empty_file);
33763389 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));
33783391 } else {
33793392 try dwarf.emitIncompleteContainerType(
33803393 &wip_nav,
33813394 loaded_struct.zir_index,
3382 loaded_struct.name,
3395 loaded_struct.fqn,
33833396 loaded_struct.name_nav,
33843397 );
33853398 }
......@@ -3389,7 +3402,7 @@ fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_inde
33893402 try dwarf.emitIncompleteContainerType(
33903403 &wip_nav,
33913404 loaded_union.zir_index,
3392 loaded_union.name,
3405 loaded_union.fqn,
33933406 loaded_union.name_nav,
33943407 );
33953408 },
......@@ -3399,12 +3412,12 @@ fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_inde
33993412 try dwarf.emitIncompleteContainerType(
34003413 &wip_nav,
34013414 zir_index,
3402 loaded_enum.name,
3415 loaded_enum.fqn,
34033416 loaded_enum.name_nav,
34043417 );
34053418 } else {
34063419 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));
34083421 try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
34093422 }
34103423 },
......@@ -3413,7 +3426,7 @@ fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_inde
34133426 try dwarf.emitIncompleteContainerType(
34143427 &wip_nav,
34153428 loaded_opaque.zir_index,
3416 loaded_opaque.name,
3429 loaded_opaque.fqn,
34173430 loaded_opaque.name_nav,
34183431 );
34193432 },
......@@ -3438,7 +3451,7 @@ fn emitIncompleteContainerType(
34383451 dwarf: *Dwarf,
34393452 wip_nav: *WipNav,
34403453 zir_index: InternPool.TrackedInst.Index,
3441 name: InternPool.NullTerminatedString,
3454 fqn: InternPool.NullTerminatedString,
34423455 name_nav: InternPool.Nav.Index.Optional,
34433456) !void {
34443457 const zcu = wip_nav.pt.zcu;
......@@ -3450,7 +3463,7 @@ fn emitIncompleteContainerType(
34503463 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
34513464 try wip_nav.declCommon(.{
34523465 .decl = .decl_namespace_struct,
3453 .generic_decl = .generic_decl_const,
3466 .decl_specification = .decl_specification_const,
34543467 .decl_instance = .decl_instance_namespace_struct,
34553468 }, &nav, file, &decl);
34563469 try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
......@@ -3459,7 +3472,7 @@ fn emitIncompleteContainerType(
34593472 const file_gop = try dwarf.getModInfo(wip_nav.unit).files.getOrPut(dwarf.gpa, file);
34603473 try wip_nav.abbrevCode(.empty_struct_type);
34613474 try diw.writeUleb128(file_gop.index);
3462 try wip_nav.strp(name.toSlice(ip));
3475 try wip_nav.strp(fqn.toSlice(ip));
34633476 try diw.writeByte(@intFromBool(true));
34643477 }
34653478}
......@@ -3868,11 +3881,11 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
38683881 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
38693882 try wip_nav.declCommon(if (loaded_struct.field_types.len == 0) .{
38703883 .decl = .decl_namespace_struct,
3871 .generic_decl = .generic_decl_const,
3884 .decl_specification = .decl_specification_const,
38723885 .decl_instance = .decl_instance_namespace_struct,
38733886 } else .{
38743887 .decl = .decl_struct,
3875 .generic_decl = .generic_decl_const,
3888 .decl_specification = .decl_specification_const,
38763889 .decl_instance = .decl_instance_struct,
38773890 }, &nav, file, &decl);
38783891 } else {
......@@ -3882,7 +3895,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
38823895 else => if (struct_is_file) .file else .struct_type,
38833896 });
38843897 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));
38863899 }
38873900 if (loaded_struct.field_types.len == 0) {
38883901 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
39473960 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
39483961 try wip_nav.declCommon(.{
39493962 .decl = .decl_packed_struct,
3950 .generic_decl = .generic_decl_const,
3963 .decl_specification = .decl_specification_const,
39513964 .decl_instance = .decl_instance_packed_struct,
39523965 }, &nav, file, &decl);
39533966 break :t true;
......@@ -3955,7 +3968,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
39553968 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
39563969 try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type);
39573970 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));
39593972 break :t loaded_struct.field_types.len > 0;
39603973 };
39613974 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
39843997 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
39853998 try wip_nav.declCommon(.{
39863999 .decl = .decl_union,
3987 .generic_decl = .generic_decl_const,
4000 .decl_specification = .decl_specification_const,
39884001 .decl_instance = .decl_instance_union,
39894002 }, &nav, file, &decl);
39904003 break :t true;
......@@ -3992,7 +4005,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
39924005 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
39934006 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);
39944007 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));
39964009 break :t loaded_union.field_types.len > 0;
39974010 };
39984011 const union_layout = Type.getUnionLayout(loaded_union, zcu);
......@@ -4046,7 +4059,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
40464059 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
40474060 try wip_nav.declCommon(.{
40484061 .decl = .decl_packed_union,
4049 .generic_decl = .generic_decl_const,
4062 .decl_specification = .decl_specification_const,
40504063 .decl_instance = .decl_instance_packed_union,
40514064 }, &nav, file, &decl);
40524065 break :t true;
......@@ -4054,7 +4067,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
40544067 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
40554068 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .packed_union_type else .empty_packed_union_type);
40564069 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));
40584071 break :t loaded_union.field_types.len > 0;
40594072 };
40604073 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
40794092 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
40804093 try wip_nav.declCommon(if (loaded_enum.field_names.len > 0) .{
40814094 .decl = .decl_enum,
4082 .generic_decl = .generic_decl_const,
4095 .decl_specification = .decl_specification_const,
40834096 .decl_instance = .decl_instance_enum,
40844097 } else .{
40854098 .decl = .decl_empty_enum,
4086 .generic_decl = .generic_decl_const,
4099 .decl_specification = .decl_specification_const,
40874100 .decl_instance = .decl_instance_empty_enum,
40884101 }, &nav, file, &decl);
40894102 } else {
40904103 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
40914104 try wip_nav.abbrevCode(if (loaded_enum.field_names.len > 0) .enum_type else .empty_enum_type);
40924105 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));
40944107 }
40954108 try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
40964109 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
41024115 } else {
41034116 assert(loaded_enum.owner_union != .none);
41044117 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));
41064119 try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
41074120 for (0..loaded_enum.field_names.len) |field_index| {
41084121 try wip_nav.abbrevCode(.enum_field);
......@@ -4121,14 +4134,14 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
41214134 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
41224135 try wip_nav.declCommon(.{
41234136 .decl = .decl_namespace_struct,
4124 .generic_decl = .generic_decl_const,
4137 .decl_specification = .decl_specification_const,
41254138 .decl_instance = .decl_instance_namespace_struct,
41264139 }, &nav, file, &decl);
41274140 } else {
41284141 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
41294142 try wip_nav.abbrevCode(.empty_struct_type);
41304143 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));
41324145 }
41334146 try diw.writeByte(@intFromBool(true));
41344147 },
......@@ -4614,6 +4627,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
46144627 }
46154628 try diw.writeUleb128(@backingInt(AbbrevCode.null));
46164629 },
4630
46174631 .memoized_call => unreachable, // not a value
46184632 }
46194633 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
46324646 };
46334647}
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 {
46364650 const comp = dwarf.bin_file.comp;
46374651 const io = comp.io;
46384652 const ip = &zcu.intern_pool;
46394653
46404654 const inst_info = zir_index.resolveFull(ip).?;
4641 assert(inst_info.inst != .main_struct_inst);
4655 if (inst_info.inst == .main_struct_inst) return;
46424656 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
46524658 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
46554661 const unit = dwarf.debug_info.section.getUnit(dwarf.getUnitIfExists(file.mod.?) orelse return);
46564662 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
46964702
46974703 // Update `anyerror` based on the finished global error set.
46984704 {
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);
47004706 const unit, const entry = dwarf.values.items[@backingInt(index)];
47014707 var wip_nav: WipNav = .{
47024708 .dwarf = dwarf,
......@@ -4731,7 +4737,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Err
47314737 }
47324738 if (global_error_set_names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null));
47334739 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());
47354741 }
47364742
47374743 for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {
......@@ -4783,7 +4789,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Err
47834789 .debug_frame => unreachable,
47844790 .eh_frame => switch (target.cpu.arch) {
47854791 .x86_64 => {
4786 dev.check(.x86_64_backend);
4792 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
47874793 const Register = @import("../codegen/x86_64/bits.zig").Register;
47884794 for (dwarf.debug_frame.section.units.items) |*unit| {
47894795 header_aw.clearRetainingCapacity();
......@@ -5131,9 +5137,9 @@ const AbbrevCode = enum {
51315137 decl_func_generic,
51325138 decl_extern_nullary_func,
51335139 decl_extern_func,
5134 generic_decl_var,
5135 generic_decl_const,
5136 generic_decl_func,
5140 decl_specification_var,
5141 decl_specification_const,
5142 decl_specification_func,
51375143 decl_instance_alias,
51385144 decl_instance_empty_enum,
51395145 decl_instance_enum,
......@@ -5257,7 +5263,7 @@ const AbbrevCode = enum {
52575263 .{ .accessibility, .data1 },
52585264 .{ .name, .strp },
52595265 };
5260 const generic_decl_abbrev_common_attrs = decl_abbrev_common_attrs ++ &[_]Attr{
5266 const decl_specification_abbrev_common_attrs = decl_abbrev_common_attrs ++ &[_]Attr{
52615267 .{ .declaration, .flag_present },
52625268 };
52635269 const decl_instance_abbrev_common_attrs = &[_]Attr{
......@@ -5442,17 +5448,17 @@ const AbbrevCode = enum {
54425448 .{ .noreturn, .flag },
54435449 },
54445450 },
5445 .generic_decl_var = .{
5451 .decl_specification_var = .{
54465452 .tag = .variable,
5447 .attrs = generic_decl_abbrev_common_attrs,
5453 .attrs = decl_specification_abbrev_common_attrs,
54485454 },
5449 .generic_decl_const = .{
5455 .decl_specification_const = .{
54505456 .tag = .constant,
5451 .attrs = generic_decl_abbrev_common_attrs,
5457 .attrs = decl_specification_abbrev_common_attrs,
54525458 },
5453 .generic_decl_func = .{
5459 .decl_specification_func = .{
54545460 .tag = .subprogram,
5455 .attrs = generic_decl_abbrev_common_attrs,
5461 .attrs = decl_specification_abbrev_common_attrs,
54565462 },
54575463 .decl_instance_alias = .{
54585464 .tag = .imported_declaration,
......@@ -6301,6 +6307,14 @@ fn getFile(dwarf: *Dwarf) ?Io.File {
63016307 return dwarf.bin_file.file;
63026308}
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
63046318fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {
63056319 const entry = try dwarf.debug_aranges.section.getUnit(unit).addEntry(dwarf.gpa);
63066320 assert(try dwarf.debug_frame.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
......@@ -6362,14 +6376,14 @@ fn uleb128Bytes(value: anytype) u32 {
63626376 var buf: [64]u8 = undefined;
63636377 var dw: Writer.Discarding = .init(&buf);
63646378 dw.writer.writeUleb128(value) catch unreachable;
6365 return @intCast(dw.count + dw.writer.end);
6379 return @intCast(dw.fullCount());
63666380}
63676381
63686382fn sleb128Bytes(value: anytype) u32 {
63696383 var buf: [64]u8 = undefined;
63706384 var dw: Writer.Discarding = .init(&buf);
63716385 dw.writer.writeSleb128(value) catch unreachable;
6372 return @intCast(dw.count + dw.writer.end);
6386 return @intCast(dw.fullCount());
63736387}
63746388
63756389/// 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(
16771677 ty: InternPool.Index,
16781678 success: bool,
16791679) link.Error!void {
1680 return self.zigObjectPtr().?.updateContainerType(pt, ty, success) catch |err| switch (err) {
1681 error.OutOfMemory => |e| return e,
1682 };
1680 try self.zigObjectPtr().?.updateContainerType(pt, ty, success);
16831681}
16841682
16851683pub fn updateExports(
......@@ -1690,8 +1688,8 @@ pub fn updateExports(
16901688 return self.zigObjectPtr().?.updateExports(self, pt, export_indices);
16911689}
16921690
1693pub fn updateLineNumber(self: *Elf, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) link.Error!void {
1694 return self.zigObjectPtr().?.updateLineNumber(pt, ti_id);
1691pub fn updateLineNumber(self: *Elf, pt: Zcu.PerThread, inst: InternPool.TrackedInst.Index, line: u32) link.Error!void {
1692 return self.zigObjectPtr().?.updateLineNumber(pt, inst, line);
16951693}
16961694
16971695fn checkDuplicates(self: *Elf) !void {
......@@ -4412,7 +4410,6 @@ const Path = std.Build.Cache.Path;
44124410const Stat = std.Build.Cache.File.Stat;
44134411
44144412const codegen = @import("../codegen.zig");
4415const dev = @import("../dev.zig");
44164413const eh_frame = @import("Elf/eh_frame.zig");
44174414const gc = @import("Elf/gc.zig");
44184415const musl = @import("../libs/musl.zig");
src/link/Elf/Atom.zig+17-11
......@@ -945,7 +945,7 @@ const x86_64 = struct {
945945 code: ?[]const u8,
946946 it: *RelocsIterator,
947947 ) !void {
948 dev.check(.x86_64_backend);
948 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
949949 const t = &elf_file.base.comp.root_mod.resolved_target.result;
950950 const is_static = elf_file.base.isStatic();
951951 const is_dyn_lib = elf_file.isEffectivelyDynLib();
......@@ -1059,7 +1059,7 @@ const x86_64 = struct {
10591059 it: *RelocsIterator,
10601060 code: []u8,
10611061 ) !void {
1062 dev.check(.x86_64_backend);
1062 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
10631063 const t = &elf_file.base.comp.root_mod.resolved_target.result;
10641064 const diags = &elf_file.base.comp.link_diags;
10651065 const r_type: elf.R_X86_64 = @fromBackingInt(@intCast(rel.r_type()));
......@@ -1200,7 +1200,7 @@ const x86_64 = struct {
12001200 args: ResolveArgs,
12011201 code: []u8,
12021202 ) !void {
1203 dev.check(.x86_64_backend);
1203 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
12041204 const r_type: elf.R_X86_64 = @fromBackingInt(@intCast(rel.r_type()));
12051205
12061206 _, const A, const S, const GOT, _, _, const DTP = args;
......@@ -1240,7 +1240,7 @@ const x86_64 = struct {
12401240 }
12411241
12421242 fn relaxGotpcrelx(code: []u8, t: *const std.Target) !void {
1243 dev.check(.x86_64_backend);
1243 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
12441244 const old_inst = disassemble(code) orelse return error.RelaxFailure;
12451245 const inst: Instruction = switch (old_inst.encoding.mnemonic) {
12461246 .call => try .new(old_inst.prefix, .call, &.{
......@@ -1259,7 +1259,7 @@ const x86_64 = struct {
12591259 }
12601260
12611261 fn relaxRexGotpcrelx(code: []u8, t: *const std.Target) !void {
1262 dev.check(.x86_64_backend);
1262 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
12631263 const old_inst = disassemble(code) orelse return error.RelaxFailure;
12641264 switch (old_inst.encoding.mnemonic) {
12651265 .mov => {
......@@ -1279,7 +1279,7 @@ const x86_64 = struct {
12791279 code: []u8,
12801280 r_offset: usize,
12811281 ) !void {
1282 dev.check(.x86_64_backend);
1282 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
12831283 assert(rels.len == 2);
12841284 const diags = &elf_file.base.comp.link_diags;
12851285 const rel: elf.R_X86_64 = @fromBackingInt(@intCast(rels[1].r_type()));
......@@ -1319,7 +1319,7 @@ const x86_64 = struct {
13191319 code: []u8,
13201320 r_offset: usize,
13211321 ) !void {
1322 dev.check(.x86_64_backend);
1322 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
13231323 assert(rels.len == 2);
13241324 const diags = &elf_file.base.comp.link_diags;
13251325 const rel: elf.R_X86_64 = @fromBackingInt(@intCast(rels[1].r_type()));
......@@ -1366,7 +1366,7 @@ const x86_64 = struct {
13661366 }
13671367
13681368 fn canRelaxGotTpOff(code: []const u8, t: *const std.Target) bool {
1369 dev.check(.x86_64_backend);
1369 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
13701370 const old_inst = disassemble(code) orelse return false;
13711371 switch (old_inst.encoding.mnemonic) {
13721372 .mov => {
......@@ -1384,7 +1384,7 @@ const x86_64 = struct {
13841384 }
13851385
13861386 fn relaxGotTpOff(code: []u8, t: *const std.Target) void {
1387 dev.check(.x86_64_backend);
1387 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
13881388 const old_inst = disassemble(code) orelse unreachable;
13891389 switch (old_inst.encoding.mnemonic) {
13901390 .mov => {
......@@ -1401,7 +1401,7 @@ const x86_64 = struct {
14011401 }
14021402
14031403 fn relaxGotPcTlsDesc(code: []u8, target: *const std.Target) !void {
1404 dev.check(.x86_64_backend);
1404 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
14051405 const old_inst = disassemble(code) orelse return error.RelaxFailure;
14061406 switch (old_inst.encoding.mnemonic) {
14071407 .lea => {
......@@ -1425,7 +1425,7 @@ const x86_64 = struct {
14251425 code: []u8,
14261426 r_offset: usize,
14271427 ) !void {
1428 dev.check(.x86_64_backend);
1428 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
14291429 assert(rels.len == 2);
14301430 const diags = &elf_file.base.comp.link_diags;
14311431 const rel: elf.R_X86_64 = @fromBackingInt(@intCast(rels[1].r_type()));
......@@ -1492,6 +1492,7 @@ const aarch64 = struct {
14921492 ) !void {
14931493 _ = code;
14941494 _ = it;
1495 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
14951496
14961497 const r_type: elf.R_AARCH64 = @fromBackingInt(@intCast(rel.r_type()));
14971498 const is_dyn_lib = elf_file.isEffectivelyDynLib();
......@@ -1569,6 +1570,7 @@ const aarch64 = struct {
15691570 code_buffer: []u8,
15701571 ) (error{ UnexpectedRemainder, DivisionByZero } || RelocError)!void {
15711572 _ = it;
1573 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
15721574
15731575 const diags = &elf_file.base.comp.link_diags;
15741576 const r_type: elf.R_AARCH64 = @fromBackingInt(@intCast(rel.r_type()));
......@@ -1742,6 +1744,7 @@ const aarch64 = struct {
17421744 args: ResolveArgs,
17431745 code: []u8,
17441746 ) !void {
1747 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
17451748 const r_type: elf.R_AARCH64 = @fromBackingInt(@intCast(rel.r_type()));
17461749
17471750 _, const A, const S, _, _, _, _ = args;
......@@ -1772,6 +1775,7 @@ const riscv = struct {
17721775 ) !void {
17731776 _ = code;
17741777 _ = it;
1778 dev.checkAny(&.{ .llvm_backend, .riscv64_backend });
17751779
17761780 const r_type: elf.R_RISCV = @fromBackingInt(@intCast(rel.r_type()));
17771781
......@@ -1815,6 +1819,7 @@ const riscv = struct {
18151819 it: *RelocsIterator,
18161820 code: []u8,
18171821 ) !void {
1822 dev.checkAny(&.{ .llvm_backend, .riscv64_backend });
18181823 const diags = &elf_file.base.comp.link_diags;
18191824 const r_type: elf.R_RISCV = @fromBackingInt(@intCast(rel.r_type()));
18201825 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
......@@ -1951,6 +1956,7 @@ const riscv = struct {
19511956 args: ResolveArgs,
19521957 code: []u8,
19531958 ) !void {
1959 dev.checkAny(&.{ .llvm_backend, .riscv64_backend });
19541960 const r_type: elf.R_RISCV = @fromBackingInt(@intCast(rel.r_type()));
19551961
19561962 _, 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
12361236
12371237 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {
12381238 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();
12391243 switch (chdr.ch_type) {
12401244 .ZLIB => {
1241 var stream: std.Io.Reader = .fixed(data[@sizeOf(elf.Elf64_Chdr)..]);
1242 var zlib_stream: std.compress.flate.Decompress = .init(&stream, .zlib, &.{});
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();
1245 var decompress: std.compress.flate.Decompress = .init(&compressed_reader, .zlib, &.{});
1246 _ = try decompress.reader.streamRemaining(&aw.writer);
12491247 },
12501248 .ZSTD => {
1251 var input: std.Io.Reader = .fixed(data[@sizeOf(elf.Elf64_Chdr)..]);
1252 var stream: std.compress.zstd.Decompress = .init(&input, &.{}, .{});
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();
1249 var decompress: std.compress.zstd.Decompress = .init(&compressed_reader, &.{}, .{});
1250 _ = try decompress.reader.streamRemaining(&aw.writer);
12591251 },
12601252 else => @panic("TODO unhandled compression scheme"),
12611253 }
1254 return aw.toOwnedSlice();
12621255 }
12631256
12641257 return data;
......@@ -1492,7 +1485,7 @@ const Format = struct {
14921485 object: *Object,
14931486 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 {
14961489 const object = f.object;
14971490 const elf_file = f.elf_file;
14981491 try writer.writeAll(" locals\n");
......@@ -1511,7 +1504,7 @@ const Format = struct {
15111504 }
15121505 }
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 {
15151508 const object = f.object;
15161509 try writer.writeAll(" atoms\n");
15171510 for (object.atoms_indexes.items) |atom_index| {
......@@ -1520,7 +1513,7 @@ const Format = struct {
15201513 }
15211514 }
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 {
15241517 const object = f.object;
15251518 try writer.writeAll(" cies\n");
15261519 for (object.cies.items, 0..) |cie, i| {
......@@ -1528,7 +1521,7 @@ const Format = struct {
15281521 }
15291522 }
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 {
15321525 const object = f.object;
15331526 try writer.writeAll(" fdes\n");
15341527 for (object.fdes.items, 0..) |fde, i| {
......@@ -1536,7 +1529,7 @@ const Format = struct {
15361529 }
15371530 }
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 {
15401533 const object = f.object;
15411534 const elf_file = f.elf_file;
15421535 try writer.writeAll(" groups\n");
......@@ -1586,7 +1579,7 @@ pub fn fmtPath(self: Object) std.fmt.Alt(Object, formatPath) {
15861579 return .{ .data = self };
15871580}
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 {
15901583 if (object.archive) |ar| {
15911584 try writer.print("{f}({f})", .{ ar.path, object.path });
15921585 } else {
src/link/Elf/Thunk.zig+2
......@@ -91,6 +91,7 @@ pub const Index = u32;
9191
9292const aarch64 = struct {
9393 fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
94 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
9495 for (thunk.symbols.keys(), 0..) |ref, i| {
9596 const sym = elf_file.symbol(ref).?;
9697 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));
......@@ -113,6 +114,7 @@ const aarch64 = struct {
113114};
114115
115116const assert = std.debug.assert;
117const dev = @import("../../dev.zig");
116118const elf = std.elf;
117119const log = std.log.scoped(.link);
118120const math = std.math;
src/link/Elf/ZigObject.zig+14-18
......@@ -946,14 +946,11 @@ pub fn getNavVAddr(
946946 .r_addend = reloc_info.addend,
947947 }, self);
948948 },
949 .debug_output => |debug_output| switch (debug_output) {
950 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
951 .source_off = @intCast(reloc_info.offset),
952 .target_sym = @fromBackingInt(@intCast(this_sym_index)),
953 .target_off = reloc_info.addend,
954 }),
955 .none => unreachable,
956 },
949 .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
950 .source_off = @intCast(reloc_info.offset),
951 .target_sym = @fromBackingInt(@intCast(this_sym_index)),
952 .target_off = reloc_info.addend,
953 }),
957954 }
958955 return @intCast(vaddr);
959956}
......@@ -978,14 +975,11 @@ pub fn getUavVAddr(
978975 .r_addend = reloc_info.addend,
979976 }, self);
980977 },
981 .debug_output => |debug_output| switch (debug_output) {
982 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
983 .source_off = @intCast(reloc_info.offset),
984 .target_sym = @fromBackingInt(@intCast(sym_index)),
985 .target_off = reloc_info.addend,
986 }),
987 .none => unreachable,
988 },
978 .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
979 .source_off = @intCast(reloc_info.offset),
980 .target_sym = @fromBackingInt(@intCast(sym_index)),
981 .target_off = reloc_info.addend,
982 }),
989983 }
990984 return @intCast(vaddr);
991985}
......@@ -1952,11 +1946,11 @@ pub fn updateExports(
19521946 }
19531947}
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 {
19561950 if (self.dwarf) |*dwarf| {
19571951 const comp = dwarf.bin_file.comp;
19581952 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) {
19601954 error.OutOfMemory, error.Canceled, error.AlreadyReported => |e| return e,
19611955 else => |e| return diags.fail("failed to update dwarf line numbers: {s}", .{@errorName(e)}),
19621956 };
......@@ -2402,6 +2396,7 @@ const TlsTable = std.array_hash_map.Auto(Atom.Index, void);
24022396
24032397const x86_64 = struct {
24042398 fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 {
2399 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
24052400 const disp = @as(i64, @intCast(target_addr)) - source_addr - 5;
24062401 var bytes = [_]u8{
24072402 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel32
......@@ -2417,6 +2412,7 @@ const assert = std.debug.assert;
24172412const build_options = @import("build_options");
24182413const builtin = @import("builtin");
24192414const codegen = @import("../../codegen.zig");
2415const dev = @import("../../dev.zig");
24202416const elf = std.elf;
24212417const link = @import("../../link.zig");
24222418const 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 {
535535
536536const x86_64 = struct {
537537 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 });
538539 const r_type: elf.R_X86_64 = @fromBackingInt(@intCast(rel.r_type()));
539540 switch (r_type) {
540541 .NONE => {},
......@@ -549,6 +550,7 @@ const x86_64 = struct {
549550
550551const aarch64 = struct {
551552 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 });
552554 const r_type: elf.R_AARCH64 = @fromBackingInt(@intCast(rel.r_type()));
553555 switch (r_type) {
554556 .NONE => {},
......@@ -562,6 +564,7 @@ const aarch64 = struct {
562564
563565const riscv = struct {
564566 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 });
565568 const r_type: elf.R_RISCV = @fromBackingInt(@intCast(rel.r_type()));
566569 switch (r_type) {
567570 .NONE => {},
......@@ -584,6 +587,7 @@ fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void {
584587
585588const std = @import("std");
586589const assert = std.debug.assert;
590const dev = @import("../../dev.zig");
587591const elf = std.elf;
588592const math = std.math;
589593const relocs_log = std.log.scoped(.link_relocs);
src/link/Elf/synthetic_sections.zig+5
......@@ -772,6 +772,7 @@ pub const PltSection = struct {
772772
773773 const x86_64 = struct {
774774 fn write(plt: PltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
775 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
775776 const shdrs = elf_file.sections.items(.shdr);
776777 const plt_addr = shdrs[elf_file.section_indexes.plt.?].sh_addr;
777778 const got_plt_addr = shdrs[elf_file.section_indexes.got_plt.?].sh_addr;
......@@ -807,6 +808,7 @@ pub const PltSection = struct {
807808
808809 const aarch64 = struct {
809810 fn write(plt: PltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
811 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
810812 {
811813 const shdrs = elf_file.sections.items(.shdr);
812814 const plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.plt.?].sh_addr);
......@@ -949,6 +951,7 @@ pub const PltGotSection = struct {
949951
950952 const x86_64 = struct {
951953 pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
954 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
952955 for (plt_got.symbols.items) |ref| {
953956 const sym = elf_file.symbol(ref).?;
954957 const target_addr = sym.gotAddress(elf_file);
......@@ -967,6 +970,7 @@ pub const PltGotSection = struct {
967970
968971 const aarch64 = struct {
969972 fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
973 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
970974 for (plt_got.symbols.items) |ref| {
971975 const sym = elf_file.symbol(ref).?;
972976 const target_addr = sym.gotAddress(elf_file);
......@@ -1518,6 +1522,7 @@ fn writeInt(value: anytype, elf_file: *Elf, writer: *std.Io.Writer) !void {
15181522
15191523const assert = std.debug.assert;
15201524const builtin = @import("builtin");
1525const dev = @import("../../dev.zig");
15211526const elf = std.elf;
15221527const math = std.math;
15231528const mem = std.mem;
src/link/Elf2.zig+3350-1425
......@@ -1,8 +1,5 @@
11const Elf = @This();
22
3const builtin = @import("builtin");
4const native_endian = builtin.cpu.arch.endian();
5
63const std = @import("std");
74const Io = std.Io;
85const assert = std.debug.assert;
......@@ -10,9 +7,10 @@ const log = std.log.scoped(.link);
107
118const codegen = @import("../codegen.zig");
129const Compilation = @import("../Compilation.zig");
10const Dwarf = @import("Dwarf2.zig");
1311const InternPool = @import("../InternPool.zig");
1412const link = @import("../link.zig");
15const MappedFile = @import("MappedFile.zig");
13const MappedFile = link.MappedFile;
1614const target_util = @import("../target.zig");
1715const tracy = @import("../tracy.zig");
1816const Type = @import("../Type.zig");
......@@ -23,7 +21,18 @@ const Alignment = MappedFile.Alignment;
2321base: link.File,
2422options: link.File.OpenOptions,
2523mf: 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},
2736archive: ?Archive,
2837nodes: std.MultiArrayList(Node),
2938/// Does not contain an item for `SHN_UNDEF`.
......@@ -43,6 +52,16 @@ shndx: struct {
4352 tdata: Section.Index,
4453 rela_dyn: Section.Index,
4554 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,
4665 // These sections are created only as needed, and are initially `.UNDEF`.
4766 init_array: Section.Index,
4867 fini_array: Section.Index,
......@@ -123,6 +142,8 @@ got: std.array_hash_map.Auto(GotKey, Section.RelaIndex.Optional),
123142plt: std.array_hash_map.Auto(String(.strtab), void),
124143/// The `.plt` section contains zero or more symbol relocations starting at this index.
125144plt_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
127148needed: std.array_hash_map.Auto(String(.dynstr), void),
128149inputs: std.ArrayList(struct {
......@@ -175,6 +196,7 @@ lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {
175196}),
176197pending_uavs: std.ArrayList(Node.UavMapIndex),
177198symbol_relocs: std.ArrayList(SymbolReloc),
199node_relocs: std.ArrayList(NodeReloc),
178200got_relocs: std.ArrayList(GotReloc),
179201/// Set of relocations which must be re-applied if the size of the TLS segment changes.
180202tls_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),
191213/// section in `flush` only when it is actually necessary. See also `nodeWantsDsoRelocation`.
192214textrel_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
194224overflowed_reloc_count: u32,
195225misaligned_reloc_count: u32,
196226
197227const_prog_node: std.Progress.Node,
198synth_prog_node: std.Progress.Node,
199228input_prog_node: std.Progress.Node,
200229
201230const Error = link.Error || error{MappedFileIo};
202231
203232const Node = union(enum) {
233 deleted,
234
204235 /// Only used when emitting a static library.
205236 ///
206237 /// Contains a header node which is an `.archive_header`.
......@@ -232,8 +263,9 @@ const Node = union(enum) {
232263 ehdr,
233264 shdr,
234265 segment: u32,
235 /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`.
236266 section: Section.Index,
267 /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`.
268 section_manual_size: Section.Index,
237269 /// May contain relocations.
238270 input_section: InputSection.Index,
239271 /// 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) {
253285 /// May contain relocations.
254286 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
256307 pub const InputIndex = enum(u32) {
257308 _,
258309
......@@ -288,7 +339,7 @@ const Node = union(enum) {
288339 pub const NavMapIndex = enum(u32) {
289340 _,
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 {
292343 return elf.navs.keys()[@backingInt(nmi)];
293344 }
294345
......@@ -363,18 +414,6 @@ const Node = union(enum) {
363414 }
364415 };
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
378417 comptime {
379418 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8);
380419 }
......@@ -439,7 +478,7 @@ const Section = struct {
439478 ni: MappedFile.Node.Index,
440479 /// A symbol which is exactly at the start of this section.
441480 ///
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`.
443482 lsi: Symbol.LocalIndex,
444483 rela: union {
445484 /// This field is active if and only if this section is *not* a `SHT_RELA` section.
......@@ -526,8 +565,8 @@ const Section = struct {
526565 std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @fromBackingInt(reserve(sec)),
527566 };
528567 }
529 pub fn toSection(s: Index) ?std.elf.Section {
530 return switch (@backingInt(s)) {
568 pub fn toSection(shndx: Index) ?std.elf.Section {
569 return switch (@backingInt(shndx)) {
531570 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => |sec| @intCast(sec),
532571 std.elf.SHN_LORESERVE...reserve(std.elf.SHN_LORESERVE) - 1 => null,
533572 reserve(std.elf.SHN_LORESERVE)...reserve(std.elf.SHN_HIRESERVE) => |sec| @intCast(
......@@ -536,28 +575,40 @@ const Section = struct {
536575 };
537576 }
538577
539 fn get(s: Index, elf: *Elf) *Section {
540 return &elf.shdrs.items[@backingInt(s) - 1]; // overflow means you tried to get the `.UNDEF` section
578 fn get(shndx: Index, elf: *Elf) *Section {
579 return &elf.shdrs.items[@backingInt(shndx) - 1]; // overflow means you tried to get the `.UNDEF` section
541580 }
542581
543 fn name(s: Index, elf: *Elf) String(.shstrtab) {
544 return switch (elf.shdrPtr(s)) {
582 fn name(shndx: Index, elf: *Elf) String(.shstrtab) {
583 return switch (elf.shdrPtr(shndx)) {
545584 inline else => |shdr| @fromBackingInt(elf.targetLoad(&shdr.name)),
546585 };
547586 }
548587
549 fn vaddr(s: Index, elf: *Elf) u64 {
550 return switch (elf.shdrPtr(s)) {
588 fn vaddr(shndx: Index, elf: *Elf) u64 {
589 return switch (elf.shdrPtr(shndx)) {
551590 inline else => |shdr| elf.targetLoad(&shdr.addr),
552591 };
553592 }
554593
555 fn size(s: Index, elf: *Elf) u64 {
556 return switch (elf.shdrPtr(s)) {
594 fn size(shndx: Index, elf: *Elf) u64 {
595 return switch (elf.shdrPtr(shndx)) {
557596 inline else => |shdr| elf.targetLoad(&shdr.size),
558597 };
559598 }
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
561612 fn flags(s: Index, elf: *Elf) std.elf.SHF {
562613 return switch (elf.shdrPtr(s)) {
563614 inline else => |shdr| elf.targetLoad(&shdr.flags).shf,
......@@ -582,7 +633,7 @@ const Section = struct {
582633 }
583634 const ni = shndx.get(elf).ni;
584635 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);
586637 }
587638 switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {
588639 .elf => {},
......@@ -615,7 +666,7 @@ const Section = struct {
615666 break :need_size cur_size + need_additional * ent_size;
616667 },
617668 };
618 try node.ensureMinimumSize(&elf.mf, elf.base.comp.gpa, need_size);
669 try node.ensureMinimumSize(elf.base.comp.gpa, &elf.mf, need_size);
619670 }
620671
621672 /// Asserts that `rela_shndx` is a `SHT_RELA` section and deletes the `ElfN.Rela` entry at
......@@ -649,7 +700,7 @@ const Section = struct {
649700 },
650701 .addend = @intCast(old_free_len + 1), // list length
651702 };
652 if (elf.targetEndian() != native_endian) {
703 if (elf.targetEndian() != std.lang.Endian.native) {
653704 std.mem.byteSwapAllFields(class.ElfN().Rela, &relas[@backingInt(index)]);
654705 }
655706 },
......@@ -708,7 +759,7 @@ const Section = struct {
708759 },
709760 .addend = @intCast(opts.addend),
710761 };
711 if (elf.targetEndian() != native_endian) {
762 if (elf.targetEndian() != std.lang.Endian.native) {
712763 std.mem.byteSwapAllFields(class.ElfN().Rela, &relas[@backingInt(new_index)]);
713764 }
714765 return new_index;
......@@ -786,10 +837,10 @@ const Section = struct {
786837 }
787838 }
788839
789 /// Asserts that `rela_shndx` is a `SHT_RELA` section, and asserts that `index` refers to an
790 /// `R_*_RELATIVE` relocation inside of it; then, updates that relocation's addend (which is
791 /// an address in this DSO without the runtime load offset applied) to the given value.
792 fn relaSetRelativeOffset(rela_shndx: Index, elf: *Elf, index: RelaIndex, new_addend: u64) void {
840 /// Asserts that `rela_shndx` is a `SHT_RELA` section and updates the `addend` field of the
841 /// `ElfN.Rela` entry at the given index. Asserts that `index` is not in the free-list (i.e.
842 /// it is not deleted).
843 fn relaSetAddend(rela_shndx: Index, elf: *Elf, index: RelaIndex, new_addend: u64) void {
793844 switch (elf.shdrPtr(rela_shndx)) {
794845 inline else => |shdr, class| {
795846 assert(elf.targetLoad(&shdr.type) == .RELA);
......@@ -807,44 +858,322 @@ const Section = struct {
807858 },
808859 }
809860 }
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 }
810867 };
811868};
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.
814const GotKey = union(enum) {
815 /// The entry is a reserved word, initialized to zero. `initHeaders` will add as many of these
816 /// as the target machine ABI requires.
817 ///
818 /// This `u32` value exists to allow reserving multiple words with distinct keys.
819 reserved: u32,
879const dwarf_relocs = struct {
880 const Shared = struct {
881 first_target_reloc: NodeReloc.Index,
882 };
883 const Unit = struct {
884 frame_cie_first_target_reloc: NodeReloc.Index,
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.
822 symbol: Symbol.Id,
917pub const MachineRelocType = union {
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.
825 tpoff: Symbol.Id,
925 pub const Format = struct {
926 rt: MachineRelocType,
927 elf: *const Elf,
826928
827 /// Value is the TLS module ID of the DSO we are creating.
828 ///
829 /// Used for the first of the two GOT entries generated by a TLSLD relocation.
830 tlsld0,
831 /// Value is always 0.
832 ///
833 /// Used for the second of the two GOT entries generated by a TLSLD relocation.
834 tlsld1,
929 pub fn format(f: Format, w: *Io.Writer) Io.Writer.Error!void {
930 switch (f.elf.ehdrMachine()) {
931 .AARCH64 => try w.print("R_AARCH64_{t}", .{f.rt.AARCH64}),
932 .LOONGARCH => try w.print("R_LARCH_{t}", .{f.rt.LARCH}),
933 .PPC64 => try w.print("R_PPC64_{t}", .{f.rt.PPC64}),
934 .RISCV => try w.print("R_RISCV_{t}", .{f.rt.RISCV}),
935 .SPARCV9 => try w.print("R_SPARC_{t}", .{f.rt.SPARC}),
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.
837 ///
838 /// Used for the first of the two GOT entries generated by a TLSGD relocation.
839 tlsgd0: Symbol.Id,
840 /// Value is the offset of the given STT_TLS symbol from the base of the per-module TLS area.
841 ///
842 /// Used for the second of the two GOT entries generated by a TLSGD relocation.
843 tlsgd1: Symbol.Id,
941 pub fn fmt(rt: MachineRelocType, elf: *const Elf) Format {
942 return .{ .rt = rt, .elf = elf };
943 }
944
945 pub fn none(elf: *const Elf) MachineRelocType {
946 return switch (elf.ehdrMachine()) {
947 .AARCH64 => .{ .AARCH64 = .NONE },
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 }
8441173};
8451174
846/// A relocation targeting a particular GOT entry.
847const GotReloc = struct {
1175/// A relocation targeting an arbitrary symbol with a fixed addend.
1176const SymbolReloc = struct {
8481177 /// The node containing this relocation. Possible values are:
8491178 /// * An input section
8501179 /// * A section
......@@ -853,137 +1182,488 @@ const GotReloc = struct {
8531182 node: MappedFile.Node.Index.Optional,
8541183 /// The offset of the relocation inside of `node`.
8551184 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"`.
8571188 addend: i64,
858 type: GotReloc.Type,
859 result: enum(u8) { ok, overflowed, misaligned },
860
861 /// `GotReloc.Type` has the same structure as `SymbolReloc.Type`, just with different `Target`
862 /// and `Special` enums---consult doc comments on `SymbolReloc.Type` for an overview.
1189 /// Specifies how to apply the relocation.
1190 ///
1191 /// When emitting a relocatable, this field is `undefined`.
1192 type: SymbolReloc.Type,
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`.
8631244 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 {
8651248 assert(target != .special);
8661249 return .{ .target = target, .action = .{ .simple = action } };
8671250 }
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 {
8701255 return .{ .target = .special, .action = .{ .special = s } };
8711256 }
8721257
1258 /// See doc comment on `Target`.
8731259 target: Target,
1260 /// If `target == .special`, the `special` field is used.
1261 ///
1262 /// Otherwise, the `.simple` field is used.
8741263 action: packed union {
8751264 simple: Simple,
8761265 special: Special,
8771266 },
8781267
879 /// Like `SymbolReloc.Target`, but for GOT relocations. There are fewer tags because there
880 /// are fewer different kinds of GOT relocation.
1268 /// If a relocation is "special", indicates that using the value `.@"special"`.
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.
8811273 const Target = enum(u3) {
8821274 /// This is a "special" relocation whose specific type is in the `action.special` field.
8831275 special,
8841276
885 /// Absolute address of the GOT entry.
1277 /// Absolute value of the target symbol.
8861278 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").
8881280 rel,
889 /// Offset from the base of the GOT to the GOT entry.
890 offset,
1281 /// Address of the target symbol's PLT entry.
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,
8911295 };
8921296
893 const Simple = SymbolReloc.Type.Simple;
894
895 /// Like `SymbolReloc.Special`, but for GOT relocations.
896 const Special = enum(u13) {
897 larch_pcala_hi20,
898 larch_pcala64_lo20,
899 larch_pcala64_hi12,
1297 /// For a "simple" relocation, after the initial value is computed according to `Target`, a
1298 /// `Simple` value communicates how to shift, truncate, and store that value into memory.
1299 const Simple = packed struct(u13) {
1300 /// The field being written to, represented as a sequence of bits in a backing integer
1301 /// of 8, 16, 32, or 64 bits.
1302 ///
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,
902 sparc_op_hix22,
1327 @"32[4:0]",
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(
905 s: Special,
906 elf: *Elf,
907 got_vaddr: u64,
908 got_offset: u64,
909 addend: u64,
910 dest_vaddr: u64,
911 dest_slice: []u8,
912 ) error{ RelocationMisaligned, RelocationOverflow }!void {
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 },
1340 /// Returns `true` iff `dest` writes a full address for the target.
1341 ///
1342 /// i.e. checks for `.@"32"` on 32-bit targets; for `.@"64"` on 64-bit targets.
1343 fn isAddr(dest: @This(), elf: *const Elf) bool {
1344 return switch (elf.identClass()) {
1345 .NONE, _ => unreachable,
1346 .@"32" => dest == .@"32",
1347 .@"64" => dest == .@"64",
1348 };
9611349 }
962 }
963 };
964 };
1350 },
9651351
966 const Index = enum(u32) {
967 none = std.math.maxInt(u32),
968 _,
1352 /// After the relocation value is shifted (see `shift`), it is truncated to the size of
1353 /// the bit field (see `dest`). This field specifies whether the linker will check for,
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 {
971 return &elf.got_relocs.items[@backingInt(index)];
972 }
973 };
1366 /// The relocation value (computed based on the `Target`) gets shifted to the right by
1367 /// this amount. By default, the shifted-out bits can be anything, but tags ending in
1368 /// "_exact" introduce a check that the shifted-out bits are all zeroes (an error is
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 {
976 assert(elf.ehdrType() != .REL);
977 const node = reloc.node.unwrap() orelse {
978 return; // deleted
979 };
980 if (node.hasMoved(&elf.mf) or elf.shndx.got.get(elf).ni.hasMoved(&elf.mf)) {
981 // There's no point applying the relocation now, because it will be re-applied by
982 // `flushMoved` at some point anyway.
983 return;
984 }
985 switch (reloc.result) {
986 .ok => {},
1380 /// Given a value (computed based on the `Target`), applies the shift and truncation
1381 /// operations specified by `s`, then writes the result to the start of `dest_slice` as
1382 /// specified by `s.dest`.
1383 fn write(
1384 s: Simple,
1385 val: u64,
1386 dest_slice: []u8,
1387 target_endian: std.lang.Endian,
1388 ) error{ RelocationMisaligned, RelocationOverflow }!void {
1389 const shift: u6, const shift_exact: bool = switch (s.shift) {
1390 .@"0" => .{ 0, false },
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 => {},
9871667 .overflowed => elf.overflowed_reloc_count -= 1,
9881668 .misaligned => elf.misaligned_reloc_count -= 1,
9891669 }
......@@ -999,543 +1679,361 @@ const GotReloc = struct {
9991679 reloc.result = .misaligned;
10001680 elf.misaligned_reloc_count += 1;
10011681 },
1002 }
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 };
1682 }
11671683 }
1168 pub fn size32(elf: *const Elf) ?MachineRelocType {
1169 return switch (elf.ehdrMachine()) {
1170 .AARCH64,
1171 .LOONGARCH,
1172 .PPC64,
1173 .RISCV,
1174 => null,
1684 fn applyInner(reloc: *const SymbolReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
1685 const node = reloc.node.unwrap().?;
1686 const dest_vaddr = elf.getNodeVAddr(node) + reloc.offset;
1687 const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..];
11751688
1176 .SPARCV9 => .{ .SPARC = .SIZE32 },
1177 .X86_64 => .{ .X86_64 = .SIZE32 },
1689 const addend: u64 = @bitCast(reloc.addend);
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 ),
11781726 };
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 },
1189 .X86_64 => .{ .X86_64 = .SIZE64 },
1728 // Check for the `R_*_RELATIVE` case now, because it is possible only when no shift or cast
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 },
11901747 };
1748
1749 try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian());
11911750 }
11921751
1193 pub fn wrap(int: u32, elf: *const Elf) MachineRelocType {
1194 return switch (elf.ehdrMachine()) {
1195 .AARCH64 => .{ .AARCH64 = @fromBackingInt(int) },
1196 .LOONGARCH => .{ .LARCH = @fromBackingInt(int) },
1197 .PPC64 => .{ .PPC64 = @fromBackingInt(int) },
1198 .RISCV => .{ .RISCV = @fromBackingInt(int) },
1199 .SPARCV9 => .{ .SPARC = @fromBackingInt(int) },
1200 .X86_64 => .{ .X86_64 = @fromBackingInt(int) },
1201 };
1752 fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void {
1753 assert(index.get(elf) == reloc);
1754
1755 reloc.deleteOutputRel(elf);
1756 if (reloc.type.dependsOnTlsSize(elf)) {
1757 assert(elf.tls_size_symbol_relocs.swapRemove(index));
1758 }
1759
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;
12021780 }
1203 pub fn unwrap(rt: MachineRelocType, elf: *const Elf) u32 {
1204 return switch (elf.ehdrMachine()) {
1205 .AARCH64 => @backingInt(rt.AARCH64),
1206 .LOONGARCH => @backingInt(rt.LARCH),
1207 .PPC64 => @backingInt(rt.PPC64),
1208 .RISCV => @backingInt(rt.RISCV),
1209 .SPARCV9 => @backingInt(rt.SPARC),
1210 .X86_64 => @backingInt(rt.X86_64),
1211 };
1781
1782 /// If `reloc.rela_index` is populated, reset it to `.none` and delete the relocation, updating
1783 /// `elf.textrel_count` if necessary.
1784 fn deleteOutputRel(reloc: *SymbolReloc, elf: *Elf) void {
1785 const rela_index = reloc.rela_index.unwrap() orelse return;
1786 reloc.relaSection(elf).relaDeleteOne(elf, rela_index);
1787 switch (elf.ehdrType()) {
1788 .REL => {},
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;
12121796 }
12131797};
12141798
1215/// A relocation targeting an arbitrary symbol with a fixed addend.
1216const SymbolReloc = struct {
1217 /// The node containing this relocation. Possible values are:
1218 /// * An input section
1219 /// * A section
1220 /// * A NAV, UAV, or lazy code/data
1221 node: MappedFile.Node.Index,
1222 /// The offset of the relocation inside of `node`.
1799/// A relocation targeting an arbitrary node (within a section) with a fixed addend.
1800/// This represents a symbol reloc against the section symbol containing the node
1801/// with a variable addend that changes when the target node moves.
1802const NodeReloc = struct {
1803 node: MappedFile.Node.Index.Optional,
12231804 offset: u64,
1224 /// A symbol used to compute the relocated value. Precise meaning depends on `@"type"`.
1225 target: Symbol.Id,
1226 /// A signed constant used to compute the relocated value. Precise meaning depends on `@"type"`.
1805 target: MappedFile.Node.Index,
12271806 addend: i64,
1228 /// Specifies how to apply the relocation.
1229 ///
1230 /// When emitting a relocatable, this field is `undefined`.
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.
1807 type: NodeReloc.Type,
1808 next: NodeReloc.Index,
1809 prev: NodeReloc.Index,
12481810 rela_index: Section.RelaIndex.Optional,
12491811 result: enum(u8) { ok, overflowed, misaligned },
12501812
1251 /// Determines the section in which this relocation will be placed if it is outstanding.
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 }
1813 const Type = enum { abs32, abs64 };
12671814
12681815 const Index = enum(u32) {
12691816 none = std.math.maxInt(u32),
12701817 _,
12711818
1272 fn get(index: SymbolReloc.Index, elf: *Elf) *SymbolReloc {
1273 return &elf.symbol_relocs.items[@backingInt(index)];
1274 }
1275 };
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 };
1819 fn get(index: NodeReloc.Index, elf: *Elf) *NodeReloc {
1820 return &elf.node_relocs.items[@backingInt(index)];
1821 }
1822 };
13441823
1345 /// For a "simple" relocation, after the initial value is computed according to `Target`, a
1346 /// `Simple` value communicates how to shift, truncate, and store that value into memory.
1347 const Simple = packed struct(u13) {
1348 /// The field being written to, represented as a sequence of bits in a backing integer
1349 /// of 8, 16, 32, or 64 bits.
1350 ///
1351 /// The `.@"8"`, `.@"16"`, `.@"32"`, and `.@"64"` fields simply write to all bits of the
1352 /// backing integer; i.e. the existing value is entirely overwritten.
1353 ///
1354 /// Other fields are named like "B[H:L]", where "B" is the backing integer type, and
1355 /// "H" and "L" are the indices of the highest and lowest bits in the bit field (in
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",
1824 fn flushMovedNode(reloc: *NodeReloc, elf: *Elf, node_vaddr: u64) void {
1825 if (reloc.rela_index.unwrap()) |rela_index| {
1826 assert(elf.ehdrType() == .REL);
1827 // The node has moved, so the offset of the relocation within the section might have
1828 // changed, so update the `offset` field of the `ElfN.Rela` entry.
1829 elf.getNodeShndx(reloc.node.unwrap().?).get(elf).rela.shndx.relaSetOffset(elf, rela_index, node_vaddr + reloc.offset);
1830 } else {
1831 assert(elf.ehdrType() != .REL);
1832 reloc.apply(elf);
1833 }
1834 }
13741835
1375 @"32[4:0]",
1376 @"32[5:0]",
1377 @"32[6:0]",
1378 @"32[9:0]",
1379 @"32[10:0]",
1380 @"32[11:0]",
1381 @"32[12:0]",
1382 @"32[21:0]",
1383 @"32[21:10]",
1384 @"32[24:5]",
1385 @"32[25:10]",
1386 @"32[29:0]",
1836 fn flushMovedTarget(reloc: *NodeReloc, elf: *Elf, target_section_offset: u64) void {
1837 if (reloc.rela_index.unwrap()) |rela_index| {
1838 assert(elf.ehdrType() == .REL);
1839 // The target has moved, so the `addend` field of the `ElfN.Rela` entry needs to be updated.
1840 elf.getNodeShndx(reloc.node.unwrap().?).get(elf).rela.shndx.relaSetAddend(elf, rela_index, target_section_offset +% @as(u64, @bitCast(reloc.addend)));
1841 } else {
1842 assert(elf.ehdrType() != .REL);
1843 reloc.apply(elf);
1844 }
1845 }
13871846
1388 /// Returns `true` iff `dest` writes a full address for the target.
1389 ///
1390 /// i.e. checks for `.@"32"` on 32-bit targets; for `.@"64"` on 64-bit targets.
1391 fn isAddr(dest: @This(), elf: *const Elf) bool {
1392 return switch (elf.identClass()) {
1393 .NONE, _ => unreachable,
1394 .@"32" => dest == .@"32",
1395 .@"64" => dest == .@"64",
1396 };
1397 }
1398 },
1847 fn apply(reloc: *NodeReloc, elf: *Elf) void {
1848 const node = reloc.node.unwrap() orelse return; // deleted
1849 if (reloc.rela_index.unwrap()) |rela_index| {
1850 assert(elf.ehdrType() == .REL);
1851 _ = rela_index;
1852 } else {
1853 assert(elf.ehdrType() != .REL);
1854 if (node.hasMoved(&elf.mf) or reloc.target.hasMoved(&elf.mf)) {
1855 // There's no point applying the relocation now, because it will be re-applied by
1856 // `flushMoved` at some point anyway.
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 of
1401 /// the bit field (see `dest`). This field specifies whether the linker will check for,
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 },
1890 fn delete(reloc: *NodeReloc, elf: *Elf) void {
1891 reloc.deleteOutputRel(elf);
14131892
1414 /// The relocation value (computed based on the `Target`) gets shifted to the right by
1415 /// this amount. By default, the shifted-out bits can be anything, but tags ending in
1416 /// "_exact" introduce a check that the shifted-out bits are all zeroes (an error is
1417 /// emitted if not), similar to the behavior of `@shrExact`.
1418 shift: enum(u5) {
1419 @"0",
1420 @"2_exact",
1421 @"10",
1422 @"12",
1423 @"22",
1424 @"32",
1425 @"52",
1893 switch (reloc.prev) {
1894 .none => {
1895 const first_target_reloc = switch (elf.getNode(reloc.target)) {
1896 else => unreachable,
1897 .debug_shared => |ss| &elf.dwarf_shared.getPtr(ss).first_target_reloc,
1898 .unit_frame_cie => |ui| &elf.dwarf_units[@backingInt(ui)].frame_cie_first_target_reloc,
1899 .unit_debug_info_header => |ui| &elf.dwarf_units[@backingInt(ui)].debug_info_header_first_target_reloc,
1900 .unit_debug_line_header => |ui| &elf.dwarf_units[@backingInt(ui)].debug_line_header_first_target_reloc,
1901 .unit_debug_rnglists => |ui| &elf.dwarf_units[@backingInt(ui)].debug_rnglists_first_target_reloc,
1902 .const_debug_info => |cpi| &elf.dwarf_consts.getPtr(cpi).?.debug_info_first_target_reloc,
1903 .global_debug_info => |gi| &elf.dwarf_globals.items[@backingInt(gi)].debug_info_first_target_reloc,
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;
14261908 },
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 truncation
1429 /// operations specified by `s`, then writes the result to the start of `dest_slice` as
1430 /// specified by `s.dest`.
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 };
1921 reloc.* = undefined;
1922 reloc.node = .none;
1923 }
14461924
1447 if (shift_exact and (val >> shift) << shift != val) {
1448 return error.RelocationMisaligned;
1449 }
1925 /// If `reloc.rela_index` is populated, reset it to `.none` and delete the relocation.
1926 fn deleteOutputRel(reloc: *NodeReloc, elf: *Elf) void {
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) {
1452 // zig fmt: off
1453 .@"8" => .{ 8, 7, 0 },
1454 .@"16" => .{ 16, 15, 0 },
1455 .@"32" => .{ 32, 31, 0 },
1456 .@"64" => .{ 64, 63, 0 },
1457 .@"32[4:0]" => .{ 32, 4, 0 },
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 };
1934/// Identifies a single entry in the GOT.
1935const GotKey = union(enum) {
1936 /// The entry is a reserved word, initialized to zero. `initHeaders` will add as many of these
1937 /// as the target machine ABI requires.
1938 ///
1939 /// This `u32` value exists to allow reserving multiple words with distinct keys.
1940 reserved: u32,
14711941
1472 // The number of bits we are truncating from the full 64-bit relocation value.
1473 const trunc_bits: u6 = 63 - dest_high_bit + dest_low_bit;
1942 /// Value is the address of the given symbol.
1943 symbol: Symbol.Id,
14741944
1475 // When we shift, whether we do an arithmetic or logical shift depends on what cast
1476 // behavior we are going to use. If we'll be doing a signed int cast, we must shift
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;
1945 /// Value is the signed offset of the given symbol from the TLS pointer.
1946 tpoff: Symbol.Id,
14851947
1486 if ((shifted << trunc_bits) >> trunc_bits != shifted) {
1487 return error.RelocationOverflow;
1488 }
1948 /// Value is the TLS module ID of the DSO we are creating.
1949 ///
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);
1491 },
1492 };
1957 /// Value is the TLS module ID for the given STT_TLS symbol.
1958 ///
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] -> 0b00001110
1495 const field_mask = (~@as(u64, 0) >> trunc_bits) << dest_low_bit;
1967/// A relocation targeting a particular GOT entry.
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.
1498 const masked_field: u64 = (shifted_val << dest_low_bit) & field_mask;
1982 /// `GotReloc.Type` has the same structure as `SymbolReloc.Type`, just with different `Target`
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, replacing
1501 // the field bits with those in `masked_field`, and storing the result back.
1502 switch (dest_word_bits) {
1503 inline 8, 16, 32, 64 => |bits| {
1504 const word_slice = dest_slice[0..@divExact(bits, 8)];
1505 const Int = @Int(.unsigned, bits);
1506 const old: u64 = std.mem.readInt(Int, word_slice, target_endian);
1507 const new: u64 = (old & ~field_mask) | masked_field;
1508 std.mem.writeInt(Int, word_slice, @intCast(new), target_endian);
1509 },
1510 else => unreachable,
1511 }
1512 }
1990 fn special(s: Special) GotReloc.Type {
1991 return .{ .target = .special, .action = .{ .special = s } };
1992 }
1993
1994 target: Target,
1995 action: packed union {
1996 simple: Simple,
1997 special: Special,
1998 },
1999
2000 /// Like `SymbolReloc.Target`, but for GOT relocations. There are fewer tags because there
2001 /// are fewer different kinds of GOT relocation.
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,
15132012 };
15142013
1515 /// Enum representing "special" relocation types, i.e. those which cannot be represented
1516 /// just with `Target` and `Simple`. These relocations have completely custom handling in
1517 /// the `Special.applyInner` function.
2014 const Simple = SymbolReloc.Type.Simple;
2015
2016 /// Like `SymbolReloc.Special`, but for GOT relocations.
15182017 const Special = enum(u13) {
15192018 larch_pcala_hi20,
15202019 larch_pcala64_lo20,
15212020 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
15282025 fn applyInner(
15292026 s: Special,
15302027 elf: *Elf,
1531 target: Symbol.Id,
2028 got_vaddr: u64,
2029 got_offset: u64,
15322030 addend: u64,
15332031 dest_vaddr: u64,
15342032 dest_slice: []u8,
15352033 ) error{ RelocationMisaligned, RelocationOverflow }!void {
15362034 switch (s) {
15372035 .larch_pcala_hi20 => {
1538 const val = target.value(elf) +% addend;
2036 const val = got_vaddr +% got_offset +% addend;
15392037 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
15402038 elf.targetStore(inst, .{
15412039 .b0_4 = elf.targetLoad(inst).b0_4,
......@@ -1544,7 +2042,7 @@ const SymbolReloc = struct {
15442042 });
15452043 },
15462044 .larch_pcala64_lo20 => {
1547 const val = target.value(elf) +% addend;
2045 const val = got_vaddr +% got_offset +% addend;
15482046 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
15492047 elf.targetStore(inst, .{
15502048 .b0_4 = elf.targetLoad(inst).b0_4,
......@@ -1553,7 +2051,7 @@ const SymbolReloc = struct {
15532051 });
15542052 },
15552053 .larch_pcala64_hi12 => {
1556 const val = target.value(elf) +% addend;
2054 const val = got_vaddr +% got_offset +% addend;
15572055 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);
15582056 elf.targetStore(inst, .{
15592057 .b0_9 = elf.targetLoad(inst).b0_9,
......@@ -1561,127 +2059,44 @@ const SymbolReloc = struct {
15612059 .b22_31 = elf.targetLoad(inst).b22_31,
15622060 });
15632061 },
1564 .larch_b21, .larch_b26, .larch_call36 => {
1565 const target_vaddr: u64 = elf.pltEntryTargetAddr(target) orelse target.value(elf);
1566 const jump_offset: i64 = @bitCast(target_vaddr +% addend -% dest_vaddr);
1567 if ((jump_offset >> 2) << 2 != jump_offset) {
1568 return error.RelocationMisaligned;
1569 }
1570 const shifted_jump_offset: i64 = @shrExact(jump_offset, 2);
1571 switch (s) {
1572 .larch_b21 => {
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 }
2062 .sparc_op_lox10 => {
2063 const dest_ptr: *align(1) packed struct(u32) {
2064 imm13: u13,
2065 b13_31: u19,
2066 } = @ptrCast(dest_slice);
2067 elf.targetStore(dest_ptr, .{
2068 .imm13 = @as(u10, @truncate(got_offset)),
2069 .b13_31 = elf.targetLoad(dest_ptr).b13_31,
2070 });
16232071 },
1624 .sparc_le_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 };
2072 .sparc_op_hix22 => {
16322073 const dest_ptr: *align(1) packed struct(u32) {
16332074 imm22: u22,
16342075 b22_31: u10,
16352076 } = @ptrCast(dest_slice);
16362077 elf.targetStore(dest_ptr, .{
1637 .imm22 = @truncate(~(target.value(elf) +% addend -% tls_size) >> 10),
2078 .imm22 = @truncate(got_offset >> 10),
16382079 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
16392080 });
16402081 },
16412082 }
16422083 }
16432084 };
2085 };
16442086
1645 fn dependsOnTlsSize(t: SymbolReloc.Type, elf: *const Elf) bool {
1646 return switch (elf.targetTlsVariant()) {
1647 // In TLS variant I, the executable's TLS block starts at a fixed offset from the
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,
2087 const Index = enum(u32) {
2088 none = std.math.maxInt(u32),
2089 _,
16682090
1669 .larch_pcala_hi20,
1670 .larch_pcala64_lo20,
1671 .larch_pcala64_hi12,
1672 .larch_b21,
1673 .larch_b26,
1674 .larch_call36,
1675 => false,
1676 },
1677 },
1678 };
2091 fn get(index: GotReloc.Index, elf: *Elf) *GotReloc {
2092 return &elf.got_relocs.items[@backingInt(index)];
16792093 }
16802094 };
16812095
1682 fn apply(reloc: *SymbolReloc, elf: *Elf) void {
2096 fn apply(reloc: *GotReloc, elf: *Elf) void {
16832097 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)) {
16852100 // There's no point applying the relocation now, because it will be re-applied by
16862101 // `flushMoved` at some point anyway.
16872102 return;
......@@ -1705,118 +2120,99 @@ const SymbolReloc = struct {
17052120 },
17062121 }
17072122 }
1708 fn applyInner(reloc: *const SymbolReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
1709 const dest_vaddr = elf.getNodeVAddr(reloc.node) + reloc.offset;
1710 const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..];
2123 fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
2124 const node = reloc.node.unwrap().?;
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 };
17122134 const addend: u64 = @bitCast(reloc.addend);
1713 const target_val: u64 = type: switch (reloc.type.target) {
1714 .abs => reloc.target.value(elf) +% addend,
1715 .rel => reloc.target.value(elf) +% addend -% dest_vaddr,
1716 .pltabs => {
1717 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .abs;
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 },
2135
2136 const target_val: u64 = switch (reloc.type.target) {
2137 .abs => got_vaddr +% got_offset +% addend,
2138 .rel => got_vaddr +% got_offset +% addend -% dest_vaddr,
2139 .offset => got_offset +% addend,
17422140 .special => return reloc.type.action.special.applyInner(
17432141 elf,
1744 reloc.target,
2142 got_vaddr,
2143 got_offset,
17452144 addend,
17462145 dest_vaddr,
17472146 dest_slice,
17482147 ),
17492148 };
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 cast
1752 // is required, meaning we can handle it now and return early.
1753 if (reloc.rela_index.unwrap()) |rela_index| switch (elf.classifySymbolValue(reloc.target)) {
1754 .static => unreachable,
1755 .dynamic => return, // the relocation happens at runtime
1756 .static_relative => {
1757 // We have emitted an R_*_RELATIVE relocation to help lower an absolute-address
1758 // relocation. The value computed above is valid, but instead of writing it to the
1759 // destination slice, we actually want to write it to the runtime relocation entry.
1760 switch (elf.identClass()) {
1761 .NONE, _ => unreachable,
1762 .@"32" => assert(reloc.type.action.simple.dest == .@"32"),
1763 .@"64" => assert(reloc.type.action.simple.dest == .@"64"),
1764 }
1765 assert(reloc.type.action.simple.cast == .unsigned);
1766 assert(reloc.type.action.simple.shift == .@"0");
1767 elf.shndx.rela_dyn.relaSetRelativeOffset(elf, rela_index, target_val);
1768 return;
1769 },
2152 fn delete(reloc: *GotReloc, elf: *Elf) void {
2153 switch (reloc.result) {
2154 .ok => {},
2155 .overflowed => elf.overflowed_reloc_count -= 1,
2156 .misaligned => elf.misaligned_reloc_count -= 1,
2157 }
2158 reloc.* = .{
2159 .node = .none,
2160 .offset = undefined,
2161 .target = undefined,
2162 .addend = undefined,
2163 .type = undefined,
2164 .result = undefined,
2165 };
2166 }
2167};
2168
2169fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe_global }) Error!void {
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),
17702183 };
1771
1772 try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian());
2184 try Section.Index.symtab.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_node_size);
17732185 }
17742186
1775 fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void {
1776 assert(index.get(elf) == reloc);
2187 switch (kind) {
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);
1779 if (reloc.type.dependsOnTlsSize(elf)) {
1780 assert(elf.tls_size_symbol_relocs.swapRemove(index));
1781 }
2195 try elf.node_global_symbols.ensureUnusedCapacity(gpa, len);
17822196
1783 switch (reloc.prev) {
1784 .none => {
1785 const target_ptr = reloc.target.index(elf).ptr(elf);
1786 assert(target_ptr.first_target_reloc == index);
1787 target_ptr.first_target_reloc = reloc.next;
1788 },
1789 else => |prev| prev.get(elf).next = reloc.next,
1790 }
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 }
2197 if (elf.shndx.dynsym != .UNDEF) {
2198 const dynsym_cur_size: u64, const dynsym_ent_size: u32 = switch (elf.shdrPtr(elf.shndx.dynsym)) {
2199 inline else => |shdr, class| .{
2200 elf.targetLoad(&shdr.size),
2201 @sizeOf(class.ElfN().Sym),
2202 },
2203 };
2204 const dynsym_cur_len: u32 = @intCast(@divExact(dynsym_cur_size, dynsym_ent_size));
18002205
1801 reloc.* = undefined;
1802 }
2206 const dynsym_need_size: u64 = (dynsym_cur_len + len) * dynsym_ent_size;
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, updating
1805 /// `elf.textrel_count` if necessary.
1806 fn deleteOutputRel(reloc: *SymbolReloc, elf: *Elf) void {
1807 const rela_index = reloc.rela_index.unwrap() orelse return;
1808 reloc.relaSection(elf).relaDeleteOne(elf, rela_index);
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;
2209 try elf.ensureDynsymHashCapacity(dynsym_cur_len + len);
2210
2211 try elf.ensureUnusedPltCapacity(len);
2212 }
2213 },
18182214 }
1819};
2215}
18202216
18212217fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {
18222218 const gpa = elf.base.comp.gpa;
......@@ -1841,7 +2237,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {
18412237 // We don't need to add any buckets, but we still need to make sure the section is large
18422238 // enough to fit `max_dynsym_count` chains.
18432239 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);
18452241 return;
18462242 }
18472243 // 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 {
18532249
18542250 {
18552251 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);
18572253 }
18582254
18592255 elf.mf.nodes_lock.lock();
......@@ -1984,53 +2380,6 @@ fn clearDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {
19842380 }
19852381}
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}
20342383fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
20352384 const gpa = elf.base.comp.gpa;
20362385
......@@ -2044,19 +2393,19 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
20442393 // Ensure the `.plt` section's node is big enough:
20452394 {
20462395 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);
20482397 }
20492398
20502399 // If there is a `.got.plt` section, ensure its node is big enough
20512400 if (plt.got_plt) |got_plt| {
20522401 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);
20542403 }
20552404
20562405 // If there is a `.plt.sec` section, ensure its node is big enough
20572406 if (plt.plt_sec) |plt_sec| {
20582407 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);
20602409 }
20612410}
20622411/// 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
21382487 .other = .{ .visibility = .DEFAULT },
21392488 .shndx = opts.shndx.toSection().?,
21402489 };
2141 if (elf.targetEndian() != native_endian) {
2490 if (elf.targetEndian() != std.lang.Endian.native) {
21422491 std.mem.byteSwapAllFields(class.ElfN().Sym, target_sym);
21432492 }
21442493
......@@ -2323,7 +2672,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{
23232672 .other = .{ .visibility = opts.visibility },
23242673 .shndx = opts.shndx.toSection().?,
23252674 };
2326 if (elf.targetEndian() != native_endian) {
2675 if (elf.targetEndian() != std.lang.Endian.native) {
23272676 std.mem.byteSwapAllFields(Sym, sym);
23282677 }
23292678 },
......@@ -2359,7 +2708,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{
23592708 .other = .{ .visibility = opts.visibility },
23602709 .shndx = opts.shndx.toSection().?,
23612710 };
2362 if (elf.targetEndian() != native_endian) {
2711 if (elf.targetEndian() != std.lang.Endian.native) {
23632712 std.mem.byteSwapAllFields(Sym, sym);
23642713 }
23652714 elf.appendDynsymHashEntry(dynsym_index);
......@@ -2869,7 +3218,8 @@ const Symbol = struct {
28693218 .abs, .pltabs => {},
28703219 }
28713220 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)) {
28733223 .no => continue,
28743224 .yes_textrel => elf.textrel_count += 1,
28753225 .yes => {},
......@@ -2877,7 +3227,7 @@ const Symbol = struct {
28773227 // There is capacity for a relocation because we just deleted one earlier.
28783228 reloc.rela_index = elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{
28793229 .type = .relative(elf),
2880 .offset = elf.getNodeVAddr(reloc.node) + reloc.offset,
3230 .offset = elf.getNodeVAddr(node) + reloc.offset,
28813231 .raw_sym_index = 0,
28823232 .addend = 0,
28833233 }).toOptional();
......@@ -2982,6 +3332,7 @@ fn classifySymbolValue(elf: *Elf, sym: Symbol.Id) enum {
29823332
29833333pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {
29843334 const lsi: Symbol.LocalIndex = switch (elf.getNode(Node.fromAtom(atom))) {
3335 .deleted,
29853336 .archive,
29863337 .archive_header,
29873338 .archive_input_member,
......@@ -2991,10 +3342,27 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {
29913342 .shdr,
29923343 .segment,
29933344 .section,
3345 .section_manual_size,
29943346 .input_section,
29953347 .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,
29963365 => unreachable,
2997
29983366 inline .nav,
29993367 .uav,
30003368 .lazy_code,
......@@ -3005,10 +3373,9 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {
30053373 return s.toTypeErased();
30063374}
30073375pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) link.Error!link.File.SymbolId {
3008 const diags = &elf.base.comp.link_diags;
30093376 return elf.lazySymbolInner(lazy) catch |err| switch (err) {
3010 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
30113377 else => |e| return e,
3378 error.MappedFileIo => return elf.base.comp.link_diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
30123379 };
30133380}
30143381fn 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
30243391 .code => .{ .text, .FUNC },
30253392 .const_data => .{ .rodata, .OBJECT },
30263393 };
3027 const node = try shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{});
3028 var name_buf: [64]u8 = undefined;
3029 const name = std.mem.print(
3030 &name_buf,
3031 "__lazy_{t}_{d}",
3032 .{ lazy.kind, @backingInt(lazy.ty) },
3033 ) catch unreachable;
3394 const node = elf.addNodeAssumeCapacity(
3395 try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}),
3396 switch (lazy.kind) {
3397 .code => .{ .lazy_code = @fromBackingInt(@intCast(gop.index)) },
3398 .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(gop.index)) },
3399 },
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;
30343404 gop.value_ptr.* = .{
30353405 .lsi = elf.addLocalSymbolAssumeCapacity(.{
30363406 .node = .wrap(node),
......@@ -3043,11 +3413,7 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol
30433413 .first_symbol_reloc = .none,
30443414 .first_got_reloc = .none,
30453415 };
3046 elf.nodes.appendAssumeCapacity(switch (lazy.kind) {
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);
3416 elf.base.comp.link_prog_node.increaseEstimatedTotalItems(1);
30513417 }
30523418 const s: Symbol.Id = .local(gop.value_ptr.lsi);
30533419 return s.toTypeErased();
......@@ -3062,8 +3428,8 @@ pub const ExternSymbolOpts = struct {
30623428pub fn externSymbol(elf: *Elf, opts: ExternSymbolOpts) link.Error!link.File.SymbolId {
30633429 const diags = &elf.base.comp.link_diags;
30643430 return (elf.externSymbolInner(opts) catch |err| switch (err) {
3065 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
30663431 else => |e| return e,
3432 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
30673433 }).toTypeErased();
30683434}
30693435fn externSymbolInner(elf: *Elf, opts: ExternSymbolOpts) Error!Symbol.Id {
......@@ -3103,15 +3469,33 @@ pub fn addReloc(
31033469 const node: MappedFile.Node.Index = Node.fromAtom(atom);
31043470 const diags = &elf.base.comp.link_diags;
31053471 elf.ensureUnusedRelocCapacity(node, 1) catch |err| switch (err) {
3106 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
31073472 else => |e| return e,
3473 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
31083474 };
31093475 elf.addRelocAssumeCapacity(node, offset, .fromTypeErased(target), addend, @"type") catch |err| switch (err) {
3476 else => |e| return e,
31103477 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
31113478 error.UnknownRelocation => unreachable, // codegen bug
31123479 error.NonStaticRelocation => unreachable, // codegen bug
31133480 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) {
31143497 else => |e| return e,
3498 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
31153499 };
31163500}
31173501pub 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
31293513 });
31303514 }
31313515 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.?}),
31333516 else => |e| return e,
3517 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
31343518 };
31353519 const s: Symbol.Id = .local(nmi.symbol(elf));
31363520 return s.toTypeErased();
......@@ -3142,8 +3526,8 @@ pub fn uavSymbol(
31423526) link.Error!link.File.SymbolId {
31433527 const diags = &elf.base.comp.link_diags;
31443528 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.?}),
31463529 else => |e| return e,
3530 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
31473531 };
31483532 const s: Symbol.Id = .local(umi.symbol(elf));
31493533 return s.toTypeErased();
......@@ -3166,7 +3550,11 @@ pub fn getUavVAddr(
31663550}
31673551pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target: link.File.SymbolId) link.Error!u64 {
31683552 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 },
31703558 reloc_info.offset,
31713559 target,
31723560 reloc_info.addend,
......@@ -3183,8 +3571,8 @@ pub fn lowerUav(
31833571 _ = pt;
31843572 const diags = &elf.base.comp.link_diags;
31853573 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.?}),
31873574 else => |e| return e,
3575 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
31883576 };
31893577 const s: Symbol.Id = .local(umi.symbol(elf));
31903578 return s.toTypeErased();
......@@ -3283,7 +3671,7 @@ const StringTable = struct {
32833671 break :size .{ old_size, new_size };
32843672 },
32853673 };
3286 try ni.ensureMinimumSize(&elf.mf, gpa, new_size);
3674 try ni.ensureMinimumSize(gpa, &elf.mf, new_size);
32873675 const slice = ni.slice(&elf.mf)[old_size..];
32883676 @memcpy(slice[0..key.len], key);
32893677 slice[key.len] = 0;
......@@ -3393,6 +3781,7 @@ fn create(
33933781 .data = undefined,
33943782 .data_rel_ro = undefined,
33953783 .tls = .none,
3784 .gnu_eh_frame = .none,
33963785 },
33973786 .archive = null,
33983787 .nodes = .empty,
......@@ -3410,6 +3799,16 @@ fn create(
34103799 .tdata = .UNDEF,
34113800 .rela_dyn = .UNDEF,
34123801 .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,
34133812 .init_array = .UNDEF,
34143813 .fini_array = .UNDEF,
34153814 .preinit_array = .UNDEF,
......@@ -3437,6 +3836,7 @@ fn create(
34373836 .got = .empty,
34383837 .plt = .empty,
34393838 .plt_first_symbol_reloc = .none,
3839 .eh_frame_hdr_first_symbol_reloc = .none,
34403840 .needed = .empty,
34413841 .inputs = .empty,
34423842 .input_pending_index = 0,
......@@ -3451,15 +3851,31 @@ fn create(
34513851 }),
34523852 .pending_uavs = .empty,
34533853 .symbol_relocs = .empty,
3854 .node_relocs = .empty,
34543855 .got_relocs = .empty,
34553856 .tls_size_symbol_relocs = .empty,
34563857 .section_by_name = .empty,
34573858 .changed_symtab_index = .empty,
34583859 .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
34593875 .overflowed_reloc_count = 0,
34603876 .misaligned_reloc_count = 0,
3877
34613878 .const_prog_node = .none,
3462 .synth_prog_node = .none,
34633879 .input_prog_node = .none,
34643880 };
34653881 errdefer elf.deinit();
......@@ -3498,10 +3914,20 @@ pub fn deinit(elf: *Elf) void {
34983914 for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa);
34993915 elf.pending_uavs.deinit(gpa);
35003916 elf.symbol_relocs.deinit(gpa);
3917 elf.node_relocs.deinit(gpa);
35013918 elf.got_relocs.deinit(gpa);
35023919 elf.tls_size_symbol_relocs.deinit(gpa);
35033920 elf.section_by_name.deinit(gpa);
35043921 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
35053931 elf.* = undefined;
35063932}
35073933
......@@ -3518,11 +3944,17 @@ fn initHeaders(
35183944 const gpa = comp.gpa;
35193945
35203946 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") {
35223948 .REL => false,
35233949 .EXEC => comp.config.link_mode == .dynamic,
35243950 .DYN => true,
35253951 };
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 };
35263958 const addr_align: Alignment = switch (class) {
35273959 .NONE, _ => unreachable,
35283960 .@"32" => .@"4",
......@@ -3537,7 +3969,7 @@ fn initHeaders(
35373969 //
35383970 // It can be handy to temporarily set this to `.@"1"` when working on the linker, because it
35393971 // 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
35423974 const plt: PltInfo = .fromMachine(machine);
35433975
......@@ -3552,7 +3984,7 @@ fn initHeaders(
35523984 shnum += 1; // .data
35533985 shnum += @intFromBool(comp.config.any_non_single_threaded); // .tdata
35543986 shnum += 1; // .data.rel.ro
3555 if (have_dynamic_section) {
3987 if (have_dynamic) {
35563988 shnum += 1; // .dynamic
35573989 shnum += 1; // .dynstr
35583990 shnum += 1; // .dynsym
......@@ -3560,6 +3992,24 @@ fn initHeaders(
35603992 shnum += 1; // .rela.dyn
35613993 shnum += 1; // .rela.plt
35623994 }
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 }
35634013 if (@"type" != .REL) {
35644014 shnum += 1; // .got
35654015 shnum += @intFromBool(plt.got_plt != null); // .got.plt
......@@ -3574,14 +4024,15 @@ fn initHeaders(
35744024 interp: u32,
35754025 rodata: u32,
35764026 text: u32,
3577 data: u32,
35784027 /// On most targets this is `undefined`, but on machines where JUMP_SLOT relocations write
35794028 /// directly to the PLT, we place the PLT in its own segment in order to avoid making the
35804029 /// general data segment RWX.
35814030 plt: u32,
4031 data: u32,
35824032 tls: u32,
35834033 dynamic: u32,
35844034 relro: u32,
4035 gnu_eh_frame: u32,
35854036 gnu_stack: u32,
35864037 }, const phnum: u32 = ph: {
35874038 switch (@"type") {
......@@ -3622,7 +4073,7 @@ fn initHeaders(
36224073 defer phnum += 1;
36234074 break :phndx phnum;
36244075 } else undefined,
3625 .dynamic = if (have_dynamic_section) phndx: {
4076 .dynamic = if (have_dynamic) phndx: {
36264077 defer phnum += 1;
36274078 break :phndx phnum;
36284079 } else undefined,
......@@ -3630,6 +4081,10 @@ fn initHeaders(
36304081 defer phnum += 1;
36314082 break :phndx phnum;
36324083 },
4084 .gnu_eh_frame = if (have_eh_frame) phndx: {
4085 defer phnum += 1;
4086 break :phndx phnum;
4087 } else undefined,
36334088 .gnu_stack = phndx: {
36344089 defer phnum += 1;
36354090 break :phndx phnum;
......@@ -3643,7 +4098,8 @@ fn initHeaders(
36434098 const expected_nodes_len = @as(usize, if (is_archive) 3 else 0) + // .archive, .archive_header, .archive_elf_member_header
36444099 3 + // `.elf`, `.ehdr`, and `.shdr` nodes
36454100 (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` node
4101 (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
36484104 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
36494105 try elf.shdrs.ensureTotalCapacity(gpa, shnum - 1); // -1 to exclude SHN_UNDEF
......@@ -3652,21 +4108,21 @@ fn initHeaders(
36524108 try elf.symtab.ensureTotalCapacity(gpa, 1);
36534109
36544110 if (is_archive) {
3655 elf.nodes.appendAssumeCapacity(.archive);
3656
3657 const archive_ni: MappedFile.Node.Index = .root;
3658
3659 const archive_header_ni = try archive_ni.addOnlyHeaderChild(&elf.mf, gpa, .{
3660 // We intentionally do not set `.alignment = .@"2"` here, because the string table data
3661 // in this node does not need to have an aligned length. (This node's offset is aligned
3662 // regardless by virtue of it being a header.)
3663 .size = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr),
3664 // The archive header uses 'next_moved' events to resize the "//" member, so that it
3665 // absorbs all padding between `archive_header_ni` and the actual object file members.
3666 .enable_next_moved = true,
3667 .next_moved = true,
3668 });
3669 elf.nodes.appendAssumeCapacity(.archive_header);
4111 const archive_ni = elf.addNodeAssumeCapacity(.root, .archive);
4112
4113 const archive_header_ni = elf.addNodeAssumeCapacity(
4114 try archive_ni.addOnlyHeaderChild(gpa, &elf.mf, .{
4115 // We intentionally do not set `.alignment = .@"2"` here, because the string table data
4116 // in this node does not need to have an aligned length. (This node's offset is aligned
4117 // regardless by virtue of it being a header.)
4118 .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
4120 // absorbs all padding between `archive_header_ni` and the actual object file members.
4121 .enable_next_moved = true,
4122 .next_moved = true,
4123 }),
4124 .archive_header,
4125 );
36704126 const archive_header_slice = archive_header_ni.slice(&elf.mf);
36714127 @memcpy(archive_header_slice[0..std.elf.ARMAG.len], std.elf.ARMAG);
36724128 const strtab_ar_hdr: *std.elf.ar_hdr = @ptrCast(archive_header_slice[std.elf.ARMAG.len..]);
......@@ -3680,18 +4136,19 @@ fn initHeaders(
36804136 .ar_fmag = std.elf.ARFMAG.*,
36814137 };
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, .{
36844140 .alignment = node_block_align.max(.@"2"),
36854141 .bubbles_moved = false,
36864142 .resized = true, // ensure that this node's `ar_hdr.ar_size` is updated at least once
3687 });
3688 elf.nodes.appendAssumeCapacity(.elf);
4143 }), .elf);
36894144
3690 const elf_ar_hdr_ni = try archive_ni.addFooterChildBefore(&elf.mf, gpa, .wrap(elf.ni.elf), .{
3691 .alignment = .@"2",
3692 .size = @sizeOf(std.elf.ar_hdr),
3693 });
3694 elf.nodes.appendAssumeCapacity(.archive_elf_member_header);
4145 const elf_ar_hdr_ni = elf.addNodeAssumeCapacity(
4146 try archive_ni.addFooterChildBefore(gpa, &elf.mf, .wrap(elf.ni.elf), .{
4147 .alignment = .@"2",
4148 .size = @sizeOf(std.elf.ar_hdr),
4149 }),
4150 .archive_elf_member_header,
4151 );
36954152
36964153 // Must be populated before we call `populateArchiveMemberName` below.
36974154 elf.archive = .{
......@@ -3717,10 +4174,7 @@ fn initHeaders(
37174174 defer gpa.free(zcu_member_name);
37184175 // After this call returns, `elf_ar_hdr` is invalidated.
37194176 try elf.populateArchiveMemberName(elf_ar_hdr, zcu_member_name);
3720 } else {
3721 elf.ni.elf = .root;
3722 elf.nodes.appendAssumeCapacity(.elf);
3723 }
4177 } else elf.ni.elf = elf.addNodeAssumeCapacity(.root, .elf);
37244178
37254179 const entsize: struct { ph: u32, sh: u32 } = switch (class) {
37264180 .NONE, _ => unreachable,
......@@ -3736,69 +4190,65 @@ fn initHeaders(
37364190 if (@"type" != .REL) {
37374191 // This node will contain the ehdr, which must be at the start of the ELF file, so this
37384192 // 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, .{
37404194 // Must be at least `addr_align` for `elf.ni.phdr` to be placed inside this node
37414195 .alignment = node_block_align.max(addr_align),
37424196 .moved = true,
37434197 .bubbles_moved = false,
3744 });
3745 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.rodata });
4198 }), .{ .segment = phndx.rodata });
37464199 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, .{
37494202 .size = @as(u64, phnum) * entsize.ph,
37504203 .alignment = addr_align, // keep in sync with `elf.ni.rodata` alignment above
37514204 .moved = true,
37524205 .resized = true,
37534206 .bubbles_moved = false,
3754 });
3755 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.phdr });
4207 }), .{ .segment = phndx.phdr });
37564208 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, .{
37594211 .alignment = node_block_align,
37604212 .moved = true,
37614213 .bubbles_moved = false,
3762 });
3763 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.text });
4214 }), .{ .segment = phndx.text });
37644215 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, .{
37674218 // Must be at least `addr_align` for `elf.ni.data_rel_ro` to be placed inside this node
37684219 .alignment = node_block_align.max(addr_align),
37694220 .moved = true,
37704221 .bubbles_moved = false,
3771 });
3772 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.data });
4222 }), .{ .segment = phndx.data });
37734223 elf.phdrs.items[phndx.data] = .wrap(elf.ni.data);
37744224
3775 if (plt.got_plt == null) {
3776 const plt_ni = try elf.ni.elf.addFloatingChild(&elf.mf, gpa, .{
4225 if (plt.got_plt == null) elf.phdrs.items[phndx.plt] = .wrap(elf.addNodeAssumeCapacity(
4226 try elf.ni.elf.addFloatingChild(gpa, &elf.mf, .{
37774227 .alignment = node_block_align,
37784228 .moved = true,
37794229 .bubbles_moved = false,
3780 });
3781 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.plt });
3782 elf.phdrs.items[phndx.plt] = .wrap(plt_ni);
3783 }
4230 }),
4231 .{ .segment = phndx.plt },
4232 ));
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, .{
37864235 // Must be at least `addr_align` for the `PT_DYNAMIC` node to be placed inside this one
37874236 // later (if `have_dynamic_section`). Keep in sync with `elf.ni.data` alignment above.
37884237 .alignment = node_block_align.max(addr_align),
37894238 .moved = true,
37904239 .bubbles_moved = false,
3791 });
3792 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.relro });
4240 }), .{ .segment = phndx.relro });
37934241 elf.phdrs.items[phndx.relro] = .wrap(elf.ni.data_rel_ro);
37944242
37954243 if (comp.config.any_non_single_threaded) {
3796 elf.ni.tls = .wrap(try elf.ni.rodata.addFloatingChild(&elf.mf, gpa, .{
3797 .alignment = node_block_align,
3798 .moved = true,
3799 .bubbles_moved = false,
3800 }));
3801 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.tls });
4244 elf.ni.tls = .wrap(elf.addNodeAssumeCapacity(
4245 try elf.ni.rodata.addFloatingChild(gpa, &elf.mf, .{
4246 .alignment = node_block_align,
4247 .moved = true,
4248 .bubbles_moved = false,
4249 }),
4250 .{ .segment = phndx.tls },
4251 ));
38024252 elf.phdrs.items[phndx.tls] = elf.ni.tls;
38034253 }
38044254
......@@ -3822,11 +4272,10 @@ fn initHeaders(
38224272 .REL => elf.ni.elf,
38234273 .DYN, .EXEC => elf.ni.rodata,
38244274 };
3825 elf.ni.ehdr = try parent_ni.addOnlyHeaderChild(&elf.mf, gpa, .{
4275 elf.ni.ehdr = elf.addNodeAssumeCapacity(try parent_ni.addOnlyHeaderChild(gpa, &elf.mf, .{
38264276 .size = @sizeOf(ElfN.Ehdr),
38274277 .alignment = addr_align,
3828 });
3829 elf.nodes.appendAssumeCapacity(.ehdr);
4278 }), .ehdr);
38304279
38314280 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf)));
38324281 ehdr.ident = .{
......@@ -3872,17 +4321,16 @@ fn initHeaders(
38724321 ehdr.shentsize = @sizeOf(ElfN.Shdr);
38734322 ehdr.shnum = 1; // Only the SHN_UNDEF shdr initially---will be incremented by `addSection`
38744323 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);
38764325 },
38774326 }
38784327
3879 elf.ni.shdr = try elf.ni.elf.addFloatingChild(&elf.mf, gpa, .{
3880 .size = node_block_align.forward(1 * entsize.sh), // as above, only the SHN_UNDEF initially
3881 .alignment = addr_align.max(node_block_align),
4328 elf.ni.shdr = elf.addNodeAssumeCapacity(try elf.ni.elf.addFloatingChild(gpa, &elf.mf, .{
4329 .size = 1 * entsize.sh, // as above, only the null shdr initially
4330 .alignment = addr_align,
38824331 .moved = true,
38834332 .resized = true,
3884 });
3885 elf.nodes.appendAssumeCapacity(.shdr);
4333 }), .shdr);
38864334
38874335 switch (class) {
38884336 .NONE, _ => unreachable,
......@@ -3925,8 +4373,7 @@ fn initHeaders(
39254373 elf.ni.phdr.slice(&elf.mf)[0 .. phnum * @sizeOf(ElfN.Phdr)],
39264374 ));
39274375
3928 const ph_phdr = &phdr[phndx.phdr];
3929 ph_phdr.* = .{
4376 phdr[phndx.phdr] = .{
39304377 .type = .PHDR,
39314378 .offset = 0,
39324379 .vaddr = 0,
......@@ -3937,22 +4384,18 @@ fn initHeaders(
39374384 .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()),
39384385 };
39394386
3940 if (maybe_interp) |_| {
3941 const ph_interp = &phdr[phndx.interp];
3942 ph_interp.* = .{
3943 .type = .INTERP,
3944 .offset = 0,
3945 .vaddr = 0,
3946 .paddr = 0,
3947 .filesz = 0,
3948 .memsz = 0,
3949 .flags = .{ .R = true },
3950 .@"align" = 1,
3951 };
3952 }
4387 if (maybe_interp) |_| phdr[phndx.interp] = .{
4388 .type = .INTERP,
4389 .offset = 0,
4390 .vaddr = 0,
4391 .paddr = 0,
4392 .filesz = 0,
4393 .memsz = 0,
4394 .flags = .{ .R = true },
4395 .@"align" = 1,
4396 };
39534397
3954 const ph_rodata = &phdr[phndx.rodata];
3955 ph_rodata.* = .{
4398 phdr[phndx.rodata] = .{
39564399 .type = .NULL,
39574400 .offset = 0,
39584401 .vaddr = @intCast(base_vaddr),
......@@ -3963,8 +4406,7 @@ fn initHeaders(
39634406 .@"align" = @intCast(page_align.toByteUnits()),
39644407 };
39654408
3966 const ph_text = &phdr[phndx.text];
3967 ph_text.* = .{
4409 phdr[phndx.text] = .{
39684410 .type = .NULL,
39694411 .offset = 0,
39704412 .vaddr = @intCast(base_vaddr),
......@@ -3975,8 +4417,7 @@ fn initHeaders(
39754417 .@"align" = @intCast(page_align.toByteUnits()),
39764418 };
39774419
3978 const ph_data = &phdr[phndx.data];
3979 ph_data.* = .{
4420 phdr[phndx.data] = .{
39804421 .type = .NULL,
39814422 .offset = 0,
39824423 .vaddr = @intCast(base_vaddr),
......@@ -3987,50 +4428,40 @@ fn initHeaders(
39874428 .@"align" = @intCast(page_align.toByteUnits()),
39884429 };
39894430
3990 if (plt.got_plt == null) {
3991 const ph_plt = &phdr[phndx.plt];
3992 ph_plt.* = .{
3993 .type = .NULL,
3994 .offset = 0,
3995 .vaddr = @intCast(base_vaddr),
3996 .paddr = @intCast(base_vaddr),
3997 .filesz = 0,
3998 .memsz = 0,
3999 .flags = .{ .R = true, .W = true, .X = true },
4000 .@"align" = @intCast(page_align.toByteUnits()),
4001 };
4002 }
4431 if (plt.got_plt == null) phdr[phndx.plt] = .{
4432 .type = .NULL,
4433 .offset = 0,
4434 .vaddr = @intCast(base_vaddr),
4435 .paddr = @intCast(base_vaddr),
4436 .filesz = 0,
4437 .memsz = 0,
4438 .flags = .{ .R = true, .W = true, .X = true },
4439 .@"align" = @intCast(page_align.toByteUnits()),
4440 };
40034441
4004 if (elf.ni.tls.unwrap()) |tls_segment_ni| {
4005 const ph_tls = &phdr[phndx.tls];
4006 ph_tls.* = .{
4007 .type = .TLS,
4008 .offset = 0,
4009 .vaddr = 0,
4010 .paddr = 0,
4011 .filesz = 0,
4012 .memsz = 0,
4013 .flags = .{ .R = true },
4014 .@"align" = @intCast(tls_segment_ni.alignment(&elf.mf).toByteUnits()),
4015 };
4016 }
4442 if (elf.ni.tls.unwrap()) |tls_segment_ni| phdr[phndx.tls] = .{
4443 .type = .TLS,
4444 .offset = 0,
4445 .vaddr = 0,
4446 .paddr = 0,
4447 .filesz = 0,
4448 .memsz = 0,
4449 .flags = .{ .R = true },
4450 .@"align" = @intCast(tls_segment_ni.alignment(&elf.mf).toByteUnits()),
4451 };
40174452
4018 if (have_dynamic_section) {
4019 const ph_dynamic = &phdr[phndx.dynamic];
4020 ph_dynamic.* = .{
4021 .type = .DYNAMIC,
4022 .offset = 0,
4023 .vaddr = 0,
4024 .paddr = 0,
4025 .filesz = 0,
4026 .memsz = 0,
4027 .flags = .{ .R = true, .W = true },
4028 .@"align" = @intCast(addr_align.toByteUnits()),
4029 };
4030 }
4453 if (have_dynamic) phdr[phndx.dynamic] = .{
4454 .type = .DYNAMIC,
4455 .offset = 0,
4456 .vaddr = 0,
4457 .paddr = 0,
4458 .filesz = 0,
4459 .memsz = 0,
4460 .flags = .{ .R = true, .W = true },
4461 .@"align" = @intCast(addr_align.toByteUnits()),
4462 };
40314463
4032 const ph_relro = &phdr[phndx.relro];
4033 ph_relro.* = .{
4464 phdr[phndx.relro] = .{
40344465 .type = .GNU_RELRO,
40354466 .offset = 0,
40364467 .vaddr = 0,
......@@ -4041,8 +4472,18 @@ fn initHeaders(
40414472 .@"align" = @intCast(elf.ni.data_rel_ro.alignment(&elf.mf).toByteUnits()),
40424473 };
40434474
4044 const ph_gnu_stack = &phdr[phndx.gnu_stack];
4045 ph_gnu_stack.* = .{
4475 if (have_eh_frame) phdr[phndx.gnu_eh_frame] = .{
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] = .{
40464487 .type = .GNU_STACK,
40474488 .offset = 0,
40484489 .vaddr = 0,
......@@ -4071,7 +4512,7 @@ fn initHeaders(
40714512 .addralign = 0,
40724513 .entsize = 0,
40734514 };
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
40764517 elf.symtab.addOneAssumeCapacity().* = .{
40774518 .node = .none,
......@@ -4084,6 +4525,7 @@ fn initHeaders(
40844525 .entsize = @sizeOf(ElfN.Sym),
40854526 .node_align = node_block_align,
40864527 .info = 1, // index of first non-local symbol
4528 .manual_size = true,
40874529 }));
40884530 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
40894531 symtab_null.* = .{
......@@ -4094,7 +4536,7 @@ fn initHeaders(
40944536 .other = .{ .visibility = .DEFAULT },
40954537 .shndx = std.elf.SHN_UNDEF,
40964538 };
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
40994541 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));
41004542 ehdr.shstrndx = ehdr.shnum;
......@@ -4105,6 +4547,7 @@ fn initHeaders(
41054547 .size = 1,
41064548 .entsize = 1,
41074549 .node_align = node_block_align,
4550 .manual_size = true,
41084551 }));
41094552 Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0;
41104553
......@@ -4117,6 +4560,7 @@ fn initHeaders(
41174560 .size = 1,
41184561 .entsize = 1,
41194562 .node_align = node_block_align,
4563 .manual_size = true,
41204564 }));
41214565 Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0;
41224566 switch (elf.shdrPtr(.symtab)) {
......@@ -4156,6 +4600,7 @@ fn initHeaders(
41564600 .flags = .{ .WRITE = true, .ALLOC = true },
41574601 .addralign = addr_align,
41584602 .entsize = @intCast(addr_align.toByteUnits()),
4603 .manual_size = true,
41594604 });
41604605 {
41614606 const init_plt_size = plt.entry_size * plt.header_entries;
......@@ -4168,6 +4613,7 @@ fn initHeaders(
41684613 .size = got_plt.header_entries * elf.targetPtrSize(),
41694614 .addralign = addr_align,
41704615 .entsize = @intCast(addr_align.toByteUnits()),
4616 .manual_size = true,
41714617 });
41724618 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
41734619 .name = ".plt",
......@@ -4176,6 +4622,7 @@ fn initHeaders(
41764622 .size = plt.@"align".forward(init_plt_size),
41774623 .addralign = plt.@"align",
41784624 .node_align = node_block_align,
4625 .manual_size = true,
41794626 });
41804627 } else {
41814628 elf.shndx.plt = try elf.addSection(elf.phdrs.items[phndx.plt].unwrap().?, .{
......@@ -4185,6 +4632,7 @@ fn initHeaders(
41854632 .size = plt.@"align".forward(init_plt_size),
41864633 .addralign = plt.@"align",
41874634 .node_align = node_block_align,
4635 .manual_size = true,
41884636 });
41894637 }
41904638 // And the award for most annoying PLT requirement goes to SPARC, which decided that the
......@@ -4203,13 +4651,15 @@ fn initHeaders(
42034651 .node_align = node_block_align,
42044652 });
42054653 if (maybe_interp) |interp| {
4206 const interp_ni = try elf.ni.rodata.addFloatingChild(&elf.mf, gpa, .{
4207 .size = interp.len + 1,
4208 .moved = true,
4209 .resized = true,
4210 .bubbles_moved = false,
4211 });
4212 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.interp });
4654 const interp_ni = elf.addNodeAssumeCapacity(
4655 try elf.ni.rodata.addFloatingChild(gpa, &elf.mf, .{
4656 .size = interp.len + 1,
4657 .moved = true,
4658 .resized = true,
4659 .bubbles_moved = false,
4660 }),
4661 .{ .segment = phndx.interp },
4662 );
42134663 elf.phdrs.items[phndx.interp] = .wrap(interp_ni);
42144664
42154665 const sec_interp_shndx = try elf.addSection(interp_ni, .{
......@@ -4222,14 +4672,16 @@ fn initHeaders(
42224672 @memcpy(sec_interp[0..interp.len], interp);
42234673 sec_interp[interp.len] = 0;
42244674 }
4225 if (have_dynamic_section) {
4675 if (have_dynamic) {
42264676 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, .{
4228 .alignment = addr_align,
4229 .moved = true,
4230 .bubbles_moved = false,
4231 });
4232 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.dynamic });
4677 const dynamic_ni = elf.addNodeAssumeCapacity(
4678 try elf.ni.data_rel_ro.addFloatingChild(gpa, &elf.mf, .{
4679 .alignment = addr_align,
4680 .moved = true,
4681 .bubbles_moved = false,
4682 }),
4683 .{ .segment = phndx.dynamic },
4684 );
42334685 elf.phdrs.items[phndx.dynamic] = .wrap(dynamic_ni);
42344686
42354687 const dynstr_shndx = try elf.addSection(elf.ni.rodata, .{
......@@ -4239,6 +4691,7 @@ fn initHeaders(
42394691 .size = 1,
42404692 .entsize = 1,
42414693 .node_align = node_block_align,
4694 .manual_size = true,
42424695 });
42434696 dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0;
42444697 elf.shndx.dynstr = dynstr_shndx;
......@@ -4257,6 +4710,7 @@ fn initHeaders(
42574710 .addralign = addr_align,
42584711 .entsize = @sizeOf(Sym),
42594712 .node_align = node_block_align,
4713 .manual_size = true,
42604714 });
42614715 const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class));
42624716 dynsym_null.* = .{
......@@ -4267,7 +4721,7 @@ fn initHeaders(
42674721 .other = .{ .visibility = .DEFAULT },
42684722 .shndx = std.elf.SHN_UNDEF,
42694723 };
4270 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(
4724 if (elf.targetEndian() != std.lang.Endian.native) std.mem.byteSwapAllFields(
42714725 Sym,
42724726 dynsym_null,
42734727 );
......@@ -4285,6 +4739,7 @@ fn initHeaders(
42854739 .addralign = addr_align,
42864740 .entsize = rela_size,
42874741 .node_align = node_block_align,
4742 .manual_size = true,
42884743 });
42894744 elf.shndx.rela_plt = try elf.addSection(elf.ni.rodata, .{
42904745 .name = ".rela.plt",
......@@ -4295,6 +4750,7 @@ fn initHeaders(
42954750 .addralign = addr_align,
42964751 .entsize = rela_size,
42974752 .node_align = node_block_align,
4753 .manual_size = true,
42984754 });
42994755 elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{
43004756 .name = ".dynamic",
......@@ -4303,6 +4759,7 @@ fn initHeaders(
43034759 .link = dynstr_shndx.toSection().?,
43044760 .entsize = @intCast(addr_align.toByteUnits() * 2),
43054761 .addralign = addr_align,
4762 .manual_size = true,
43064763 });
43074764 switch (elf.targetDynsymHashInfo()) {
43084765 inline else => |info| {
......@@ -4318,6 +4775,7 @@ fn initHeaders(
43184775 .addralign = .fromByteUnits(@sizeOf(info.Int())),
43194776 // initially: nbucket = 8 + nchain = 1
43204777 .size = @sizeOf(info.Header()) + @sizeOf(info.Int()) * (8 + 1),
4778 .manual_size = true,
43214779 });
43224780 const hash_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf));
43234781 const header: *info.Header() = @ptrCast(hash_slice[0..@sizeOf(info.Header())]);
......@@ -4386,34 +4844,78 @@ fn initHeaders(
43864844 elf.plt_first_symbol_reloc = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
43874845 try elf.ensureUnusedRelocCapacity(plt_ni, 3);
43884846 elf.addRelocAssumeCapacity(plt_ni, 0, got_plt_sym, 0, .{ .LARCH = .PCALA_HI20 }) catch |err| switch (err) {
4847 else => |e| return e,
43894848 error.UnknownRelocation => unreachable,
43904849 error.NonStaticRelocation => unreachable,
43914850 error.UnimplementedRelocation => unreachable,
4392 else => |e| return e,
43934851 };
43944852 elf.addRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .{ .LARCH = .PCALA_LO12 }) catch |err| switch (err) {
4853 else => |e| return e,
43954854 error.UnknownRelocation => unreachable,
43964855 error.NonStaticRelocation => unreachable,
43974856 error.UnimplementedRelocation => unreachable,
4398 else => |e| return e,
43994857 };
44004858 elf.addRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .{ .LARCH = .PCALA_LO12 }) catch |err| switch (err) {
4859 else => |e| return e,
44014860 error.UnknownRelocation => unreachable,
44024861 error.NonStaticRelocation => unreachable,
44034862 error.UnimplementedRelocation => unreachable,
4404 else => |e| return e,
44054863 };
44064864 },
44074865 .SPARCV9 => {},
44084866 }
44094867 }
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
44114913 // Populate reserved GOT words.
44124914 switch (machine) {
44134915 .AARCH64, .PPC64, .RISCV => @panic(@tagName(machine)),
44144916 .X86_64 => {
44154917 try elf.got.ensureUnusedCapacity(gpa, 3);
4416 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) {
4918 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic) {
44174919 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },
44184920 false => .{ .reserved = 0 },
44194921 }, .none);
......@@ -4422,7 +4924,7 @@ fn initHeaders(
44224924 },
44234925 .LOONGARCH, .SPARCV9 => {
44244926 try elf.got.ensureUnusedCapacity(gpa, 1);
4425 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) {
4927 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic) {
44264928 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },
44274929 false => .{ .reserved = 0 },
44284930 }, .none);
......@@ -4567,7 +5069,7 @@ fn initHeaders(
45675069 }) catch |err| switch (err) {
45685070 error.MultipleDefinitions => unreachable, // no inputs are processed yet
45695071 };
4570 if (have_dynamic_section) {
5072 if (have_dynamic) {
45715073 _ = elf.addGlobalSymbolAssumeCapacity(.{
45725074 .node = .wrap(elf.shndx.dynamic.get(elf).ni),
45735075 .name = try .string(elf, "_DYNAMIC"),
......@@ -4583,13 +5085,57 @@ fn initHeaders(
45835085 }
45845086 } else {
45855087 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 });
45875097 }
45885098 if (elf.ni.tls.unwrap()) |tls_segment_ni| elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{
45895099 .name = ".tdata",
45905100 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
45915101 .node_align = node_block_align,
45925102 });
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
45945140 assert(elf.nodes.len == expected_nodes_len);
45955141 assert(elf.shdrs.items.len == shnum - 1); // -1 to exclude SHN_UNDEF
......@@ -4599,7 +5145,7 @@ fn initHeaders(
45995145 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});
46005146 }
46015147
4602 if (have_dynamic_section) elf.dynamic = .{
5148 if (have_dynamic) elf.dynamic = .{
46035149 .flags = if (elf.options.z_now) std.elf.DF_BIND_NOW else 0,
46045150 .flags_1 = f: {
46055151 var f: u32 = 0;
......@@ -4642,11 +5188,6 @@ fn initHeaders(
46425188pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void {
46435189 prog_node.increaseEstimatedTotalItems(4);
46445190 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 });
46505191 elf.mf.update_prog_node = prog_node.start("Relocations", elf.mf.updates.items.len);
46515192 elf.input_prog_node = prog_node.start("Inputs", (elf.inputs.items.len - elf.input_pending_index) +
46525193 (elf.input_sections.items.len - elf.input_section_pending_index));
......@@ -4657,8 +5198,6 @@ pub fn endProgress(elf: *Elf) void {
46575198 elf.input_prog_node = .none;
46585199 elf.mf.update_prog_node.end();
46595200 elf.mf.update_prog_node = .none;
4660 elf.synth_prog_node.end();
4661 elf.synth_prog_node = .none;
46625201 elf.const_prog_node.end();
46635202 elf.const_prog_node = .none;
46645203}
......@@ -4669,6 +5208,7 @@ fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
46695208/// Asserts that `ni` is a section, input section, copied global, NAV, UAV, or lazy code/data.
46705209fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index {
46715210 return switch (elf.getNode(ni)) {
5211 .deleted,
46725212 .archive,
46735213 .archive_header,
46745214 .archive_input_member,
......@@ -4678,18 +5218,43 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index {
46785218 .shdr,
46795219 .segment,
46805220 => unreachable,
4681 .section => |shndx| shndx,
5221 .section, .section_manual_size => |shndx| shndx,
46825222 .input_section,
46835223 .copied_global,
46845224 .nav,
46855225 .uav,
46865226 .lazy_code,
46875227 .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 },
46895253 };
46905254}
46915255fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
46925256 return switch (elf.getNode(ni)) {
5257 .deleted,
46935258 .archive,
46945259 .archive_header,
46955260 .archive_input_member,
......@@ -4700,17 +5265,37 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
47005265 .segment,
47015266 .copied_global,
47025267 => unreachable,
4703 .section => |shndx| shndx.vaddr(elf),
5268 .section, .section_manual_size => |shndx| shndx.vaddr(elf),
47045269 .input_section => |isi| isi.ptrConst(elf).vaddr,
47055270 inline .nav,
47065271 .uav,
47075272 .lazy_code,
47085273 .lazy_const_data,
47095274 => |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),
47105293 };
47115294}
47125295fn 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,
47145299 .archive,
47155300 .archive_header,
47165301 .archive_input_member,
......@@ -4721,14 +5306,72 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
47215306 .segment => |phndx| switch (elf.phdrSlice()) {
47225307 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),
47235308 },
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),
47255310 .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,
47275333 };
47285334 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);
47295335 return parent_vaddr + offset;
47305336}
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 {
47325375 return ni.fileLocation(&elf.mf, false).offset - elf.ni.elf.fileLocation(&elf.mf, false).offset;
47335376}
47345377
......@@ -4736,9 +5379,16 @@ fn getNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 {
47365379/// sequence of relocations, so that the caller may append the node's updated relocations.
47375380///
47385381/// Asserts that `ni` must be a node which supports relocations (see `Elf.Node`). Does not support
4739/// the special-case sections '.plt' and '.dynamic'.
4740fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
4741 const symbol_relocs: *SymbolReloc.Index, const got_relocs: ?*GotReloc.Index = switch (elf.getNode(ni)) {
5382/// the special-case sections '.plt', '.dynamic', and '.eh_frame_hdr'.
5383pub fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
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,
47425392 .archive,
47435393 .archive_header,
47445394 .archive_input_member,
......@@ -4748,41 +5398,106 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
47485398 .shdr,
47495399 .segment,
47505400 .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,
47515408 => 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)
47535412 .input_section => |isi| .{
4754 &elf.input_sections.items[@backingInt(isi)].first_symbol_reloc,
4755 &elf.input_sections.items[@backingInt(isi)].first_got_reloc,
5413 .first_symbol_reloc = &elf.input_sections.items[@backingInt(isi)].first_symbol_reloc,
5414 .first_got_reloc = &elf.input_sections.items[@backingInt(isi)].first_got_reloc,
47565415 },
47575416 .nav => |nmi| .{
4758 &elf.navs.values()[@backingInt(nmi)].first_symbol_reloc,
4759 &elf.navs.values()[@backingInt(nmi)].first_got_reloc,
5417 .first_symbol_reloc = &elf.navs.values()[@backingInt(nmi)].first_symbol_reloc,
5418 .first_got_reloc = &elf.navs.values()[@backingInt(nmi)].first_got_reloc,
47605419 },
47615420 .uav => |umi| .{
4762 &elf.uavs.values()[@backingInt(umi)].first_symbol_reloc,
4763 null,
5421 .first_symbol_reloc = &elf.uavs.values()[@backingInt(umi)].first_symbol_reloc,
47645422 },
47655423 inline .lazy_code, .lazy_const_data => |lmi| .{
4766 &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,
5424 .first_symbol_reloc = &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_symbol_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,
47685463 },
47695464 };
47705465
4771 if (symbol_relocs.* != .none) {
4772 for (
4773 elf.symbol_relocs.items[@backingInt(symbol_relocs.*)..],
4774 @backingInt(symbol_relocs.*)..,
4775 ) |*reloc, index| {
4776 if (reloc.node != ni) break;
4777 reloc.delete(elf, @fromBackingInt(@intCast(index)));
5466 if (opts.first_symbol_reloc) |ptr| {
5467 if (ptr.* != .none) {
5468 for (elf.symbol_relocs.items[@backingInt(ptr.*)..], @backingInt(ptr.*)..) |*reloc, index| {
5469 if (reloc.node != ni.toOptional()) {
5470 if (reloc.node == .none) continue;
5471 if (reloc.node == opts.skip_symbol_relocs) continue;
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 }
47785490 }
5491 ptr.* = @fromBackingInt(@intCast(elf.node_relocs.items.len));
47795492 }
4780 symbol_relocs.* = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
47815493
4782 if (got_relocs) |ptr| {
5494 if (opts.first_got_reloc) |ptr| {
47835495 if (ptr.* != .none) {
47845496 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 }
47865501 reloc.delete(elf);
47875502 }
47885503 }
......@@ -4796,29 +5511,42 @@ fn flushMovedNodeRelocs(
47965511 elf: *Elf,
47975512 node: MappedFile.Node.Index,
47985513 node_vaddr: u64,
4799 first_symbol_reloc: SymbolReloc.Index,
4800 first_got_reloc: GotReloc.Index,
5514 opts: struct {
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 },
48015521) void {
4802 if (first_symbol_reloc != .none) {
4803 for (elf.symbol_relocs.items[@backingInt(first_symbol_reloc)..]) |*reloc| {
4804 if (reloc.node != node) break;
4805 if (reloc.rela_index.unwrap()) |rela_index| {
4806 // The node has moved, so the offset of the relocation within the section might have
4807 // changed, so update the `offset` field of the `ElfN.Rela` entry.
4808 reloc.relaSection(elf).relaSetOffset(elf, rela_index, node_vaddr + reloc.offset);
4809 }
4810 // This is not just the inverse of the above condition, because if `reloc` is relative
4811 // to the base of this DSO, then `rela_index` is an `R_*_RELATIVE` relocation, but we
4812 // still need to call `SymbolReloc.apply` to update that relocation's addend.
4813 if (elf.ehdrType() != .REL) {
4814 reloc.apply(elf);
5522 if (opts.first_symbol_reloc != .none) {
5523 for (elf.symbol_relocs.items[@backingInt(opts.first_symbol_reloc)..]) |*reloc| {
5524 if (reloc.node != node.toOptional()) {
5525 if (reloc.node == .none) continue;
5526 if (reloc.node == opts.skip_symbol_relocs) continue;
5527 break;
5528 }
5529 reloc.flushMovedNode(elf, node_vaddr);
5530 }
5531 }
5532
5533 if (opts.first_node_reloc != .none) {
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;
48155539 }
5540 reloc.flushMovedNode(elf, node_vaddr);
48165541 }
48175542 }
48185543
4819 if (first_got_reloc != .none) {
4820 for (elf.got_relocs.items[@backingInt(first_got_reloc)..]) |*reloc| {
4821 if (reloc.node != node.toOptional()) break;
5544 if (opts.first_got_reloc != .none) {
5545 for (elf.got_relocs.items[@backingInt(opts.first_got_reloc)..]) |*reloc| {
5546 if (reloc.node != node.toOptional()) {
5547 if (reloc.node == .none) continue;
5548 break;
5549 }
48225550 reloc.apply(elf);
48235551 }
48245552 }
......@@ -5088,13 +5816,12 @@ const ShdrPtr = union(std.elf.CLASS) {
50885816 @"64": *std.elf.Elf64.Shdr,
50895817};
50905818fn 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);
50925820 switch (elf.identClass()) {
50935821 .NONE, _ => unreachable,
50945822 inline else => |class| {
5095 const shdrs_len = elf.shdrs.items.len + 1; // +1 for SHN_UNDEF
50965823 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)],
50985825 ));
50995826 const shdr_ptr = &shdr_slice[@backingInt(shndx)];
51005827 return @unionInit(ShdrPtr, @tagName(class), shdr_ptr);
......@@ -5226,7 +5953,7 @@ fn mapInputSection(elf: *Elf, opts: struct {
52265953 }
52275954
52285955 switch (elf.targetLoad(&shdr.type)) {
5229 .NULL, .PROGBITS => {},
5956 .NULL, .PROGBITS, .X86_64_UNWIND => {},
52305957 else => return error.SectionTypeConflict,
52315958 }
52325959
......@@ -5270,6 +5997,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
52705997 })) |shndx| {
52715998 break :section shndx;
52725999 } else |err| switch (err) {
6000 else => |e| return e,
52736001 error.StripSection,
52746002 error.TlsSectionUnavailable,
52756003 error.UnsupportedSectionFlags,
......@@ -5277,7 +6005,6 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
52776005 error.SectionFlagsConflict,
52786006 => {}, // fall back to default behavior below
52796007
5280 else => |e| return e,
52816008 }
52826009 }
52836010 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
52946021 .@"fn" => a: {
52956022 const mod = zcu.navFileScope(nav_index).mod.?;
52966023 const target = &mod.resolved_target.result;
5297 const min = target_util.minFunctionAlignment(target);
52986024 break :a .fromIp(switch (nav.resolved.?.@"align") {
5299 else => |a| a.maxStrict(min),
6025 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
53006026 .none => switch (mod.optimize_mode) {
5301 .debug,
5302 .safe,
5303 .fast,
5304 => target_util.defaultFunctionAlignment(target),
5305 .small => min,
6027 .debug, .safe, .fast => target_util.defaultFunctionAlignment(target),
6028 .small => target_util.minFunctionAlignment(target),
53066029 }.maxStrict(Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu)),
53076030 });
53086031 },
......@@ -5312,9 +6035,9 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
53126035 },
53136036 };
53146037 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, .{
53166039 .alignment = alignment,
5317 });
6040 }), .{ .nav = nmi });
53186041 nav_gop.value_ptr.* = .{
53196042 .lsi = elf.addLocalSymbolAssumeCapacity(.{
53206043 .node = .wrap(node),
......@@ -5327,7 +6050,6 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
53276050 .first_symbol_reloc = .none,
53286051 .first_got_reloc = .none,
53296052 };
5330 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
53316053 }
53326054 return nmi;
53336055}
......@@ -5356,16 +6078,12 @@ fn uavMapIndex(
53566078 if (!uav_gop.found_existing) {
53576079 const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs
53586080 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, .{
53606082 .moved = true, // see assert at end of `genUav`
53616083 .alignment = resolved_align,
5362 });
5363 var name_buf: [32]u8 = undefined;
5364 const name = std.mem.print(
5365 &name_buf,
5366 "__anon_{d}",
5367 .{@backingInt(uav_val)},
5368 ) catch unreachable;
6084 }), .{ .uav = umi });
6085 var name_buf: [std.fmt.count("__anon_{d}", .{std.math.maxInt(u32)})]u8 = undefined;
6086 const name = std.mem.print(&name_buf, "__anon_{d}", .{umi}) catch unreachable;
53696087 uav_gop.value_ptr.* = .{
53706088 .lsi = elf.addLocalSymbolAssumeCapacity(.{
53716089 .node = .wrap(node),
......@@ -5377,15 +6095,14 @@ fn uavMapIndex(
53776095 }),
53786096 .first_symbol_reloc = .none,
53796097 };
5380 elf.nodes.appendAssumeCapacity(.{ .uav = umi });
53816098 elf.const_prog_node.increaseEstimatedTotalItems(1);
53826099 elf.pending_uavs.appendAssumeCapacity(umi);
53836100 } else {
53846101 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);
53866103 try shndx.ensureAligned(elf, resolved_align);
53876104 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);
53896106 }
53906107 }
53916108 return umi;
......@@ -5518,9 +6235,9 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load
55186235 return error.BadMagic;
55196236 }
55206237 }
5521 var strtab: std.Io.Writer.Allocating = .init(gpa);
6238 var strtab: Io.Writer.Allocating = .init(gpa);
55226239 defer strtab.deinit();
5523 while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| {
6240 while (r.takeStruct(std.elf.ar_hdr, .native)) |header| {
55246241 if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG))
55256242 return diags.failParse(path, "bad file magic", .{});
55266243 const offset = fr.logicalPos();
......@@ -5530,8 +6247,8 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load
55306247 strtab.clearRetainingCapacity();
55316248 try strtab.ensureTotalCapacityPrecise(size);
55326249 r.streamExact(&strtab.writer, size) catch |err| switch (err) {
5533 error.WriteFailed => return error.OutOfMemory,
55346250 else => |e| return e,
6251 error.WriteFailed => return error.OutOfMemory,
55356252 };
55366253 continue;
55376254 }
......@@ -5562,14 +6279,14 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load
55626279 }
55636280 try fr.seekTo(std.mem.alignForward(u64, offset + size, 2));
55646281 } else |err| switch (err) {
5565 error.EndOfStream => if (!fr.atEnd()) return error.EndOfStream,
55666282 else => |e| return e,
6283 error.EndOfStream => if (!fr.atEnd()) return error.EndOfStream,
55676284 }
55686285}
55696286fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEscape) {
55706287 return .{ .data = member };
55716288}
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 {
55736290 try w.print("({f})", .{std.zig.fmtString(member orelse return)});
55746291}
55756292fn loadObject(
......@@ -5614,11 +6331,13 @@ fn loadObject(
56146331 };
56156332
56166333 try elf.nodes.ensureUnusedCapacity(gpa, 1);
5617 const new_member_ni = try archive.ni.addFooterChildBefore(&elf.mf, gpa, first_member_oni, .{
5618 .size = Alignment.@"2".forward(@sizeOf(std.elf.ar_hdr) + fl.size),
5619 .alignment = .@"2",
5620 });
5621 elf.nodes.appendAssumeCapacity(.{ .archive_input_member = input_index });
6334 const new_member_ni = elf.addNodeAssumeCapacity(
6335 try archive.ni.addFooterChildBefore(gpa, &elf.mf, first_member_oni, .{
6336 .size = Alignment.@"2".forward(@sizeOf(std.elf.ar_hdr) + fl.size),
6337 .alignment = .@"2",
6338 }),
6339 .{ .archive_input_member = input_index },
6340 );
56226341 input.extra = .{ .node = new_member_ni };
56236342 elf.input_prog_node.increaseEstimatedTotalItems(1);
56246343
......@@ -5717,18 +6436,19 @@ fn loadObject(
57176436 for (sections[1..]) |*section| {
57186437 if (section.shdr.name >= shstrtab.len) continue;
57196438 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;
57206440 const opts: struct {
57216441 shndx: Section.Index,
5722 has_file_bits: bool,
57236442 node_fixed: bool,
57246443 } = switch (section.shdr.type) {
57256444 else => continue,
5726 .PROGBITS, .NOBITS => opts: {
6445 .PROGBITS, .NOBITS, .X86_64_UNWIND => opts: {
57276446 const shndx = elf.mapInputSection(.{
57286447 .name = name,
57296448 .flags = section.shdr.flags.shf,
57306449 .entsize = section.shdr.entsize,
57316450 }) catch |err| switch (err) {
6451 else => |e| return e,
57326452 error.StripSection => continue,
57336453 error.TlsSectionUnavailable => return diags.failParse(
57346454 path,
......@@ -5759,7 +6479,6 @@ fn loadObject(
57596479 "flags of section '{s}' conflict with other inputs",
57606480 .{name},
57616481 ),
5762 else => |e| return e,
57636482 };
57646483 if (section.shdr.flags.shf.COMPRESSED) {
57656484 // SHF_COMPRESSED is only allowed on non-alloc sections.
......@@ -5776,7 +6495,6 @@ fn loadObject(
57766495 }
57776496 break :opts .{
57786497 .shndx = shndx,
5779 .has_file_bits = section.shdr.type == .PROGBITS,
57806498 // For well-known sections, we know that it's fine to have e.g. random
57816499 // padding, so there's no need to make the sections fixed. For custom
57826500 // sections, however, we do want fixed nodes to avoid padding.
......@@ -5819,7 +6537,6 @@ fn loadObject(
58196537 }
58206538 break :shndx shndx.*;
58216539 },
5822 .has_file_bits = true,
58236540 // This node must be fixed to prevent padding from being added between different
58246541 // INIT_ARRAY/FINI_ARRAY/PREINIT_ARRAY input sections.
58256542 .node_fixed = true,
......@@ -5834,28 +6551,26 @@ fn loadObject(
58346551 .alignment = need_align,
58356552 .moved = true, // see assert at end of `flushInputSection`
58366553 };
5837 const ni = if (opts.node_fixed) ni: {
5838 const shndx_ni = opts.shndx.get(elf).ni;
5839 const after_oni: MappedFile.Node.Index.Optional = after: {
5840 const last_ni = shndx_ni.last(&elf.mf).unwrap() orelse break :after .none;
5841 break :after switch (last_ni.position(&elf.mf)) {
5842 .header => .wrap(last_ni),
5843 .footer, .floating => .none,
6554 const ni = elf.addNodeAssumeCapacity(
6555 if (opts.node_fixed) ni: {
6556 const shndx_ni = opts.shndx.get(elf).ni;
6557 const after_oni: MappedFile.Node.Index.Optional = after: {
6558 const last_ni = shndx_ni.last(&elf.mf).unwrap() orelse break :after .none;
6559 break :after switch (last_ni.position(&elf.mf)) {
6560 .header => .wrap(last_ni),
6561 .footer, .floating => .none,
6562 };
58446563 };
5845 };
5846 break :ni try shndx_ni.addHeaderChildAfter(&elf.mf, gpa, after_oni, add_node_opts);
5847 } else ni: {
5848 break :ni try opts.shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, add_node_opts);
5849 };
5850 elf.nodes.appendAssumeCapacity(.{
5851 .input_section = @fromBackingInt(@intCast(elf.input_sections.items.len)),
5852 });
6564 break :ni try shndx_ni.addHeaderChildAfter(gpa, &elf.mf, after_oni, add_node_opts);
6565 } else try opts.shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, add_node_opts),
6566 .{ .input_section = @fromBackingInt(@intCast(elf.input_sections.items.len)) },
6567 );
58536568 section.isi = @fromBackingInt(@intCast(elf.input_sections.items.len));
58546569 elf.input_sections.addOneAssumeCapacity().* = .{
58556570 .input = input_index,
58566571 .file_location = .{
58576572 .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,
58596574 },
58606575 // The section vaddr is initially 0, because the symbol addresses are
58616576 // zero-based. This will eventually be updated by `flushMoved`.
......@@ -6043,6 +6758,7 @@ fn loadObject(
60436758 rel.addend,
60446759 rt,
60456760 ) catch |err| switch (err) {
6761 else => |e| return e,
60466762 error.UnknownRelocation => diags.addParseError(
60476763 path,
60486764 "unknown relocation type '{f}'",
......@@ -6058,7 +6774,6 @@ fn loadObject(
60586774 "TODO(Elf2): unimplemented relocation type '{f}'",
60596775 .{rt.fmt(elf)},
60606776 ),
6061 else => |e| return e,
60626777 };
60636778 }
60646779 },
......@@ -6102,7 +6817,7 @@ fn populateArchiveMemberName(elf: *Elf, member_ar_hdr: *std.elf.ar_hdr, member_n
61026817 // We set the size of the archive header node exactly, because we want padding bytes to go into
61036818 // the root `.archive` node. That way, those bytes could still be used to grow the string table
61046819 // 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
61076822 const dest_slice = archive_header_ni.slice(&elf.mf)[@intCast(old_archive_header_size)..];
61086823 @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
62546969 // We have a copy relocation for this global, but the amount of space we
62556970 // reserved for it could be too small or underaligned!
62566971 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));
6258 try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment);
6972 try copied_global.node.resizeLeaf(
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);
62596978 const global_ptr = elf.globalByName(name).?;
62606979 switch (elf.symPtr(global_ptr.symtab_index)) {
62616980 inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)),
......@@ -6407,6 +7126,7 @@ fn createInitFiniArraySection(
64077126 .type = @"type",
64087127 .flags = .{ .WRITE = true, .ALLOC = true },
64097128 .node_align = addr_align,
7129 .manual_size = true,
64107130 });
64117131 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});
64127132 try elf.ensureUnusedSymbolCapacity(2, .maybe_global);
......@@ -6454,8 +7174,9 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) link.Error!void {
64547174fn prelinkInner(elf: *Elf) Error!void {
64557175 const comp = elf.base.comp;
64567176 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) {
64597180 // We're using self-hosted codegen---add an input representing the Zig "object".
64607181 try elf.ensureUnusedSymbolCapacity(1, .all_local);
64617182 try elf.inputs.ensureUnusedCapacity(gpa, 1);
......@@ -6475,7 +7196,226 @@ fn prelinkInner(elf: *Elf) Error!void {
64757196 .extra = .{ .file_symbol = zcu_file_symbol },
64767197 };
64777198 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 }
64787384 }
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 };
64797419}
64807420
64817421fn prepareDynamic(elf: *Elf) Error!void {
......@@ -6500,7 +7440,7 @@ fn prepareDynamic(elf: *Elf) Error!void {
65007440
65017441 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);
65047444 switch (elf.shdrPtr(elf.shndx.dynamic)) {
65057445 inline else => |shdr| elf.targetStore(&shdr.size, @intCast(dynamic_size)),
65067446 }
......@@ -6610,7 +7550,7 @@ fn flushDynamic(elf: *Elf) void {
66107550 dynamic_index += 9;
66117551
66127552 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|
66147554 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);
66157555 },
66167556 }
......@@ -6626,6 +7566,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
66267566 addralign: Alignment = .@"1",
66277567 entsize: std.elf.Word = 0,
66287568 node_align: Alignment = .@"1",
7569 manual_size: bool = false,
66297570}) Error!Section.Index {
66307571 switch (opts.type) {
66317572 .NULL => assert(opts.size == 0),
......@@ -6639,7 +7580,11 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
66397580 const gpa = elf.base.comp.gpa;
66407581 try elf.nodes.ensureUnusedCapacity(gpa, 1);
66417582 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
66447589 const shstrtab_entry = try elf.string(.shstrtab, opts.name);
66457590 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 {
66697614 break :shndx .{ @fromBackingInt(shndx), @as(u64, elf.targetLoad(&ehdr.shentsize)) * @as(u64, shnum) };
66707615 },
66717616 };
6672 try elf.ni.shdr.ensureMinimumSize(&elf.mf, gpa, new_shdr_size);
7617 try elf.ni.shdr.ensureMinimumSize(gpa, &elf.mf, new_shdr_size);
66737618 const parent_ni = switch (elf.ehdrType()) {
66747619 .REL => elf.ni.elf,
66757620 .EXEC, .DYN => segment_ni,
66767621 };
66777622 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, .{
66797624 .size = opts.node_align.forward(opts.size),
66807625 .alignment = opts.addralign.max(opts.node_align),
66817626 .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 },
66827631 });
66837632 const addr = elf.computeNodeVAddr(ni);
6684 const lsi: Symbol.LocalIndex = if (opts.flags.ALLOC) elf.addLocalSymbolAssumeCapacity(.{
6685 .node = .wrap(ni),
6686 .name = .empty,
6687 .value = addr,
6688 .size = 0,
6689 .type = .SECTION,
6690 .shndx = shndx,
6691 }) else .null;
6692 elf.shdrs.appendAssumeCapacity(.{ .lsi = lsi, .ni = ni, .rela = switch (opts.type) {
6693 .REL => unreachable,
6694 .RELA => .{ .free_head = .none },
6695 else => .{ .shndx = .UNDEF },
6696 } });
6697 elf.nodes.appendAssumeCapacity(.{ .section = shndx });
7633 elf.shdrs.appendAssumeCapacity(.{
7634 .lsi = if (want_symbol) elf.addLocalSymbolAssumeCapacity(.{
7635 .node = ni.toOptional(),
7636 .name = .empty,
7637 .value = addr,
7638 .size = 0,
7639 .type = .SECTION,
7640 .shndx = shndx,
7641 }) else .null,
7642 .ni = ni,
7643 .rela = switch (opts.type) {
7644 .REL => unreachable,
7645 .RELA => .{ .free_head = .none },
7646 else => .{ .shndx = .UNDEF },
7647 },
7648 });
66987649 switch (elf.shdrPtr(shndx)) {
66997650 inline else => |shdr, class| {
67007651 shdr.* = .{
......@@ -6702,14 +7653,14 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
67027653 .type = opts.type,
67037654 .flags = .{ .shf = opts.flags },
67047655 .addr = @intCast(addr),
6705 .offset = @intCast(elf.getNodeElfOffset(ni)),
7656 .offset = @intCast(elf.computeNodeElfOffset(ni)),
67067657 .size = @intCast(opts.size),
67077658 .link = opts.link,
67087659 .info = opts.info,
67097660 .addralign = @intCast(opts.addralign.toByteUnits()),
67107661 .entsize = opts.entsize,
67117662 };
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);
67137664 },
67147665 }
67157666 return shndx;
......@@ -6719,6 +7670,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
67197670 if (len == 0) return;
67207671 const gpa = elf.base.comp.gpa;
67217672 try elf.symbol_relocs.ensureUnusedCapacity(gpa, len);
7673 try elf.node_relocs.ensureUnusedCapacity(gpa, len);
67227674 try elf.got_relocs.ensureUnusedCapacity(gpa, len);
67237675 const class = elf.identClass();
67247676 switch (elf.ehdrType()) {
......@@ -6749,6 +7701,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
67497701 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
67507702 },
67517703 .node_align = elf.mf.flags.block_size,
7704 .manual_size = true,
67527705 });
67537706 elf.section_by_name.putAssumeCapacityNoClobber(rela_shndx.name(elf), {});
67547707 shndx.get(elf).rela.shndx = rela_shndx;
......@@ -6763,7 +7716,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
67637716 .NONE, _ => unreachable,
67647717 inline else => |ct_class| (elf.got.count() + new_got_entries) * @sizeOf(ct_class.ElfN().Addr),
67657718 };
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
67687721 if (elf.shndx.dynamic != .UNDEF) {
67697722 try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, new_got_entries);
......@@ -6795,17 +7748,12 @@ fn addRelocAssumeCapacity(
67957748 .addend = addend,
67967749 });
67977750 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
6798 const next: SymbolReloc.Index = next: {
6799 const target_ptr = target.index(elf).ptr(elf);
6800 const next = target_ptr.first_target_reloc;
6801 target_ptr.first_target_reloc = ri;
6802 break :next next;
6803 };
6804 if (next != .none) {
6805 next.get(elf).prev = ri;
6806 }
7751 const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc;
7752 const next = first_target_reloc.*;
7753 first_target_reloc.* = ri;
7754 if (next != .none) next.get(elf).prev = ri;
68077755 elf.symbol_relocs.appendAssumeCapacity(.{
6808 .node = node,
7756 .node = node.toOptional(),
68097757 .offset = offset,
68107758 .type = undefined,
68117759 .target = target,
......@@ -6816,7 +7764,6 @@ fn addRelocAssumeCapacity(
68167764 .result = .ok,
68177765 });
68187766 },
6819
68207767 .DYN, .EXEC => switch (elf.ehdrMachine()) {
68217768 .AARCH64 => switch (@"type".AARCH64) {
68227769 .NONE => {},
......@@ -7239,14 +8186,12 @@ fn addSymbolRelocAssumeCapacity(
72398186 };
72408187
72418188 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
7242 const target_ptr = target.index(elf).ptr(elf);
7243 const next = target_ptr.first_target_reloc;
7244 target_ptr.first_target_reloc = ri;
7245 if (next != .none) {
7246 next.get(elf).prev = ri;
7247 }
8189 const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc;
8190 const next = first_target_reloc.*;
8191 first_target_reloc.* = ri;
8192 if (next != .none) next.get(elf).prev = ri;
72488193 elf.symbol_relocs.appendAssumeCapacity(.{
7249 .node = node,
8194 .node = node.toOptional(),
72508195 .offset = offset,
72518196 .target = target,
72528197 .addend = addend,
......@@ -7263,6 +8208,103 @@ fn addSymbolRelocAssumeCapacity(
72638208 // Actually apply the new relocation!
72648209 ri.get(elf).apply(elf);
72658210}
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}
72668308fn addGotRelocAssumeCapacity(
72678309 elf: *Elf,
72688310 node: MappedFile.Node.Index,
......@@ -7273,6 +8315,7 @@ fn addGotRelocAssumeCapacity(
72738315) void {
72748316 assert(elf.ehdrType() != .REL);
72758317 switch (elf.getNode(node)) {
8318 .deleted,
72768319 .archive,
72778320 .archive_header,
72788321 .archive_input_member,
......@@ -7282,8 +8325,26 @@ fn addGotRelocAssumeCapacity(
72828325 .shdr,
72838326 .segment,
72848327 .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,
72858345 => unreachable, // cannot contain relocs,
72868346 .section,
8347 .section_manual_size,
72878348 .uav,
72888349 => unreachable, // cannot contain GOT relocs
72898350 .input_section,
......@@ -7519,14 +8580,13 @@ fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool {
75198580 try Section.Index.data.ensureAligned(elf, dso_global.alignment);
75208581
75218582 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, .{
75238584 .size = dso_global.alignment.forward(dso_global.size),
75248585 .alignment = dso_global.alignment,
75258586 });
75268587 errdefer comptime unreachable;
75278588
75288589 const vaddr = elf.computeNodeVAddr(node);
7529 elf.nodes.appendAssumeCapacity(.{ .copied_global = global_name });
75308590 const rela_index = elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{
75318591 .type = .copy(elf),
75328592 .offset = vaddr,
......@@ -7555,10 +8615,12 @@ fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool {
75558615}
75568616
75578617pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void {
7558 const diags = &elf.base.comp.link_diags;
75598618 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.?}),
75618619 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 ),
75628624 };
75638625}
75648626fn 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)
75688630
75698631 const nav = ip.getNav(nav_index);
75708632 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
75738639 const nmi = try elf.navMapIndex(zcu, nav_index);
75748640 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;
7575 elf.resetNodeRelocs(ni);
75768641
75778642 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
75788643 // called to apply the NAV's new relocations.
......@@ -7580,8 +8645,9 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
75808645
75818646 {
75828647 var nw: MappedFile.Node.Writer = undefined;
7583 ni.writer(&elf.mf, gpa, &nw);
8648 ni.writer(gpa, &elf.mf, &nw);
75848649 defer nw.deinit();
8650 elf.resetNodeRelocs(ni);
75858651 codegen.generateSymbol(
75868652 &elf.base,
75878653 pt,
......@@ -7589,16 +8655,153 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
75898655 &nw.interface,
75908656 .{ .atom_index = Node.toAtom(ni) },
75918657 ) catch |err| switch (err) {
7592 error.WriteFailed => return nw.err.?,
75938658 else => |e| return e,
8659 error.WriteFailed => return nw.err.?,
75948660 };
75958661 switch (elf.symPtr(nmi.symbol(elf).index())) {
75968662 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
75978663 }
75988664 }
75998665
7600 // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs.
7601 try elf.genPending(pt);
8666 // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs.
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);
76028805}
76038806
76048807pub fn updateFunc(
......@@ -7607,10 +8810,12 @@ pub fn updateFunc(
76078810 func_index: InternPool.Index,
76088811 mir: *const codegen.AnyMir,
76098812) link.Error!void {
7610 const diags = &elf.base.comp.link_diags;
76118813 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.?}),
76138814 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 ),
76148819 };
76158820}
76168821fn updateFuncInner(
......@@ -7627,8 +8832,8 @@ fn updateFuncInner(
76278832
76288833 const nmi = try elf.navMapIndex(zcu, func.owner_nav);
76298834 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) });
7630 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;
7631 elf.resetNodeRelocs(ni);
8835 const lsi = nmi.symbol(elf);
8836 const ni = lsi.index().ptr(elf).node.unwrap().?;
76328837
76338838 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
76348839 // called to apply the NAV's new relocations.
......@@ -7636,8 +8841,145 @@ fn updateFuncInner(
76368841
76378842 {
76388843 var nw: MappedFile.Node.Writer = undefined;
7639 ni.writer(&elf.mf, gpa, &nw);
8844 ni.writer(gpa, &elf.mf, &nw);
76408845 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);
76418983 codegen.emitFunction(
76428984 &elf.base,
76438985 pt,
......@@ -7645,29 +8987,101 @@ fn updateFuncInner(
76458987 Node.toAtom(ni),
76468988 mir,
76478989 &nw.interface,
7648 .none,
8990 debug_output,
76498991 ) catch |err| switch (err) {
7650 error.WriteFailed => return nw.err.?,
76518992 else => |e| return e,
8993 error.WriteFailed => if (nw.err) |e| return e,
76528994 };
8995 const func_length = nw.interface.end;
76538996 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 => {},
76559037 }
76569038 }
76579039
76589040 // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs.
76599041 try elf.genPending(pt);
9042 try elf.dwarf.const_pool.flushPending(pt, .{ .elf2 = elf });
76609043}
76619044
7662pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void {
7663 const diags = &elf.base.comp.link_diags;
7664 elf.genLazy(pt, .{
7665 .kind = .const_data,
7666 .index = @intCast(elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return),
7667 }) catch |err| switch (err) {
7668 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
9045pub fn updateLineNumber(
9046 elf: *Elf,
9047 _: Zcu.PerThread,
9048 inst: InternPool.TrackedInst.Index,
9049 line: u32,
9050) void {
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) {
76699067 else => |e| return e,
9068 error.WriteFailed => unreachable,
76709069 };
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);
76719085}
76729086
76739087pub fn flush(
......@@ -7677,8 +9091,11 @@ pub fn flush(
76779091 prog_node: std.Progress.Node,
76789092) link.Error!void {
76799093 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.?}),
76819094 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 ),
76829099 };
76839100}
76849101fn flushInner(
......@@ -7694,6 +9111,8 @@ fn flushInner(
76949111 const sub_prog_node = prog_node.start("ELF Flush", 0);
76959112 defer sub_prog_node.end();
76969113
9114 try elf.flushFiles();
9115
76979116 if (comp.config.output_mode == .Exe) {
76989117 var any_undef = false;
76999118 for (elf.globals.strong_undef.keys()) |name| {
......@@ -7708,8 +9127,13 @@ fn flushInner(
77089127
77099128 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
77119133 // We've done the final `idle` loop, so everything is at its final place in the file. We have a
77129134 // 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
77149138 if (elf.overflowed_reloc_count > 0) {
77159139 diags.addError("failed to apply {d} relocations: overflow", .{elf.overflowed_reloc_count});
......@@ -7753,20 +9177,19 @@ fn flushInner(
77539177
77549178 if (elf.options.enable_link_snapshots)
77559179 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});
77579181}
77589182
77599183pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {
7760 const comp = elf.base.comp;
7761 const diags = &comp.link_diags;
7762
9184 // This function is called non-deterministically, and so must not affect the layout of any nodes.
77639185 elf.mf.nodes_lock.lock();
77649186 defer elf.mf.nodes_lock.unlock();
77659187
9188 const comp = elf.base.comp;
9189 const diags = &comp.link_diags;
9190
77669191 assert(elf.pending_uavs.items.len == 0);
7767 for (&elf.lazy.values) |*lazy| {
7768 assert(lazy.pending_index == lazy.map.count());
7769 }
9192 assert(elf.dwarf.const_pool.pending.items.len == 0);
77709193
77719194 task: {
77729195 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 {
77759198 const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(ii.node(elf)));
77769199 defer sub_prog_node.end();
77779200 elf.flushInput(ii) catch |err| switch (err) {
7778 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
77799201 else => |e| return e,
9202 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
77809203 };
77819204 break :task;
77829205 }
......@@ -7786,8 +9209,8 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {
77869209 const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.node(elf)));
77879210 defer sub_prog_node.end();
77889211 elf.flushInputSection(isi) catch |err| switch (err) {
7789 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
77909212 else => |e| return e,
9213 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
77919214 };
77929215 break :task;
77939216 }
......@@ -7885,18 +9308,18 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {
78859308
78869309 break :task;
78879310 }
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;
78899313 const clean_moved = ni.cleanMoved(&elf.mf);
78909314 const clean_resized = ni.cleanResized(&elf.mf);
78919315 const clean_next_moved = ni.cleanNextMoved(&elf.mf);
7892 if (clean_moved or clean_resized or clean_next_moved) {
7893 const sub_prog_node = elf.idleProgNode(tid, elf.mf.update_prog_node, elf.getNode(ni));
7894 defer sub_prog_node.end();
7895 if (clean_moved) try elf.flushMoved(ni);
7896 if (clean_resized) try elf.flushResized(ni);
7897 if (clean_next_moved) try elf.flushNextMoved(ni);
7898 break :task;
7899 } else elf.mf.update_prog_node.completeOne();
9316 if (!clean_moved and !clean_resized and !clean_next_moved) continue;
9317 const sub_prog_node = elf.idleProgNode(tid, elf.mf.update_prog_node, elf.getNode(ni));
9318 defer sub_prog_node.end();
9319 if (clean_moved) try elf.flushMoved(ni);
9320 if (clean_resized) try elf.flushResized(ni);
9321 if (clean_moved or clean_resized or clean_next_moved) try elf.flushPadding(ni);
9322 break :task;
79009323 }
79019324 }
79029325 if (elf.input_sections.items.len > elf.input_section_pending_index) return true;
......@@ -7915,62 +9338,119 @@ fn idleProgNode(
79159338 var name: [std.Progress.Node.max_name_len]u8 = undefined;
79169339 return prog_node.start(name: switch (node) {
79179340 else => |tag| @tagName(tag),
7918 .section => |shndx| shndx.name(elf).slice(elf),
79199341 .archive_input_member => |ii| std.mem.print(&name, "{f}{f}", .{
79209342 ii.path(elf).fmtEscapeString(),
79219343 fmtMemberString(ii.member(elf)),
79229344 }) catch &name,
9345 .section, .section_manual_size => |shndx| shndx.name(elf).slice(elf),
79239346 .input_section => |isi| {
79249347 const ii = isi.input(elf);
79259348 break :name std.mem.print(&name, "{f}{f} {s}", .{
79269349 ii.path(elf).fmtEscapeString(),
79279350 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),
79299352 }) catch &name;
79309353 },
79319354 .nav => |nmi| {
79329355 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);
79349357 },
79359358 .uav => |umi| std.mem.print(&name, "{f}", .{
79369359 Value.fromInterned(umi.uavValue(elf)).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
79379360 }) 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 },
79389418 }, 0);
79399419}
79409420
7941fn genPending(elf: *Elf, pt: Zcu.PerThread) Error!void {
7942 const zcu = elf.base.comp.zcu.?;
7943 pending: while (true) {
7944 if (elf.pending_uavs.pop()) |umi| {
7945 var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined;
7946 const prog_name = std.mem.print(&prog_name_buf, "{f}", .{
7947 Value.fromInterned(umi.uavValue(elf)).fmtValue(pt),
7948 }) catch &prog_name_buf;
7949 const prog_node = elf.const_prog_node.start(prog_name, 0);
7950 defer prog_node.end();
7951 try elf.genUav(pt, umi);
7952 continue :pending;
7953 }
7954 var lazy_it = elf.lazy.iterator();
7955 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {
7956 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };
7957 lazy.value.pending_index += 1;
7958 const lazy_ty: Type = .fromInterned(lmr.lazySymbol(elf).ty);
7959 var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined;
7960 const prog_name: []const u8 = switch (lazy_ty.zigTypeTag(zcu)) {
7961 .@"enum" => std.mem.print(&prog_name_buf, "@tagName({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf,
7962 .error_set => switch (lmr.kind) {
7963 .code => std.mem.print(&prog_name_buf, "@errorCast({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf,
7964 .const_data => "@errorName",
7965 },
7966 else => unreachable,
7967 };
7968 const prog_node = elf.synth_prog_node.start(prog_name, 0);
7969 defer prog_node.end();
7970 try elf.genLazy(pt, lmr);
7971 continue :pending;
7972 };
7973 break;
9421fn genPending(elf: *Elf, pt: Zcu.PerThread) link.Error!void {
9422 while (elf.pending_uavs.pop()) |umi| {
9423 var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined;
9424 const prog_name = std.mem.print(&prog_name_buf, "{f}", .{
9425 Value.fromInterned(umi.uavValue(elf)).fmtValue(pt),
9426 }) catch &prog_name_buf;
9427 const prog_node = elf.const_prog_node.start(prog_name, 0);
9428 defer prog_node.end();
9429 try elf.genUav(pt, umi);
9430 }
9431 var lazy_it = elf.lazy.iterator();
9432 while (lazy_it.next()) |lazy| while (lazy.value.pending_index < lazy.value.map.count()) {
9433 try elf.genLazy(pt, .{ .kind = lazy.key, .index = lazy.value.pending_index });
9434 lazy.value.pending_index += 1;
9435 };
9436 switch (elf.base.comp.config.debug_format) {
9437 .strip => {},
9438 .dwarf => {
9439 const gpa = elf.base.comp.gpa;
9440 while (true) {
9441 const pending = elf.dwarf.pending_decl;
9442 if (pending.instance_val == .none) break;
9443 elf.dwarf.pending_decl = .{ .di = undefined, .instance_val = .none };
9444 const debug_info_ni = pending.di.get(&elf.dwarf).debug_info_ni.unwrap().?;
9445 try debug_info_ni.moved(gpa, &elf.mf);
9446 var di_nw: MappedFile.Node.Writer = undefined;
9447 debug_info_ni.writer(gpa, &elf.mf, &di_nw);
9448 defer di_nw.deinit();
9449 elf.resetNodeRelocs(debug_info_ni);
9450 try elf.dwarf.genDecl(pt, &di_nw, pending.instance_val);
9451 }
9452 },
9453 .code_view => unreachable,
79749454 }
79759455}
79769456
......@@ -7978,17 +9458,17 @@ fn genUav(
79789458 elf: *Elf,
79799459 pt: Zcu.PerThread,
79809460 umi: Node.UavMapIndex,
7981) Error!void {
9461) link.Error!void {
79829462 const comp = elf.base.comp;
79839463 const gpa = comp.gpa;
79849464
79859465 const uav_val = umi.uavValue(elf);
79869466 const ni = umi.symbol(elf).index().ptr(elf).node.unwrap().?;
7987 elf.resetNodeRelocs(ni);
79889467
79899468 var nw: MappedFile.Node.Writer = undefined;
7990 ni.writer(&elf.mf, gpa, &nw);
9469 ni.writer(gpa, &elf.mf, &nw);
79919470 defer nw.deinit();
9471 elf.resetNodeRelocs(ni);
79929472 codegen.generateSymbol(
79939473 &elf.base,
79949474 pt,
......@@ -7996,8 +9476,11 @@ fn genUav(
79969476 &nw.interface,
79979477 .{ .atom_index = Node.toAtom(ni) },
79989478 ) catch |err| switch (err) {
7999 error.WriteFailed => return nw.err.?,
80009479 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 },
80019484 };
80029485 switch (elf.symPtr(umi.symbol(elf).index())) {
80039486 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
......@@ -8007,13 +9490,29 @@ fn genUav(
80079490 assert(ni.hasMoved(&elf.mf));
80089491}
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 {
80119511 const zcu = pt.zcu;
80129512 const gpa = zcu.gpa;
80139513
80149514 const lazy = lmr.lazySymbol(elf);
80159515 const ni = lmr.symbol(elf).index().ptr(elf).node.unwrap().?;
8016 elf.resetNodeRelocs(ni);
80179516
80189517 // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually
80199518 // 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 {
80219520
80229521 var required_alignment: InternPool.Alignment = .none;
80239522 var nw: MappedFile.Node.Writer = undefined;
8024 ni.writer(&elf.mf, gpa, &nw);
9523 ni.writer(gpa, &elf.mf, &nw);
80259524 defer nw.deinit();
9525 elf.resetNodeRelocs(ni);
80269526 codegen.generateLazySymbol(
80279527 &elf.base,
80289528 pt,
......@@ -8032,8 +9532,14 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {
80329532 .none,
80339533 .{ .atom_index = Node.toAtom(ni) },
80349534 ) catch |err| switch (err) {
8035 error.WriteFailed => return nw.err.?,
80369535 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 },
80379543 };
80389544 switch (elf.symPtr(lmr.symbol(elf).index())) {
80399545 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
......@@ -8104,18 +9610,18 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {
81049610 fr.seekTo(file_loc.offset) catch |err| switch (err) {
81059611 error.Canceled => |e| return e,
81069612 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),
81089614 path.fmtEscapeString(),
81099615 fmtMemberString(ii.member(elf)),
81109616 e,
81119617 }),
81129618 };
81139619 var nw: MappedFile.Node.Writer = undefined;
8114 isi.node(elf).writer(&elf.mf, gpa, &nw);
9620 isi.node(elf).writer(gpa, &elf.mf, &nw);
81159621 defer nw.deinit();
81169622 const n_bytes = nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) catch |err| switch (err) {
81179623 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),
81199625 path.fmtEscapeString(),
81209626 fmtMemberString(ii.member(elf)),
81219627 fr.err orelse (fr.seek_err orelse fr.size_err.?),
......@@ -8123,7 +9629,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {
81239629 error.WriteFailed => return nw.err.?,
81249630 };
81259631 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),
81279633 path.fmtEscapeString(),
81289634 fmtMemberString(ii.member(elf)),
81299635 });
......@@ -8133,7 +9639,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {
81339639}
81349640
81359641fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {
8136 const elf_offset = elf.getNodeElfOffset(ni);
9642 const elf_offset = elf.computeNodeElfOffset(ni);
81379643 switch (elf.getNode(ni)) {
81389644 else => unreachable,
81399645 .ehdr => assert(elf_offset == 0),
......@@ -8155,7 +9661,7 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {
81559661 elf.flushElfOffset(child_ni);
81569662 }
81579663 },
8158 .section => |shndx| switch (elf.shdrPtr(shndx)) {
9664 .section, .section_manual_size => |shndx| switch (elf.shdrPtr(shndx)) {
81599665 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(elf_offset)),
81609666 },
81619667 }
......@@ -8166,17 +9672,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
81669672 defer trace.end();
81679673
81689674 switch (elf.getNode(ni)) {
8169 .archive => unreachable,
8170 .archive_header => unreachable,
8171
8172 .archive_input_member,
8173 .archive_elf_member_header,
8174 .elf,
8175 => {
9675 .deleted => unreachable,
9676 .archive, .archive_header => unreachable,
9677 .archive_input_member, .archive_elf_member_header, .elf => {
81769678 assert(elf.archive != null);
81779679 return;
81789680 },
8179
81809681 .ehdr, .shdr => elf.flushElfOffset(ni),
81819682 .segment => |phndx| {
81829683 elf.flushElfOffset(ni);
......@@ -8194,6 +9695,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
81949695 .INTERP,
81959696 .PHDR,
81969697 .TLS,
9698 .GNU_EH_FRAME,
81979699 .GNU_RELRO,
81989700 => {
81999701 const new_vaddr = elf.computeNodeVAddr(ni);
......@@ -8204,14 +9706,11 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
82049706 },
82059707 }
82069708 },
8207 .section => |shndx| {
9709 .section, .section_manual_size => |shndx| {
82089710 elf.flushElfOffset(ni);
82099711 const addr = elf.computeNodeVAddr(ni);
82109712 const old_addr: u64, const flags: std.elf.SHF = switch (elf.shdrPtr(shndx)) {
8211 inline else => |shdr| .{
8212 elf.targetLoad(&shdr.addr),
8213 elf.targetLoad(&shdr.flags).shf,
8214 },
9713 inline else => |shdr| .{ elf.targetLoad(&shdr.addr), elf.targetLoad(&shdr.flags).shf },
82159714 };
82169715
82179716 if (flags.ALLOC) {
......@@ -8225,10 +9724,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
82259724 var name = first_name;
82269725 while (name != .empty) {
82279726 const old_sym_addr = Symbol.Id.global(name).value(elf);
8228 Symbol.Id.global(name).flushMoved(
8229 elf,
8230 old_sym_addr - old_addr + addr,
8231 );
9727 Symbol.Id.global(name).flushMoved(elf, old_sym_addr - old_addr + addr);
82329728 name = elf.globalByName(name).?.next_in_node;
82339729 }
82349730 }
......@@ -8246,12 +9742,18 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
82469742 reloc.apply(elf);
82479743 }
82489744 } 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 });
82509748 elf.flushMovedPltSection(.plt, old_addr, addr);
82519749 } else if (shndx == elf.shndx.got_plt) {
82529750 elf.flushMovedPltSection(.got_plt, old_addr, addr);
82539751 } else if (shndx == elf.shndx.plt_sec) {
82549752 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 });
82559757 }
82569758 },
82579759 .input_section => |isi| {
......@@ -8298,12 +9800,10 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
82989800 }
82999801 }
83009802
8301 elf.flushMovedNodeRelocs(
8302 ni,
8303 new_section_addr,
8304 isi.ptrConst(elf).first_symbol_reloc,
8305 isi.ptrConst(elf).first_got_reloc,
8306 );
9803 elf.flushMovedNodeRelocs(ni, new_section_addr, .{
9804 .first_symbol_reloc = isi.ptrConst(elf).first_symbol_reloc,
9805 .first_got_reloc = isi.ptrConst(elf).first_got_reloc,
9806 });
83079807 },
83089808 .copied_global => |global_name| {
83099809 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
83189818
83199819 Symbol.Id.global(global_name).flushMoved(elf, new_addr);
83209820 },
8321 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| {
9821 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi, tag| {
83229822 const new_addr = elf.computeNodeVAddr(ni);
83239823 Symbol.Id.local(mi.symbol(elf)).flushMoved(elf, new_addr);
83249824 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
83299829 name = elf.globalByName(name).?.next_in_node;
83309830 }
83319831 }
8332 elf.flushMovedNodeRelocs(
8333 ni,
8334 new_addr,
8335 mi.firstSymbolReloc(elf),
8336 mi.firstGotReloc(elf),
8337 );
9832 elf.flushMovedNodeRelocs(ni, new_addr, .{
9833 .first_symbol_reloc = mi.firstSymbolReloc(elf),
9834 .skip_symbol_relocs = switch (tag) {
9835 else => comptime unreachable,
9836 .nav => if (elf.dwarf.getFuncIfExists(mi.nav(elf))) |dwarf_fi|
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 });
83389999 },
833910000 }
834010001 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
849610157
849710158 _, const size = ni.location(&elf.mf).resolve(&elf.mf);
849810159 switch (elf.getNode(ni)) {
10160 .deleted => unreachable,
849910161 .archive, .archive_header => {},
850010162 .archive_input_member => unreachable,
850110163 .archive_elf_member_header => unreachable,
......@@ -8523,7 +10185,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
852310185 elf.targetStore(&ph.type, if (size > 0) .LOAD else .NULL);
852410186 try elf.allocateSegmentLoadAddress(phndx);
852510187 },
8526 .DYNAMIC, .INTERP, .PHDR, std.elf.PT.GNU_RELRO => {
10188 .DYNAMIC, .INTERP, .PHDR, .GNU_EH_FRAME, .GNU_RELRO => {
852710189 elf.targetStore(&ph.memsz, @intCast(size));
852810190 },
852910191 .TLS => {
......@@ -8558,39 +10220,47 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
855810220 inline else => |shdr| {
855910221 switch (elf.targetLoad(&shdr.type)) {
856010222 else => unreachable,
8561
856210223 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),
856310224 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
8564
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));
10225 .X86_64_UNWIND => {},
858210226 }
10227 elf.targetStore(&shdr.size, @intCast(size));
858310228 },
858410229 },
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 => {},
858610255 }
858710256}
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 {
859010259 const trace = tracy.trace(@src());
859110260 defer trace.end();
859210261
859310262 switch (elf.getNode(ni)) {
10263 .deleted => unreachable,
859410264 .archive,
859510265 .archive_input_member,
859610266 .archive_elf_member_header,
......@@ -8599,13 +10269,17 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!
859910269 .shdr,
860010270 .segment,
860110271 .section,
10272 .section_manual_size,
860210273 .input_section,
860310274 .copied_global,
860410275 .nav,
860510276 .uav,
860610277 .lazy_code,
860710278 .lazy_const_data,
8608 => unreachable,
10279 .debug_shared,
10280 .eh_frame_footer,
10281 .unit_debug_info_footer,
10282 => {},
860910283
861010284 .archive_header => {
861110285 const archive = &elf.archive.?;
......@@ -8633,6 +10307,190 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!
863310307 error.NoSpaceLeft => archive.strtab_member_too_big = true,
863410308 }
863510309 },
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 },
863610494 }
863710495}
863810496
......@@ -8987,11 +10845,10 @@ pub fn updateExports(
898710845 pt: Zcu.PerThread,
898810846 export_indices: []const Zcu.Export.Index,
898910847) link.Error!void {
8990 const diags = &elf.base.comp.link_diags;
899110848 for (export_indices) |export_index| {
899210849 elf.updateExportInner(pt, export_index) catch |err| switch (err) {
899310850 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.?}),
899510852 };
899610853 }
899710854}
......@@ -9068,17 +10925,19 @@ fn updateExportInner(
906810925 };
906910926}
907010927
9071fn dumpStderr(elf: *Elf, tid: Zcu.PerThread.Id) !void {
10928fn dumpStderr(elf: *Elf, tid: Zcu.PerThread.Id) Io.File.Writer.Error!void {
907210929 const comp = elf.base.comp;
907310930 const io = comp.io;
907410931 var buffer: [512]u8 = undefined;
907510932 const stderr = try io.lockStderr(&buffer, null);
907610933 defer io.unlockStderr();
907710934 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 };
907910938}
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 {
908210941 if (elf.options.enable_link_snapshots) {
908310942 try elf.printNode(tid, w, .root, 0);
908410943 return .enabled;
......@@ -9118,22 +10977,22 @@ pub fn printNode(
911810977 try w.writeByte(')');
911910978 },
912010979 },
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)}),
912210981 .input_section => |isi| {
912310982 const ii = isi.input(elf);
912410983 try w.print("({f}{f}, {s})", .{
912510984 ii.path(elf).fmtEscapeString(),
912610985 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),
912810987 });
912910988 },
913010989 .copied_global => |name| try w.print("(copy:{s})", .{name.slice(elf)}),
913110990 .nav => |nmi| {
913210991 const zcu = elf.base.comp.zcu.?;
913310992 const ip = &zcu.intern_pool;
9134 const nav = ip.getNav(nmi.navIndex(elf));
10993 const nav = ip.getNav(nmi.nav(elf));
913510994 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 }),
913710996 nav.fqn.fmt(ip),
913810997 });
913910998 },
......@@ -9151,19 +11010,66 @@ pub fn printNode(
915111010 .tid = tid,
915211011 }),
915311012 }),
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 },
915411058 }
915511059 {
915611060 const mf_node = &elf.mf.nodes.items[@backingInt(ni)];
915711061 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", .{
915911063 @backingInt(ni),
916011064 off,
916111065 size,
916211066 mf_node.flags.alignment.toByteUnits(),
916311067 mf_node.flags.position,
9164 if (mf_node.flags.moved) " moved" else "",
9165 if (mf_node.flags.next_moved) " next_moved" else "",
11068 if (mf_node.flags.bubbles_moved) " bubbles_moved" else "",
11069 if (mf_node.flags.resized) " moved" else "",
916611070 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 "",
916711073 if (mf_node.flags.has_content) " has_content" else "",
916811074 });
916911075 }
......@@ -9176,26 +11082,30 @@ pub fn printNode(
917611082 }
917711083 return;
917811084 }
9179 const file_loc = ni.fileLocation(&elf.mf, false);
9180 var address = file_loc.offset;
9181 if (file_loc.size == 0) {
9182 try w.splatByteAll(' ', indent + 1);
9183 try w.print("{x:0>8}\n", .{address});
9184 return;
9185 }
11085 const start_address: usize, const end_address: usize = file_loc: {
11086 const file_loc = ni.fileLocation(&elf.mf, false);
11087 break :file_loc .{ @intCast(file_loc.offset), @intCast(file_loc.offset + file_loc.size) };
11088 };
11089 var address = start_address;
918611090 const line_len = 0x10;
9187 var line_it = std.mem.window(
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) {
11091 while (true) : (address = @min(std.mem.alignForward(usize, address + 1, line_len), end_address)) {
919411092 try w.splatByteAll(' ', indent + 1);
9195 try w.print("{x:0>8} ", .{address});
9196 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});
9197 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);
9198 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');
11093 try w.print("{x:0>8}", .{address});
11094 if (address == end_address) break try w.writeByte('\n');
11095 try w.splatByteAll(' ', 2);
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 });
919911109 try w.writeByte('\n');
920011110 }
920111111}
......@@ -9209,7 +11119,7 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: Alignment) Error
920911119 // Align the actual node
921011120 const seg_ni = elf.phdrs.items[phndx].unwrap().?;
921111121 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);
921311123 }
921411124 // Update the phdr `@"align"` field if necessary
921511125 switch (elf.phdrSlice()) {
......@@ -9240,6 +11150,21 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: Alignment) Error
924011150 }
924111151}
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
924311168/// If `sym` has a PLT entry, returns the address of that entry (specifically, the address which a
924411169/// branch to the PLT should target). If `sym` does not have a PLT entry, returns `null`.
924511170fn 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
30953095 return self.getZigObject().?.updateNav(self, pt, nav);
30963096}
30973097
3098pub fn updateLineNumber(self: *MachO, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) link.Error!void {
3099 return self.getZigObject().?.updateLineNumber(pt, ti_id);
3098pub fn updateLineNumber(self: *MachO, pt: Zcu.PerThread, inst: InternPool.TrackedInst.Index, line: u32) link.Error!void {
3099 return self.getZigObject().?.updateLineNumber(pt, inst, line);
31003100}
31013101
31023102pub fn updateExports(
......@@ -5503,4 +5503,3 @@ const Value = @import("../Value.zig");
55035503const UnwindInfo = @import("MachO/UnwindInfo.zig");
55045504const WeakBind = bind.WeakBind;
55055505const ZigObject = @import("MachO/ZigObject.zig");
5506const dev = @import("../dev.zig");
src/link/MachO/Atom.zig+2-2
......@@ -853,7 +853,7 @@ fn resolveRelocInner(
853853
854854const x86_64 = struct {
855855 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 });
857857 const t = &macho_file.base.comp.root_mod.resolved_target.result;
858858 const diags = &macho_file.base.comp.link_diags;
859859 const old_inst = disassemble(code) orelse return error.RelaxFail;
......@@ -879,7 +879,7 @@ const x86_64 = struct {
879879 }
880880
881881 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 });
883883 const old_inst = disassemble(code) orelse return error.RelaxFail;
884884 switch (old_inst.encoding.mnemonic) {
885885 .mov => {
src/link/MachO/Object.zig+5
......@@ -3,6 +3,7 @@ const Object = @This();
33const trace = @import("../../tracy.zig").trace;
44const Archive = @import("Archive.zig");
55const Atom = @import("Atom.zig");
6const dev = @import("../../dev.zig");
67const Dwarf = @import("Dwarf.zig");
78const File = @import("file.zig").File;
89const MachO = @import("../MachO.zig");
......@@ -2826,6 +2827,7 @@ const x86_64 = struct {
28262827 handle: File.Handle,
28272828 macho_file: *MachO,
28282829 ) !void {
2830 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
28292831 const comp = macho_file.base.comp;
28302832 const io = comp.io;
28312833 const gpa = comp.gpa;
......@@ -2938,6 +2940,7 @@ const x86_64 = struct {
29382940 }
29392941
29402942 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 });
29412944 switch (rel_type) {
29422945 .X86_64_RELOC_UNSIGNED => {
29432946 if (rel.r_pcrel == 1) return error.Pcrel;
......@@ -2995,6 +2998,7 @@ const aarch64 = struct {
29952998 handle: File.Handle,
29962999 macho_file: *MachO,
29973000 ) !void {
3001 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
29983002 const comp = macho_file.base.comp;
29993003 const io = comp.io;
30003004 const gpa = comp.gpa;
......@@ -3131,6 +3135,7 @@ const aarch64 = struct {
31313135 }
31323136
31333137 fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_arm64, is_extern: bool) !Relocation.Type {
3138 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
31343139 switch (rel_type) {
31353140 .ARM64_RELOC_UNSIGNED => {
31363141 if (rel.r_pcrel == 1) return error.Pcrel;
src/link/MachO/ZigObject.zig+14-18
......@@ -647,14 +647,11 @@ pub fn getNavVAddr(
647647 },
648648 });
649649 },
650 .debug_output => |debug_output| switch (debug_output) {
651 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
652 .source_off = @intCast(reloc_info.offset),
653 .target_sym = @fromBackingInt(@intCast(sym_index)),
654 .target_off = reloc_info.addend,
655 }),
656 .none => unreachable,
657 },
650 .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
651 .source_off = @intCast(reloc_info.offset),
652 .target_sym = @fromBackingInt(@intCast(sym_index)),
653 .target_off = reloc_info.addend,
654 }),
658655 }
659656 return vaddr;
660657}
......@@ -686,14 +683,11 @@ pub fn getUavVAddr(
686683 },
687684 });
688685 },
689 .debug_output => |debug_output| switch (debug_output) {
690 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
691 .source_off = @intCast(reloc_info.offset),
692 .target_sym = @fromBackingInt(@intCast(sym_index)),
693 .target_off = reloc_info.addend,
694 }),
695 .none => unreachable,
696 },
686 .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
687 .source_off = @intCast(reloc_info.offset),
688 .target_sym = @fromBackingInt(@intCast(sym_index)),
689 .target_off = reloc_info.addend,
690 }),
697691 }
698692 return vaddr;
699693}
......@@ -1418,11 +1412,11 @@ fn updateLazySymbol(
14181412 try macho_file.pwriteAll(code, file_offset);
14191413}
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 {
14221416 if (self.dwarf) |*dwarf| {
14231417 const comp = dwarf.bin_file.comp;
14241418 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) {
14261420 error.OutOfMemory, error.Canceled, error.AlreadyReported => |e| return e,
14271421 else => |e| return diags.fail("failed to update dwarf line numbers: {s}", .{@errorName(e)}),
14281422 };
......@@ -1750,6 +1744,7 @@ const TlvInitializerTable = std.array_hash_map.Auto(Atom.Index, TlvInitializer);
17501744
17511745const x86_64 = struct {
17521746 fn writeTrampolineCode(source_addr: u64, target_addr: u64, buf: *[max_trampoline_len]u8) ![]u8 {
1747 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
17531748 const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr)) - 5;
17541749 var bytes = [_]u8{
17551750 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel32
......@@ -1764,6 +1759,7 @@ const x86_64 = struct {
17641759const assert = std.debug.assert;
17651760const builtin = @import("builtin");
17661761const codegen = @import("../../codegen.zig");
1762const dev = @import("../../dev.zig");
17671763const link = @import("../../link.zig");
17681764const log = std.log.scoped(.link);
17691765const macho = std.macho;
src/link/MappedFile.zig+73-57
......@@ -362,7 +362,7 @@ pub const Node = extern struct {
362362 }
363363
364364 /// 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 {
366366 return mf.addNode(gpa, .{
367367 .add_options = opts,
368368 .position = .floating,
......@@ -373,11 +373,11 @@ pub const Node = extern struct {
373373 /// Adds a header child node to `parent_ni`. Returns the index of the new child.
374374 ///
375375 /// 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 {
377377 if (parent_ni.first(mf).unwrap()) |first_ni| {
378378 assert(first_ni.position(mf) != .header); // `parent_ni` already has a header child
379379 }
380 return parent_ni.addHeaderChildAfter(mf, gpa, .none, opts);
380 return parent_ni.addHeaderChildAfter(gpa, mf, .none, opts);
381381 }
382382 /// Adds a header child node to `parent_ni`. Returns the index of the new child.
383383 ///
......@@ -386,7 +386,7 @@ pub const Node = extern struct {
386386 ///
387387 /// Otherwise, asserts that `prev_oni` is a header node and a child of `parent_ni`, and
388388 /// 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 {
390390 return mf.addNode(gpa, .{
391391 .add_options = opts,
392392 .position = .header,
......@@ -397,11 +397,11 @@ pub const Node = extern struct {
397397 /// Adds a footer child node to `parent_ni`. Returns the index of the new child.
398398 ///
399399 /// 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 {
401401 if (parent_ni.last(mf).unwrap()) |last_ni| {
402402 assert(last_ni.position(mf) != .footer); // `parent_ni` already has a footer child
403403 }
404 return parent_ni.addFooterChildBefore(mf, gpa, .none, opts);
404 return parent_ni.addFooterChildBefore(gpa, mf, .none, opts);
405405 }
406406 /// Adds a footer child node to `parent_ni`. Returns the index of the new child.
407407 ///
......@@ -410,7 +410,7 @@ pub const Node = extern struct {
410410 ///
411411 /// Otherwise, asserts that `next_oni` is a footer node and a child of `parent_ni`, and
412412 /// 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 {
414414 const prev_oni: Node.Index.Optional = prev: {
415415 const next_ni = next_oni.unwrap() orelse {
416416 break :prev parent_ni.last(mf);
......@@ -473,8 +473,8 @@ pub const Node = extern struct {
473473 fn setNext(
474474 ni: Node.Index,
475475 gpa: Allocator,
476 next_ni: Node.Index.Optional,
477476 mf: *MappedFile,
477 next_ni: Node.Index.Optional,
478478 ) Allocator.Error!void {
479479 const next_ptr = &ni.get(mf).next;
480480 if (next_ptr.* == next_ni) return;
......@@ -514,12 +514,10 @@ pub const Node = extern struct {
514514 return node_moved.*;
515515 }
516516 pub fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
517 if (ni.hasMoved(mf)) return;
518517 const node = ni.get(mf);
518 if (node.prev.unwrap()) |prev_ni| prev_ni.nextMovedAssumeCapacity(mf);
519 if (ni.hasMoved(mf)) return;
519520 node.flags.moved = true;
520 if (node.prev.unwrap()) |prev_ni| {
521 prev_ni.nextMovedAssumeCapacity(mf);
522 }
523521 if (node.flags.resized or node.flags.next_moved) return;
524522 mf.updates.appendAssumeCapacity(ni);
525523 mf.update_prog_node.increaseEstimatedTotalItems(1);
......@@ -571,7 +569,7 @@ pub const Node = extern struct {
571569 return ni.get(mf).flags.alignment;
572570 }
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 {
575573 try mf.large.ensureUnusedCapacity(gpa, 2);
576574 try mf.updates.ensureUnusedCapacity(gpa, 2);
577575 const node = ni.get(mf);
......@@ -636,15 +634,38 @@ pub const Node = extern struct {
636634 return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
637635 }
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
639642 pub fn sliceConst(ni: Node.Index, mf: *const MappedFile) []const u8 {
640643 const file_loc = ni.fileLocation(mf, false);
641644 return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
642645 }
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
644665 /// Ensures that the size of `ni` is at least `min_size`. Valid for any node.
645666 ///
646667 /// 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 {
648669 _, const current_size = ni.location(mf).resolve(mf);
649670 if (current_size >= min_size) return;
650671 const new_size = ni.alignment(mf).forward(min_size +| min_size / growth_factor);
......@@ -660,7 +681,7 @@ pub const Node = extern struct {
660681 /// Asserts that `ni` is a leaf node, i.e. has no children.
661682 ///
662683 /// 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 {
664685 assert(ni.first(mf) == .none);
665686 // The alignment of `size` is asserted by `shrinkLeafNode` and `growNode`.
666687 _, const old_size = ni.location(mf).resolve(mf);
......@@ -680,17 +701,12 @@ pub const Node = extern struct {
680701 /// If the node's current offset or size is not sufficiently aligned, it will be moved
681702 /// and/or resized to match the new alignment. The node's size may be increased by any
682703 /// amount, as if `ensureMinimumSize` were used.
683 pub fn realign(
684 ni: Node.Index,
685 mf: *MappedFile,
686 gpa: Allocator,
687 new_alignment: Alignment,
688 ) Error!void {
704 pub fn realign(ni: Node.Index, gpa: Allocator, mf: *MappedFile, new_alignment: Alignment) Error!void {
689705 try mf.realignNode(gpa, ni, new_alignment);
690706 mf.updateWriters();
691707 }
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 {
694710 w.* = .{
695711 .gpa = gpa,
696712 .mf = mf,
......@@ -820,7 +836,7 @@ pub const Node = extern struct {
820836 ) Io.Writer.Error!void {
821837 _ = preserve;
822838 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| {
824840 w.err = err;
825841 return error.WriteFailed;
826842 };
......@@ -992,7 +1008,7 @@ fn shrinkLeafNode(
9921008 },
9931009 };
9941010 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);
9961012 return;
9971013 };
9981014
......@@ -1000,7 +1016,7 @@ fn shrinkLeafNode(
10001016 .header => {
10011017 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
10051021 // We need to shift backwards all header nodes following us.
10061022 const next_header_ni = ni.next(mf).unwrap() orelse return;
......@@ -1009,7 +1025,7 @@ fn shrinkLeafNode(
10091025 var header_ni = next_header_ni;
10101026 while (true) {
10111027 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
10141030 const next_ni = header_ni.next(mf).unwrap() orelse break;
10151031 if (next_ni.position(mf) != .header) break;
......@@ -1034,13 +1050,13 @@ fn shrinkLeafNode(
10341050 );
10351051 },
10361052 .floating => {
1037 try ni.setLocation(mf, gpa, old_offset, new_size);
1053 try ni.setLocation(gpa, mf, old_offset, new_size);
10381054 },
10391055 .footer => {
10401056 const shift = old_size - new_size;
10411057
10421058 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
10451061 const prev_footers_size = prev_footers_size: {
10461062 // We need to shift forwards all footer nodes preceding us.
......@@ -1054,7 +1070,7 @@ fn shrinkLeafNode(
10541070 var footer_ni = prev_footer_ni;
10551071 while (true) {
10561072 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
10591075 const prev_ni = footer_ni.prev(mf).unwrap() orelse break;
10601076 if (prev_ni.position(mf) != .footer) break;
......@@ -1137,7 +1153,7 @@ fn growNode(
11371153 },
11381154 };
11391155 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);
11411157 if (grow_options.move_footers) {
11421158 // We need to move any footers to be at the *new* end of the file.
11431159 if (ni.firstFooter(mf).unwrap()) |first_footer_ni| {
......@@ -1152,7 +1168,7 @@ fn growNode(
11521168 var cur_ni = first_footer_ni;
11531169 while (true) {
11541170 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);
11561172 cur_ni = cur_ni.next(mf).unwrap() orelse break;
11571173 }
11581174 }
......@@ -1211,8 +1227,8 @@ fn growNode(
12111227 while (true) {
12121228 const old_sub_footer_offset, const sub_footer_size = cur_ni.location(mf).resolve(mf);
12131229 try cur_ni.setLocation(
1214 mf,
12151230 gpa,
1231 mf,
12161232 old_sub_footer_offset + (new_size - old_size),
12171233 sub_footer_size,
12181234 );
......@@ -1227,8 +1243,8 @@ fn growNode(
12271243 assert(moved_header_ni.position(mf) == .header);
12281244 const moved_header_offset, const moved_header_size = moved_header_ni.location(mf).resolve(mf);
12291245 try moved_header_ni.setLocation(
1230 mf,
12311246 gpa,
1247 mf,
12321248 moved_header_offset - old_size + new_size,
12331249 moved_header_size,
12341250 );
......@@ -1237,7 +1253,7 @@ fn growNode(
12371253 }
12381254
12391255 // 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);
12411257 return;
12421258 },
12431259 .floating => {
......@@ -1365,8 +1381,8 @@ fn growNode(
13651381
13661382 // Update our own offset and size:
13671383 try ni.setLocation(
1368 mf,
13691384 gpa,
1385 mf,
13701386 node.location().resolve(mf)[0] - shift,
13711387 new_size,
13721388 );
......@@ -1377,7 +1393,7 @@ fn growNode(
13771393 var footer_oni = first_sub_footer_oni;
13781394 while (footer_oni.unwrap()) |footer_ni| : (footer_oni = footer_ni.next(mf)) {
13791395 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);
13811397 }
13821398 }
13831399
......@@ -1392,7 +1408,7 @@ fn growNode(
13921408 while (footer_ni != ni) : (footer_ni = footer_ni.next(mf).unwrap().?) {
13931409 moved_has_content = moved_has_content or footer_ni.get(mf).flags.has_content;
13941410 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);
13961412 }
13971413 }
13981414
......@@ -1444,8 +1460,8 @@ fn growNode(
14441460 }
14451461
14461462 try ni.setLocation(
1447 mf,
14481463 gpa,
1464 mf,
14491465 node.location().resolve(mf)[0],
14501466 actual_new_size,
14511467 );
......@@ -1461,7 +1477,7 @@ fn growNode(
14611477 assert(footer_ni.position(mf) == .footer);
14621478 moved_has_content = moved_has_content or footer_ni.get(mf).flags.has_content;
14631479 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);
14651481 }
14661482 }
14671483
......@@ -1472,7 +1488,7 @@ fn growNode(
14721488 assert(footer_ni.position(mf) == .footer);
14731489 moved_has_content = moved_has_content or footer_ni.get(mf).flags.has_content;
14741490 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);
14761492 }
14771493 }
14781494
......@@ -1544,7 +1560,7 @@ fn growFloatingNodeWithAlignment(
15441560 break :grow_in_place; // the parent is not big enough
15451561 }
15461562 // 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);
15481564 if (grow_options.move_footers) {
15491565 // If we have any footers, we need to move them to the end of our new size, and update
15501566 // their offsets accordingly.
......@@ -1554,7 +1570,7 @@ fn growFloatingNodeWithAlignment(
15541570 while (true) {
15551571 footers_have_content = footers_have_content or cur_ni.get(mf).flags.has_content;
15561572 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);
15581574 cur_ni = cur_ni.next(mf).unwrap() orelse break;
15591575 }
15601576 if (footers_have_content) {
......@@ -1691,7 +1707,7 @@ fn growFloatingNodeWithAlignment(
16911707 footers_have_content = footers_have_content or cur_ni.get(mf).flags.has_content;
16921708 const old_footer_offset, const footer_size = cur_ni.location(mf).resolve(mf);
16931709 // 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);
16951711 cur_ni = cur_ni.next(mf).unwrap() orelse break;
16961712 }
16971713
......@@ -1718,7 +1734,7 @@ fn growFloatingNodeWithAlignment(
17181734 assert(!footers_have_content);
17191735 }
17201736
1721 try ni.setLocation(mf, gpa, new_loc.offset, new_size);
1737 try ni.setLocation(gpa, mf, new_loc.offset, new_size);
17221738
17231739 if (new_loc.prev != ni.toOptional()) {
17241740 // 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(
19181934 if (cur_ni == .root) {
19191935 try mf.ensureTotalCapacityPrecise(@intCast(this_old_size + range_size));
19201936 }
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
19231939 while (cur_ni.next(mf).unwrap()) |next_ni| {
19241940 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);
19261942 cur_ni = next_ni;
19271943 }
19281944
......@@ -1935,7 +1951,7 @@ fn growNodeViaInsertRange(
19351951 var footer_ni = first_footer_ni;
19361952 while (true) {
19371953 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);
19391955 footer_ni = footer_ni.next(mf).unwrap() orelse break;
19401956 }
19411957 }
......@@ -2103,7 +2119,7 @@ fn ensureAdditionalHeaderCapacity(
21032119 const old_offset, const old_size = cur_ni.location(mf).resolve(mf);
21042120 const new_offset = old_offset - moving_offset + dest_offset;
21052121 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);
21072123 if (cur_ni == last_moving_ni) break;
21082124 cur_ni = cur_ni.next(mf).unwrap().?;
21092125 }
......@@ -2146,7 +2162,7 @@ fn removeNodesFromChildList(
21462162
21472163 if (prev_oni.unwrap()) |prev_ni| {
21482164 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);
21502166 } else {
21512167 assert(parent_ni.first(mf).unwrap().? == first_remove_ni);
21522168 parent_ni.get(mf).first = next_oni;
......@@ -2185,11 +2201,11 @@ fn addNodesToChildListBefore(
21852201 };
21862202
21872203 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
21902206 if (prev_oni.unwrap()) |prev_ni| {
21912207 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));
21932209 } else {
21942210 assert(parent_ni.first(mf) == next_oni);
21952211 parent_ni.get(mf).first = .wrap(first_add_ni);
......@@ -2630,7 +2646,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {
26302646 for (1..n) |_| cur_ni = cur_ni.next(&mf).unwrap().?;
26312647 break :prev_oni .wrap(cur_ni);
26322648 };
2633 const new_ni = try parent_ni.addHeaderChildAfter(&mf, gpa, prev_oni, .{
2649 const new_ni = try parent_ni.addHeaderChildAfter(gpa, &mf, prev_oni, .{
26342650 .size = size,
26352651 .alignment = alignment,
26362652 });
......@@ -2638,7 +2654,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {
26382654 break :new_ni new_ni;
26392655 },
26402656
2641 .floating => try parent_ni.addFloatingChild(&mf, gpa, .{
2657 .floating => try parent_ni.addFloatingChild(gpa, &mf, .{
26422658 .size = size,
26432659 .alignment = alignment,
26442660 }),
......@@ -2652,7 +2668,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {
26522668 for (1..n) |_| cur_ni = cur_ni.prev(&mf).unwrap().?;
26532669 break :next_oni .wrap(cur_ni);
26542670 };
2655 const new_ni = try parent_ni.addFooterChildBefore(&mf, gpa, next_oni, .{
2671 const new_ni = try parent_ni.addFooterChildBefore(gpa, &mf, next_oni, .{
26562672 .size = size,
26572673 .alignment = alignment,
26582674 });
......@@ -2686,13 +2702,13 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {
26862702 if (ni.first(&mf) == .none and smith.value(bool)) {
26872703 // Since this is a leaf node, we can use `resizeLeaf`.
26882704 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);
26902706 if (new_size == 0) {
26912707 node_info.initialized = false;
26922708 }
26932709 } else {
26942710 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);
26962712 }
26972713
26982714 if (ni.first(&mf) == .none) {
......@@ -2718,7 +2734,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void {
27182734 const new_alignment = smith.valueWeighted(Alignment, alignment_weights);
27192735 if (new_alignment.compare(.gt, ni.alignment(&mf))) {
27202736 _, const old_size = ni.location(&mf).resolve(&mf);
2721 try ni.realign(&mf, gpa, new_alignment);
2737 try ni.realign(gpa, &mf, new_alignment);
27222738 if (ni.first(&mf) == .none and nodes.get(ni).?.initialized) {
27232739 const slice = ni.slice(&mf);
27242740 @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");
1818const link = @import("../link.zig");
1919const Compilation = @import("../Compilation.zig");
2020const Liveness = @import("../Air/Liveness.zig");
21const dev = @import("../dev.zig");
2221const Value = @import("../Value.zig");
2322
2423base: link.File,
......@@ -89,7 +88,6 @@ pub fn updateFunc(
8988 func_index: InternPool.Index,
9089 any_mir: *const codegen.AnyMir,
9190) !void {
92 dev.check(.spork8_backend);
9391 // This linker implementation only works with `std.lang.CompilerBackend.zsf_spork8`.
9492 const mir = &any_mir.spork8;
9593 const zcu = pt.zcu;
......@@ -168,10 +166,11 @@ pub fn updateNav(spork8: *Spork8, pt: Zcu.PerThread, nav_index: InternPool.Nav.I
168166 log.debug("updateNav {f}", .{nav.fqn.fmt(ip)});
169167}
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 {
172170 _ = spork8;
173171 _ = pt;
174 _ = ti_id;
172 _ = inst;
173 _ = line;
175174}
176175
177176pub fn deleteExport(
src/link/Wasm.zig+4-15
......@@ -38,7 +38,6 @@ const Dwarf = @import("Dwarf.zig");
3838const InternPool = @import("../InternPool.zig");
3939const Zcu = @import("../Zcu.zig");
4040const codegen = @import("../codegen.zig");
41const dev = @import("../dev.zig");
4241const link = @import("../link.zig");
4342const trace = @import("../tracy.zig").trace;
4443const wasi_libc = @import("../libs/wasi_libc.zig");
......@@ -1374,11 +1373,7 @@ pub const GlobalImport = extern struct {
13741373 .__tls_base => @tagName(Unpacked.__tls_base),
13751374 .__tls_size => @tagName(Unpacked.__tls_size),
13761375 .object_global => |i| i.name(wasm).slice(wasm),
1377 inline .uav_obj, .uav_exe => |i| std.mem.print(
1378 buf,
1379 "__anon_{d}",
1380 .{@backingInt(i.key(wasm).*)},
1381 ) catch unreachable,
1376 inline .uav_obj, .uav_exe => |i| std.mem.print(buf, "__anon_{d}", .{i}) catch unreachable,
13821377 .nav_obj => |i| i.name(wasm),
13831378 .nav_exe => |i| i.name(wasm),
13841379 };
......@@ -1997,11 +1992,7 @@ pub const ObjectDataImport = extern struct {
19971992 .__heap_base => @tagName(.__heap_base),
19981993 .__heap_end => @tagName(.__heap_end),
19991994 .__wasm_first_page_end => @tagName(.__wasm_first_page_end),
2000 inline .uav_exe, .uav_obj => |i| std.mem.print(
2001 buf,
2002 "__anon_{d}",
2003 .{@backingInt(i.key(wasm).*)},
2004 ) catch unreachable,
1995 inline .uav_exe, .uav_obj => |i| std.mem.print(buf, "__anon_{d}", .{i}) catch unreachable,
20051996 inline .nav_exe, .nav_obj => |i| i.name(wasm),
20061997 };
20071998 }
......@@ -3583,8 +3574,6 @@ pub fn updateFunc(
35833574 func_index: InternPool.Index,
35843575 any_mir: *const codegen.AnyMir,
35853576) !void {
3586 dev.check(.wasm_backend);
3587
35883577 // This linker implementation only works with codegen backend `.stage2_wasm`.
35893578 const mir = &any_mir.wasm;
35903579 const zcu = pt.zcu;
......@@ -3736,11 +3725,11 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
37363725 }
37373726}
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 {
37403729 const comp = wasm.base.comp;
37413730 const diags = &comp.link_diags;
37423731 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) {
37443733 error.OutOfMemory, error.Canceled, error.AlreadyReported => |e| return e,
37453734 else => |e| return diags.fail("failed to update dwarf line numbers: {s}", .{@errorName(e)}),
37463735 };
src/main.zig+1-1
......@@ -36,7 +36,7 @@ const Module = @import("Module.zig");
3636
3737test {
3838 _ = @import("codegen.zig");
39 _ = @import("link/MappedFile.zig");
39 _ = link.MappedFile;
4040}
4141
4242const thread_stack_size = 60 << 20;
src/print_zir.zig+11-3
......@@ -1452,6 +1452,8 @@ const Writer = struct {
14521452 self.parent_decl_node = struct_decl.src_node;
14531453 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
14551457 const fields_hash = self.code.getAssociatedSrcHash(inst).?;
14561458 try stream.print("hash({x}) ", .{&fields_hash});
14571459
......@@ -1514,6 +1516,8 @@ const Writer = struct {
15141516 self.parent_decl_node = union_decl.src_node;
15151517 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
15171521 const fields_hash = self.code.getAssociatedSrcHash(inst).?;
15181522 try stream.print("hash({x}) ", .{&fields_hash});
15191523
......@@ -1590,6 +1594,8 @@ const Writer = struct {
15901594 self.parent_decl_node = enum_decl.src_node;
15911595 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
15931599 const fields_hash = self.code.getAssociatedSrcHash(inst).?;
15941600 try stream.print("hash({x}) ", .{&fields_hash});
15951601
......@@ -1637,6 +1643,8 @@ const Writer = struct {
16371643 self.parent_decl_node = opaque_decl.src_node;
16381644 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
16401648 try stream.print("{s}, ", .{@tagName(opaque_decl.name_strategy)});
16411649 try self.writeCaptures(stream, opaque_decl.captures, opaque_decl.capture_names);
16421650 try stream.writeAll(", ");
......@@ -2216,10 +2224,10 @@ const Writer = struct {
22162224 try stream.print("{s} '{s}'", .{ @tagName(decl.kind), self.code.nullTerminatedString(decl.name) });
22172225 },
22182226 }
2227 try stream.print(":{d}:{d}", .{ decl.src_line + 1, decl.src_column + 1 });
2228
22192229 const src_hash = self.code.getAssociatedSrcHash(inst).?;
2220 try stream.print(" line({d}) column({d}) hash({x})", .{
2221 decl.src_line, decl.src_column, &src_hash,
2222 });
2230 try stream.print(" hash({x})", .{&src_hash});
22232231
22242232 {
22252233 if (decl.type_body) |b| {
src/target.zig+5-1
......@@ -2,6 +2,7 @@ const builtin = @import("builtin");
22const std = @import("std");
33const assert = std.debug.assert;
44
5const dev = @import("dev.zig");
56const Type = @import("Type.zig");
67const AddressSpace = std.lang.AddressSpace;
78const Alignment = @import("InternPool.zig").Alignment;
......@@ -855,7 +856,10 @@ pub fn functionPointerMask(target: *const std.Target) ?u64 {
855856
856857pub fn supportsTailCall(target: *const std.Target, backend: std.lang.CompilerBackend) bool {
857858 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 },
859863 .stage2_c => return true,
860864 else => return false,
861865 }
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 @@
11b: *std.Build,
22options: Options,
33root_step: *std.Build.Step,
4test_matrix: []const TestTarget,
45
56pub const Options = struct {
67 test_filters: []const []const u8,
......@@ -12,19 +13,20 @@ pub const Options = struct {
1213 skip_libc: bool,
1314};
1415
15pub const Target = struct {
16 resolved: std.Build.ResolvedTarget,
16pub const TestTarget = struct {
17 target: std.Target.Query,
1718 optimize_mode: std.builtin.Optimize = .debug,
1819 link_libc: ?bool = null,
1920 single_threaded: ?bool = null,
2021 pic: ?bool = null,
21 test_name_suffix: []const u8,
22 linker: LinkerImpl,
2223};
2324
24pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
25pub const LinkerImpl = enum { default, old, new };
26
27pub fn addTests(db: *Debugger) void {
2528 db.addLldbTest(
2629 "basic",
27 target,
2830 &.{
2931 .{
3032 .path = "basic.zig",
......@@ -179,10 +181,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
179181 \\(lldb) breakpoint delete --force 1
180182 \\1 breakpoints deleted; 0 breakpoint locations disabled.
181183 },
184 .{},
182185 );
183186 db.addLldbTest(
184187 "identifiers",
185 target,
186188 &.{
187189 .{
188190 .path = "identifiers.zig",
......@@ -214,10 +216,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
214216 \\(lldb) breakpoint delete --force 1
215217 \\1 breakpoints deleted; 0 breakpoint locations disabled.
216218 },
219 .{},
217220 );
218221 db.addLldbTest(
219222 "types",
220 target,
221223 &.{
222224 .{
223225 .path = "types.zig",
......@@ -282,10 +284,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
282284 \\(lldb) breakpoint delete --force 1
283285 \\1 breakpoints deleted; 0 breakpoint locations disabled.
284286 },
287 .{},
285288 );
286289 db.addLldbTest(
287290 "pointers",
288 target,
289291 &.{
290292 .{
291293 .path = "pointers.zig",
......@@ -419,10 +421,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
419421 \\(lldb) breakpoint delete --force 1
420422 \\1 breakpoints deleted; 0 breakpoint locations disabled.
421423 },
424 .{},
422425 );
423426 db.addLldbTest(
424427 "strings",
425 target,
426428 &.{
427429 .{
428430 .path = "strings.zig",
......@@ -495,10 +497,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
495497 \\(lldb) breakpoint delete --force 1
496498 \\1 breakpoints deleted; 0 breakpoint locations disabled.
497499 },
500 .{},
498501 );
499502 db.addLldbTest(
500503 "enums",
501 target,
502504 &.{
503505 .{
504506 .path = "enums.zig",
......@@ -557,10 +559,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
557559 \\(lldb) breakpoint delete --force 1
558560 \\1 breakpoints deleted; 0 breakpoint locations disabled.
559561 },
562 .{ .skip_new_linker = true }, // passes, but prints errors
560563 );
561564 db.addLldbTest(
562565 "errors",
563 target,
564566 &.{
565567 .{
566568 .path = "errors.zig",
......@@ -627,10 +629,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
627629 \\(lldb) breakpoint delete --force 1
628630 \\1 breakpoints deleted; 0 breakpoint locations disabled.
629631 },
632 .{ .skip_new_linker = true },
630633 );
631634 db.addLldbTest(
632635 "optionals",
633 target,
634636 &.{
635637 .{
636638 .path = "optionals.zig",
......@@ -681,10 +683,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
681683 \\(lldb) breakpoint delete --force 2
682684 \\1 breakpoints deleted; 0 breakpoint locations disabled.
683685 },
686 .{},
684687 );
685688 db.addLldbTest(
686689 "unions",
687 target,
688690 &.{
689691 .{
690692 .path = "unions.zig",
......@@ -766,10 +768,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
766768 \\(lldb) breakpoint delete --force 1
767769 \\1 breakpoints deleted; 0 breakpoint locations disabled.
768770 },
771 .{ .skip_new_linker = true }, // passes, but prints errors
769772 );
770773 db.addLldbTest(
771774 "storage",
772 target,
773775 &.{
774776 .{
775777 .path = "storage.zig",
......@@ -866,10 +868,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
866868 \\(lldb) breakpoint delete --force 1
867869 \\1 breakpoints deleted; 0 breakpoint locations disabled.
868870 },
871 .{ .skip_new_linker = true },
869872 );
870873 db.addLldbTest(
871874 "if_blocks",
872 target,
873875 &.{
874876 .{
875877 .path = "if_blocks.zig",
......@@ -908,10 +910,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
908910 \\(lldb) breakpoint delete --force 1
909911 \\1 breakpoints deleted; 0 breakpoint locations disabled.
910912 },
913 .{},
911914 );
912915 db.addLldbTest(
913916 "switch_blocks",
914 target,
915917 &.{
916918 .{
917919 .path = "switch_blocks.zig",
......@@ -953,10 +955,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
953955 \\(lldb) breakpoint delete --force 1
954956 \\1 breakpoints deleted; 0 breakpoint locations disabled.
955957 },
958 .{},
956959 );
957960 db.addLldbTest(
958961 "step_single_stmt_loops",
959 target,
960962 &.{
961963 .{
962964 .path = "step_single_stmt_loops.zig",
......@@ -1371,10 +1373,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
13711373 \\(lldb) frame variable --show-all-children x
13721374 \\(u32) x = 12
13731375 },
1376 .{},
13741377 );
13751378 db.addLldbTest(
13761379 "inline_call",
1377 target,
13781380 &.{
13791381 .{
13801382 .path = "root0.zig",
......@@ -1944,10 +1946,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
19441946 \\ frame #1: inline_call`m1pfi(m1pai=89) at mod1.zig:23:15
19451947 \\ frame #2: inline_call`root0.main at root0.zig:41:15
19461948 },
1949 .{ .skip_new_linker = true },
19471950 );
19481951 db.addLldbTest(
19491952 "link_object",
1950 target,
19511953 &.{
19521954 .{
19531955 .path = "main.zig",
......@@ -1983,10 +1985,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
19831985 \\(lldb) breakpoint delete --force 2
19841986 \\1 breakpoints deleted; 0 breakpoint locations disabled.
19851987 },
1988 .{},
19861989 );
19871990 db.addLldbTest(
19881991 "hash_map",
1989 target,
19901992 &.{
19911993 .{
19921994 .path = "main.zig",
......@@ -2052,10 +2054,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
20522054 \\(lldb) breakpoint delete --force 1
20532055 \\1 breakpoints deleted; 0 breakpoint locations disabled.
20542056 },
2057 .{ .skip_new_linker = true },
20552058 );
20562059 db.addLldbTest(
20572060 "multi_array_list",
2058 target,
20592061 &.{
20602062 .{
20612063 .path = "main.zig",
......@@ -2306,22 +2308,26 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
23062308 \\(lldb) breakpoint delete --force 1
23072309 \\1 breakpoints deleted; 0 breakpoint locations disabled.
23082310 },
2311 .{ .skip_new_linker = true },
23092312 );
23102313}
23112314
23122315const File = struct { import: ?[]const u8 = null, path: []const u8, source: []const u8 };
23132316
2317const TestOptions = struct {
2318 skip_new_linker: bool = false,
2319};
2320
23142321fn addGdbTest(
23152322 db: *Debugger,
23162323 name: []const u8,
2317 target: *const Target,
23182324 files: []const File,
23192325 commands: []const u8,
23202326 expected_output: []const []const u8,
2327 options: TestOptions,
23212328) void {
23222329 db.addTest(
23232330 name,
2324 target,
23252331 files,
23262332 &.{},
23272333 &.{
......@@ -2331,24 +2337,22 @@ fn addGdbTest(
23312337 },
23322338 "set remotetimeout 0",
23332339 commands,
2334 &.{
2335 "--args",
2336 },
2340 &.{"--args"},
23372341 expected_output,
2342 options,
23382343 );
23392344}
23402345
23412346fn addLldbTest(
23422347 db: *Debugger,
23432348 name: []const u8,
2344 target: *const Target,
23452349 files: []const File,
23462350 commands: []const u8,
23472351 expected_output: []const []const u8,
2352 options: TestOptions,
23482353) void {
23492354 db.addTest(
23502355 name,
2351 target,
23522356 files,
23532357 &.{.{ "LANG", "C.UTF-8" }}, // affects output formatting
23542358 &.{
......@@ -2358,10 +2362,9 @@ fn addLldbTest(
23582362 },
23592363 "settings set plugin.process.gdb-remote.packet-timeout 0",
23602364 commands,
2361 &.{
2362 "--",
2363 },
2365 &.{"--"},
23642366 expected_output,
2367 options,
23652368 );
23662369}
23672370
......@@ -2373,7 +2376,6 @@ const success = 99;
23732376fn addTest(
23742377 db: *Debugger,
23752378 name: []const u8,
2376 target: *const Target,
23772379 files: []const File,
23782380 env: []const struct { []const u8, []const u8 },
23792381 db_argv1: []const []const u8,
......@@ -2381,57 +2383,85 @@ fn addTest(
23812383 commands: []const u8,
23822384 db_argv2: []const []const u8,
23832385 expected_output: []const []const u8,
2386 options: TestOptions,
23842387) void {
23852388 if (db.options.test_filters.len > 0) {
23862389 for (db.options.test_filters) |test_filter| {
23872390 if (std.mem.find(u8, name, test_filter) != null) break;
23882391 } else return;
23892392 }
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(.{
2399 .target = target.resolved,
2400 .root_source_file = files_wf.add(files[0].path, files[0].source),
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 });
2394 const wf = db.b.addWriteFiles();
2395 const root_source_file = wf.add(files[0].path, files[0].source);
2396 var imports: std.array_hash_map.String(*std.Build.Module) = .empty;
24072397 for (files[1..]) |file| {
2408 const path = files_wf.add(file.path, file.source);
2409 if (file.import) |import| mod.addImport(import, db.b.createModule(.{
2398 const path = wf.add(file.path, file.source);
2399 if (file.import) |import| imports.putNoClobber(db.b.allocator, import, db.b.createModule(.{
24102400 .root_source_file = path,
2411 }));
2401 })) catch @panic("OOM");
24122402 }
2413
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(
2403 const commands_file = wf.add(
24262404 db.b.fmt("{s}.cmd", .{name}),
24272405 db.b.fmt("{s}\n\n{s}\n\nquit {d}\n", .{ db_commands, commands, success }),
2428 ));
2429 run.addArgs(db_argv2);
2430 run.addArtifactArg(exe);
2431 for (expected_output) |expected| run.addCheck(.{ .expect_stdout_match = db.b.fmt("{s}\n", .{expected}) });
2432 run.addCheck(.{ .expect_term = .{ .exited = success } });
2433 run.setStdIn(.{ .bytes = "" });
2434 db.root_step.dependOn(&run.step);
2406 );
2407
2408 for (db.test_matrix) |test_target| {
2409 if (options.skip_new_linker and test_target.linker == .new) continue;
2410
2411 const resolved_target = db.b.resolveTargetQuery(test_target.target);
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 }
24352465}
24362466
24372467const Debugger = @This();
test/src/ErrorTrace.zig+29-5
......@@ -36,6 +36,7 @@ pub const CaseParameters = struct {
3636 optimize: OptimizeMode = .debug,
3737 use_llvm: ?bool = null,
3838 use_lld: ?bool = null,
39 use_new_linker: ?bool = null,
3940
4041 // This is intended for targets that, for any reason, shouldn't be run as part of a normal test
4142 // invocation. This could be because of a slow backend, requiring a newer LLVM version, being
......@@ -256,6 +257,14 @@ pub const param_sets = [_]CaseParameters{
256257 .abi = .none,
257258 },
258259 },
260 .{
261 .target = .{
262 .cpu_arch = .x86_64,
263 .os_tag = .linux,
264 .abi = .none,
265 },
266 .use_new_linker = true,
267 },
259268 .{
260269 .target = .{
261270 .cpu_arch = .x86_64,
......@@ -265,6 +274,15 @@ pub const param_sets = [_]CaseParameters{
265274 .use_llvm = true,
266275 .use_lld = true,
267276 },
277 .{
278 .target = .{
279 .cpu_arch = .x86_64,
280 .os_tag = .linux,
281 .abi = .none,
282 },
283 .use_llvm = true,
284 .use_new_linker = true,
285 },
268286 .{
269287 .target = .{
270288 .cpu_arch = .x86_64,
......@@ -439,18 +457,23 @@ pub fn addCase(self: *ErrorTrace, case: Case) void {
439457 };
440458
441459 const backend_string = if (params.use_llvm == true)
442 "-llvm"
460 " llvm"
443461 else if (params.use_llvm == false)
444 "-selfhosted"
462 " selfhosted"
445463 else
446464 "";
447465
448 const annotated_case_name = b.fmt("check {s} ({s}{s}{t}{s})", .{
466 const annotated_case_name = b.fmt("check {s} ({s} {t}{s}{s})", .{
449467 case.name,
450 triple orelse "",
451 if (triple != null) " " else "",
468 triple orelse "native",
452469 params.optimize,
453470 backend_string,
471 if (params.use_new_linker == true)
472 " new_linker"
473 else if (params.use_lld == true)
474 " lld"
475 else
476 "",
454477 });
455478 if (self.options.test_filters.len > 0) {
456479 for (self.options.test_filters) |test_filter| {
......@@ -472,6 +495,7 @@ pub fn addCase(self: *ErrorTrace, case: Case) void {
472495 .use_llvm = params.use_llvm,
473496 .use_lld = params.use_lld,
474497 });
498 exe.use_new_linker = params.use_new_linker;
475499 exe.bundle_ubsan_rt = false;
476500
477501 const run = b.addRunArtifact(exe);
test/src/StackTrace.zig+26-2
......@@ -38,6 +38,7 @@ pub const CaseParameters = struct {
3838 link_libc: ?bool = null,
3939 use_llvm: ?bool = null,
4040 use_lld: ?bool = null,
41 use_new_linker: ?bool = null,
4142 pie: ?bool = null,
4243 /// To enable this coverage, one of two things needs to happen:
4344 /// * The compiler needs to gain the ability to strip only debug info (not symbols)
......@@ -752,6 +753,14 @@ pub const param_sets = [_]CaseParameters{
752753 .abi = .none,
753754 },
754755 },
756 .{
757 .target = .{
758 .cpu_arch = .x86_64,
759 .os_tag = .linux,
760 .abi = .none,
761 },
762 .use_new_linker = true,
763 },
755764 .{
756765 .target = .{
757766 .cpu_arch = .x86_64,
......@@ -761,6 +770,15 @@ pub const param_sets = [_]CaseParameters{
761770 .use_llvm = true,
762771 .use_lld = true,
763772 },
773 .{
774 .target = .{
775 .cpu_arch = .x86_64,
776 .os_tag = .linux,
777 .abi = .none,
778 },
779 .use_llvm = true,
780 .use_new_linker = true,
781 },
764782 .{
765783 .target = .{
766784 .cpu_arch = .x86_64,
......@@ -1175,9 +1193,14 @@ fn addCaseInstance(
11751193
11761194 const annotated_case_name = b.fmt("check {s} ({s}{s}{s}{s}{s}{s}{s}{s}{s})", .{
11771195 name,
1178 triple orelse "",
1179 if (triple != null) " " else "",
1196 triple orelse "native",
11801197 backend_string,
1198 if (params.use_new_linker == true)
1199 " new_linker"
1200 else if (params.use_lld == true)
1201 " lld"
1202 else
1203 "",
11811204 if (params.pie == true) " pie" else "",
11821205 if (params.link_libc == true) " libc" else "",
11831206 if (params.linkage) |linkage| switch (linkage) {
......@@ -1210,6 +1233,7 @@ fn addCaseInstance(
12101233 .use_llvm = params.use_llvm,
12111234 .use_lld = params.use_lld,
12121235 });
1236 exe.use_new_linker = params.use_new_linker;
12131237 exe.linkage = params.linkage;
12141238 exe.pie = params.pie;
12151239 exe.bundle_ubsan_rt = false;
test/tests.zig+46-22
......@@ -2303,6 +2303,45 @@ const incremental_targets = &[_]IncrementalTarget{
23032303 },
23042304};
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
23062345fn compatible32bitArch(host: *const std.Target) ?std.Target.Cpu.Arch {
23072346 return switch (host.os.tag) {
23082347 .freebsd => switch (host.cpu.arch) {
......@@ -3323,25 +3362,9 @@ pub fn addDebuggerTests(b: *std.Build, options: DebuggerContext.Options) ?*Step
33233362 .b = b,
33243363 .options = options,
33253364 .root_step = step,
3365 .test_matrix = debugger_matrix,
33263366 };
3327 context.addTestsForTarget(&.{
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 });
3367 context.addTests();
33453368 return step;
33463369}
33473370
......@@ -3416,16 +3439,17 @@ pub fn addIncrementalTests(
34163439
34173440 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
34213447 if (options.test_target_filters.len > 0) {
34223448 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;
34243450 } else continue;
34253451 }
34263452
3427 const target_str = b.fmt("{s}-{t}", .{ triple_txt, test_target.backend });
3428
34293453 const run = b.addRunArtifact(incr_check);
34303454 run.setName(b.fmt("incr-check {s} '{s}'", .{ target_str, entry.basename }));
34313455
tools/incr-check.zig+7
......@@ -17,6 +17,7 @@ const usage =
1717 \\Debug Options:
1818 \\ --preserve-tmp
1919 \\ --debug-log foo
20 \\ --debug-link-snapshot
2021;
2122
2223pub const std_options: std.Options = .{
......@@ -60,6 +61,7 @@ pub fn main(init: std.process.Init) !void {
6061 var quiet: bool = false;
6162
6263 var debug_log_args: std.ArrayList([]const u8) = .empty;
64 var debug_link_snapshot = false;
6365
6466 var arg_it = try init.minimal.args.iterateAllocator(arena);
6567 _ = arg_it.skip();
......@@ -77,6 +79,8 @@ pub fn main(init: std.process.Init) !void {
7779 arena,
7880 arg_it.next() orelse badUsage("expected arg after --debug-log", .{}),
7981 );
82 } else if (std.mem.eql(u8, arg, "--debug-link-snapshot")) {
83 debug_link_snapshot = true;
8084 } else if (std.mem.eql(u8, arg, "--preserve-tmp")) {
8185 preserve_tmp = true;
8286 } else if (std.mem.eql(u8, arg, "-fqemu")) {
......@@ -173,6 +177,9 @@ pub fn main(init: std.process.Init) !void {
173177 for (debug_log_args.items) |arg| {
174178 try child_args.appendSlice(arena, &.{ "--debug-log", arg });
175179 }
180 if (debug_link_snapshot) {
181 try child_args.append(arena, "--debug-link-snapshot");
182 }
176183 for (case.modules) |mod| {
177184 try child_args.appendSlice(arena, &.{ "--dep", mod.name });
178185 }