authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-08-17 01:15:04-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-08-17 01:15:04-04:00
logbb70501060a8bfff25818cf1d80491d724f8a634
tree546c8d93fcbdf4e2f3e2656d5d4f45bc79e9d483
parent90989be0e31a91335f8d1c1eafb84c3b34792a8c
parented19ecd115beedfbf496c6f20995e74fbcd8ccb4
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21078 from jacobly0/new-dwarf

Dwarf: rework self-hosted debug info from scratch

51 files changed, 5267 insertions(+), 3536 deletions(-)

build.zig+9
......@@ -549,6 +549,15 @@ pub fn build(b: *std.Build) !void {
549549 test_step.dependOn(tests.addStackTraceTests(b, test_filters, optimization_modes));
550550 test_step.dependOn(tests.addCliTests(b));
551551 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filters, optimization_modes));
552 if (tests.addDebuggerTests(b, .{
553 .test_filters = test_filters,
554 .gdb = b.option([]const u8, "gdb", "path to gdb binary"),
555 .lldb = b.option([]const u8, "lldb", "path to lldb binary"),
556 .optimize_modes = optimization_modes,
557 .skip_single_threaded = skip_single_threaded,
558 .skip_non_native = skip_non_native,
559 .skip_libc = skip_libc,
560 })) |test_debugger_step| test_step.dependOn(test_debugger_step);
552561
553562 try addWasiUpdateStep(b, version);
554563
ci/x86_64-linux-debug.sh+1
......@@ -64,6 +64,7 @@ stage3-debug/bin/zig build \
6464
6565stage3-debug/bin/zig build test docs \
6666 --maxrss 21000000000 \
67 -Dlldb=$HOME/deps/lldb-zig/Debug/bin/lldb \
6768 -fqemu \
6869 -fwasmtime \
6970 -Dstatic-llvm \
ci/x86_64-linux-release.sh+1
......@@ -64,6 +64,7 @@ stage3-release/bin/zig build \
6464
6565stage3-release/bin/zig build test docs \
6666 --maxrss 21000000000 \
67 -Dlldb=$HOME/deps/lldb-zig/Release/bin/lldb \
6768 -fqemu \
6869 -fwasmtime \
6970 -Dstatic-llvm \
lib/std/array_list.zig+18
......@@ -359,6 +359,24 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
359359 return m.len;
360360 }
361361
362 pub const FixedWriter = std.io.Writer(*Self, Allocator.Error, appendWriteFixed);
363
364 /// Initializes a Writer which will append to the list but will return
365 /// `error.OutOfMemory` rather than increasing capacity.
366 pub fn fixedWriter(self: *Self) FixedWriter {
367 return .{ .context = self };
368 }
369
370 /// The purpose of this function existing is to match `std.io.Writer` API.
371 fn appendWriteFixed(self: *Self, m: []const u8) error{OutOfMemory}!usize {
372 const available_capacity = self.capacity - self.items.len;
373 if (m.len > available_capacity)
374 return error.OutOfMemory;
375
376 self.appendSliceAssumeCapacity(m);
377 return m.len;
378 }
379
362380 /// Append a value to the list `n` times.
363381 /// Allocates more memory as necessary.
364382 /// Invalidates element pointers if additional memory is needed.
lib/std/debug.zig+3
......@@ -1360,6 +1360,9 @@ test "manage resources correctly" {
13601360 return error.SkipZigTest;
13611361 }
13621362
1363 // self-hosted debug info is still too buggy
1364 if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest;
1365
13631366 const writer = std.io.null_writer;
13641367 var di = try SelfInfo.open(testing.allocator);
13651368 defer di.deinit();
lib/std/dwarf.zig+36
......@@ -95,6 +95,9 @@ pub const LNE = struct {
9595 pub const set_discriminator = 0x04;
9696 pub const lo_user = 0x80;
9797 pub const hi_user = 0xff;
98
99 // Zig extensions
100 pub const ZIG_set_decl = 0xec;
98101};
99102
100103pub const UT = struct {
......@@ -118,6 +121,8 @@ pub const LNCT = struct {
118121
119122 pub const lo_user = 0x2000;
120123 pub const hi_user = 0x3fff;
124
125 pub const LLVM_source = 0x2001;
121126};
122127
123128pub const RLE = struct {
......@@ -142,6 +147,37 @@ pub const CC = enum(u8) {
142147 GNU_renesas_sh = 0x40,
143148 GNU_borland_fastcall_i386 = 0x41,
144149
150 BORLAND_safecall = 0xb0,
151 BORLAND_stdcall = 0xb1,
152 BORLAND_pascal = 0xb2,
153 BORLAND_msfastcall = 0xb3,
154 BORLAND_msreturn = 0xb4,
155 BORLAND_thiscall = 0xb5,
156 BORLAND_fastcall = 0xb6,
157
158 LLVM_vectorcall = 0xc0,
159 LLVM_Win64 = 0xc1,
160 LLVM_X86_64SysV = 0xc2,
161 LLVM_AAPCS = 0xc3,
162 LLVM_AAPCS_VFP = 0xc4,
163 LLVM_IntelOclBicc = 0xc5,
164 LLVM_SpirFunction = 0xc6,
165 LLVM_OpenCLKernel = 0xc7,
166 LLVM_Swift = 0xc8,
167 LLVM_PreserveMost = 0xc9,
168 LLVM_PreserveAll = 0xca,
169 LLVM_X86RegCall = 0xcb,
170 LLVM_M68kRTD = 0xcc,
171 LLVM_PreserveNone = 0xcd,
172 LLVM_RISCVVectorCall = 0xce,
173 LLVM_SwiftTail = 0xcf,
174
145175 pub const lo_user = 0x40;
146176 pub const hi_user = 0xff;
147177};
178
179pub const ACCESS = struct {
180 pub const public = 0x01;
181 pub const protected = 0x02;
182 pub const private = 0x03;
183};
lib/std/dwarf/AT.zig+9
......@@ -218,6 +218,15 @@ pub const VMS_rtnbeg_pd_address = 0x2201;
218218// See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type .
219219pub const use_GNAT_descriptive_type = 0x2301;
220220pub const GNAT_descriptive_type = 0x2302;
221
222// Zig extensions.
223pub const ZIG_parent = 0x2ccd;
224pub const ZIG_padding = 0x2cce;
225pub const ZIG_relative_decl = 0x2cd0;
226pub const ZIG_decl_line_relative = 0x2cd1;
227pub const ZIG_is_allowzero = 0x2ce1;
228pub const ZIG_sentinel = 0x2ce2;
229
221230// UPC extension.
222231pub const upc_threads_scaled = 0x3210;
223232// PGI (STMicroelectronics) extensions.
lib/std/dwarf/LANG.zig+24
......@@ -35,6 +35,30 @@ pub const Fortran03 = 0x0022;
3535pub const Fortran08 = 0x0023;
3636pub const RenderScript = 0x0024;
3737pub const BLISS = 0x0025;
38pub const Kotlin = 0x0026;
39pub const Zig = 0x0027;
40pub const Crystal = 0x0028;
41pub const C_plus_plus_17 = 0x002a;
42pub const C_plus_plus_20 = 0x002b;
43pub const C17 = 0x002c;
44pub const Fortran18 = 0x002d;
45pub const Ada2005 = 0x002e;
46pub const Ada2012 = 0x002f;
47pub const HIP = 0x0030;
48pub const Assembly = 0x0031;
49pub const C_sharp = 0x0032;
50pub const Mojo = 0x0033;
51pub const GLSL = 0x0034;
52pub const GLSL_ES = 0x0035;
53pub const HLSL = 0x0036;
54pub const OpenCL_CPP = 0x0037;
55pub const CPP_for_OpenCL = 0x0038;
56pub const SYCL = 0x0039;
57pub const C_plus_plus_23 = 0x003a;
58pub const Odin = 0x003b;
59pub const Ruby = 0x0040;
60pub const Move = 0x0041;
61pub const Hylo = 0x0042;
3862
3963pub const lo_user = 0x8000;
4064pub const hi_user = 0xffff;
lib/std/io.zig+1-1
......@@ -419,7 +419,7 @@ pub const tty = @import("io/tty.zig");
419419/// A Writer that doesn't write to anything.
420420pub const null_writer: NullWriter = .{ .context = {} };
421421
422const NullWriter = Writer(void, error{}, dummyWrite);
422pub const NullWriter = Writer(void, error{}, dummyWrite);
423423fn dummyWrite(context: void, data: []const u8) error{}!usize {
424424 _ = context;
425425 return data.len;
lib/std/leb128.zig+35-20
......@@ -36,10 +36,14 @@ pub fn readUleb128(comptime T: type, reader: anytype) !T {
3636pub const readULEB128 = readUleb128;
3737
3838/// Write a single unsigned integer as unsigned LEB128 to the given writer.
39pub fn writeUleb128(writer: anytype, uint_value: anytype) !void {
40 const T = @TypeOf(uint_value);
41 const U = if (@typeInfo(T).Int.bits < 8) u8 else T;
42 var value: U = @intCast(uint_value);
39pub fn writeUleb128(writer: anytype, arg: anytype) !void {
40 const Arg = @TypeOf(arg);
41 const Int = switch (Arg) {
42 comptime_int => std.math.IntFittingRange(arg, arg),
43 else => Arg,
44 };
45 const Value = if (@typeInfo(Int).Int.bits < 8) u8 else Int;
46 var value: Value = arg;
4347
4448 while (true) {
4549 const byte: u8 = @truncate(value & 0x7f);
......@@ -118,16 +122,19 @@ pub fn readIleb128(comptime T: type, reader: anytype) !T {
118122pub const readILEB128 = readIleb128;
119123
120124/// Write a single signed integer as signed LEB128 to the given writer.
121pub fn writeIleb128(writer: anytype, int_value: anytype) !void {
122 const T = @TypeOf(int_value);
123 const S = if (@typeInfo(T).Int.bits < 8) i8 else T;
124 const U = std.meta.Int(.unsigned, @typeInfo(S).Int.bits);
125
126 var value: S = @intCast(int_value);
125pub fn writeIleb128(writer: anytype, arg: anytype) !void {
126 const Arg = @TypeOf(arg);
127 const Int = switch (Arg) {
128 comptime_int => std.math.IntFittingRange(-arg - 1, arg),
129 else => Arg,
130 };
131 const Signed = if (@typeInfo(Int).Int.bits < 8) i8 else Int;
132 const Unsigned = std.meta.Int(.unsigned, @typeInfo(Signed).Int.bits);
133 var value: Signed = arg;
127134
128135 while (true) {
129 const uvalue: U = @bitCast(value);
130 const byte: u8 = @truncate(uvalue);
136 const unsigned: Unsigned = @bitCast(value);
137 const byte: u8 = @truncate(unsigned);
131138 value >>= 6;
132139 if (value == -1 or value == 0) {
133140 try writer.writeByte(byte & 0x7F);
......@@ -147,17 +154,25 @@ pub fn writeIleb128(writer: anytype, int_value: anytype) !void {
147154/// "relocatable", meaning that it becomes possible to later go back and patch the number to be a
148155/// different value without shifting all the following code.
149156pub fn writeUnsignedFixed(comptime l: usize, ptr: *[l]u8, int: std.meta.Int(.unsigned, l * 7)) void {
150 const T = @TypeOf(int);
151 const U = if (@typeInfo(T).Int.bits < 8) u8 else T;
152 var value: U = @intCast(int);
157 writeUnsignedExtended(ptr, int);
158}
153159
154 comptime var i = 0;
155 inline while (i < (l - 1)) : (i += 1) {
156 const byte = @as(u8, @truncate(value)) | 0b1000_0000;
160/// Same as `writeUnsignedFixed` but with a runtime-known length.
161/// Asserts `slice.len > 0`.
162pub fn writeUnsignedExtended(slice: []u8, arg: anytype) void {
163 const Arg = @TypeOf(arg);
164 const Int = switch (Arg) {
165 comptime_int => std.math.IntFittingRange(arg, arg),
166 else => Arg,
167 };
168 const Value = if (@typeInfo(Int).Int.bits < 8) u8 else Int;
169 var value: Value = arg;
170
171 for (slice[0 .. slice.len - 1]) |*byte| {
172 byte.* = @truncate(0x80 | value);
157173 value >>= 7;
158 ptr[i] = byte;
159174 }
160 ptr[i] = @truncate(value);
175 slice[slice.len - 1] = @as(u7, @intCast(value));
161176}
162177
163178/// Deprecated: use `writeIleb128`
lib/std/math/big/int.zig+7-3
......@@ -2092,6 +2092,12 @@ pub const Const = struct {
20922092 return bits;
20932093 }
20942094
2095 /// Returns the number of bits required to represent the integer in twos-complement form
2096 /// with the given signedness.
2097 pub fn bitCountTwosCompForSignedness(self: Const, signedness: std.builtin.Signedness) usize {
2098 return self.bitCountTwosComp() + @intFromBool(self.positive and signedness == .signed);
2099 }
2100
20952101 /// @popCount with two's complement semantics.
20962102 ///
20972103 /// This returns the number of 1 bits set when the value would be represented in
......@@ -2147,9 +2153,7 @@ pub const Const = struct {
21472153 if (signedness == .unsigned and !self.positive) {
21482154 return false;
21492155 }
2150
2151 const req_bits = self.bitCountTwosComp() + @intFromBool(self.positive and signedness == .signed);
2152 return bit_count >= req_bits;
2156 return bit_count >= self.bitCountTwosCompForSignedness(signedness);
21532157 }
21542158
21552159 /// Returns whether self can fit into an integer of the requested type.
lib/std/mem.zig+14-5
......@@ -128,7 +128,7 @@ pub fn alignAllocLen(full_len: usize, alloc_len: usize, len_align: u29) usize {
128128 assert(full_len >= alloc_len);
129129 if (len_align == 0)
130130 return alloc_len;
131 const adjusted = alignBackwardAnyAlign(full_len, len_align);
131 const adjusted = alignBackwardAnyAlign(usize, full_len, len_align);
132132 assert(adjusted >= alloc_len);
133133 return adjusted;
134134}
......@@ -4312,6 +4312,15 @@ test "sliceAsBytes preserves pointer attributes" {
43124312 try testing.expectEqual(in.alignment, out.alignment);
43134313}
43144314
4315/// Round an address down to the next (or current) aligned address.
4316/// Unlike `alignForward`, `alignment` can be any positive number, not just a power of 2.
4317pub fn alignForwardAnyAlign(comptime T: type, addr: T, alignment: T) T {
4318 if (isValidAlignGeneric(T, alignment))
4319 return alignForward(T, addr, alignment);
4320 assert(alignment != 0);
4321 return alignBackwardAnyAlign(T, addr + (alignment - 1), alignment);
4322}
4323
43154324/// Round an address up to the next (or current) aligned address.
43164325/// The alignment must be a power of 2 and greater than 0.
43174326/// Asserts that rounding up the address does not cause integer overflow.
......@@ -4433,11 +4442,11 @@ test alignForward {
44334442
44344443/// Round an address down to the previous (or current) aligned address.
44354444/// Unlike `alignBackward`, `alignment` can be any positive number, not just a power of 2.
4436pub fn alignBackwardAnyAlign(i: usize, alignment: usize) usize {
4437 if (isValidAlign(alignment))
4438 return alignBackward(usize, i, alignment);
4445pub fn alignBackwardAnyAlign(comptime T: type, addr: T, alignment: T) T {
4446 if (isValidAlignGeneric(T, alignment))
4447 return alignBackward(T, addr, alignment);
44394448 assert(alignment != 0);
4440 return i - @mod(i, alignment);
4449 return addr - @mod(addr, alignment);
44414450}
44424451
44434452/// Round an address down to the previous (or current) aligned address.
lib/std/zig/AstGen.zig+4-1
......@@ -4405,7 +4405,6 @@ fn globalVarDecl(
44054405 .decl_line = astgen.source_line,
44064406 .astgen = astgen,
44074407 .is_comptime = true,
4408 .anon_name_strategy = .parent,
44094408 .instructions = gz.instructions,
44104409 .instructions_top = gz.instructions.items.len,
44114410 };
......@@ -4463,6 +4462,8 @@ fn globalVarDecl(
44634462 else
44644463 .none;
44654464
4465 block_scope.anon_name_strategy = .parent;
4466
44664467 const init_inst = try expr(
44674468 &block_scope,
44684469 &block_scope.base,
......@@ -4490,6 +4491,8 @@ fn globalVarDecl(
44904491 // Extern variable which has an explicit type.
44914492 const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node);
44924493
4494 block_scope.anon_name_strategy = .parent;
4495
44934496 const var_inst = try block_scope.addVar(.{
44944497 .var_type = type_inst,
44954498 .lib_name = lib_name,
src/Compilation.zig+10
......@@ -363,6 +363,7 @@ const Job = union(enum) {
363363 /// It must be deinited when the job is processed.
364364 air: Air,
365365 },
366 codegen_type: InternPool.Index,
366367 /// The `Cau` must be semantically analyzed (and possibly export itself).
367368 /// This may be its first time being analyzed, or it may be outdated.
368369 analyze_cau: InternPool.Cau.Index,
......@@ -423,6 +424,7 @@ const CodegenJob = union(enum) {
423424 /// It must be deinited when the job is processed.
424425 air: Air,
425426 },
427 type: InternPool.Index,
426428};
427429
428430pub const CObject = struct {
......@@ -3712,6 +3714,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
37123714 .air = func.air,
37133715 } });
37143716 },
3717 .codegen_type => |ty| try comp.queueCodegenJob(tid, .{ .type = ty }),
37153718 .analyze_func => |func| {
37163719 const named_frame = tracy.namedFrame("analyze_func");
37173720 defer named_frame.end();
......@@ -4001,6 +4004,13 @@ fn processOneCodegenJob(tid: usize, comp: *Compilation, codegen_job: CodegenJob)
40014004 // This call takes ownership of `func.air`.
40024005 try pt.linkerUpdateFunc(func.func, func.air);
40034006 },
4007 .type => |ty| {
4008 const named_frame = tracy.namedFrame("codegen_type");
4009 defer named_frame.end();
4010
4011 const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };
4012 try pt.linkerUpdateContainerType(ty);
4013 },
40044014 }
40054015}
40064016
src/InternPool.zig+1-1
......@@ -4003,7 +4003,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
40034003 }
40044004}
40054005
4006const LoadedEnumType = struct {
4006pub const LoadedEnumType = struct {
40074007 // TODO: the non-fqn will be needed by the new dwarf structure
40084008 /// The name of this enum type.
40094009 name: NullTerminatedString,
src/Sema.zig+35
......@@ -2845,6 +2845,11 @@ fn zirStructDecl(
28452845 try pt.scanNamespace(new_namespace_index, decls);
28462846
28472847 try mod.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
2848 codegen_type: {
2849 if (mod.comp.config.use_llvm) break :codegen_type;
2850 if (block.ownerModule().strip) break :codegen_type;
2851 try mod.comp.queueJob(.{ .codegen_type = wip_ty.index });
2852 }
28482853 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index }));
28492854 try sema.declareDependency(.{ .interned = wip_ty.index });
28502855 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
......@@ -3213,6 +3218,11 @@ fn zirEnumDecl(
32133218 }
32143219 }
32153220
3221 codegen_type: {
3222 if (mod.comp.config.use_llvm) break :codegen_type;
3223 if (block.ownerModule().strip) break :codegen_type;
3224 try mod.comp.queueJob(.{ .codegen_type = wip_ty.index });
3225 }
32163226 return Air.internedToRef(wip_ty.index);
32173227}
32183228
......@@ -3323,6 +3333,11 @@ fn zirUnionDecl(
33233333 try pt.scanNamespace(new_namespace_index, decls);
33243334
33253335 try mod.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
3336 codegen_type: {
3337 if (mod.comp.config.use_llvm) break :codegen_type;
3338 if (block.ownerModule().strip) break :codegen_type;
3339 try mod.comp.queueJob(.{ .codegen_type = wip_ty.index });
3340 }
33263341 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index }));
33273342 try sema.declareDependency(.{ .interned = wip_ty.index });
33283343 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
......@@ -3396,6 +3411,11 @@ fn zirOpaqueDecl(
33963411 const decls = sema.code.bodySlice(extra_index, decls_len);
33973412 try pt.scanNamespace(new_namespace_index, decls);
33983413
3414 codegen_type: {
3415 if (mod.comp.config.use_llvm) break :codegen_type;
3416 if (block.ownerModule().strip) break :codegen_type;
3417 try mod.comp.queueJob(.{ .codegen_type = wip_ty.index });
3418 }
33993419 return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index));
34003420}
34013421
......@@ -22071,6 +22091,11 @@ fn reifyEnum(
2207122091 return sema.fail(block, src, "non-exhaustive enum specified every value", .{});
2207222092 }
2207322093
22094 codegen_type: {
22095 if (mod.comp.config.use_llvm) break :codegen_type;
22096 if (block.ownerModule().strip) break :codegen_type;
22097 try mod.comp.queueJob(.{ .codegen_type = wip_ty.index });
22098 }
2207422099 return Air.internedToRef(wip_ty.index);
2207522100}
2207622101
......@@ -22318,6 +22343,11 @@ fn reifyUnion(
2231822343 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
2231922344
2232022345 try mod.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
22346 codegen_type: {
22347 if (mod.comp.config.use_llvm) break :codegen_type;
22348 if (block.ownerModule().strip) break :codegen_type;
22349 try mod.comp.queueJob(.{ .codegen_type = wip_ty.index });
22350 }
2232122351 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index }));
2232222352 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
2232322353}
......@@ -22591,6 +22621,11 @@ fn reifyStruct(
2259122621 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
2259222622
2259322623 try mod.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
22624 codegen_type: {
22625 if (mod.comp.config.use_llvm) break :codegen_type;
22626 if (block.ownerModule().strip) break :codegen_type;
22627 try mod.comp.queueJob(.{ .codegen_type = wip_ty.index });
22628 }
2259422629 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index }));
2259522630 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
2259622631}
src/Type.zig+1-1
......@@ -2208,7 +2208,7 @@ pub fn errorSetHasField(ty: Type, name: []const u8, mod: *Module) bool {
22082208 const field_name_interned = ip.getString(name).unwrap() orelse return false;
22092209 return error_set_type.nameIndex(ip, field_name_interned) != null;
22102210 },
2211 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
2211 .inferred_error_set_type => |i| switch (ip.funcIesResolvedUnordered(i)) {
22122212 .anyerror_type => true,
22132213 .none => false,
22142214 else => |t| {
src/Zcu.zig+9-1
......@@ -2737,7 +2737,7 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit
27372737
27382738pub fn errorSetBits(mod: *Zcu) u16 {
27392739 if (mod.error_limit == 0) return 0;
2740 return std.math.log2_int_ceil(ErrorInt, mod.error_limit + 1); // +1 for no error
2740 return @as(u16, std.math.log2_int(ErrorInt, mod.error_limit)) + 1;
27412741}
27422742
27432743pub fn errNote(
......@@ -3005,6 +3005,14 @@ pub const UnionLayout = struct {
30053005 tag_align: Alignment,
30063006 tag_size: u64,
30073007 padding: u32,
3008
3009 pub fn tagOffset(layout: UnionLayout) u64 {
3010 return if (layout.tag_align.compare(.lt, layout.payload_align)) layout.payload_size else 0;
3011 }
3012
3013 pub fn payloadOffset(layout: UnionLayout) u64 {
3014 return if (layout.tag_align.compare(.lt, layout.payload_align)) 0 else layout.tag_size;
3015 }
30083016};
30093017
30103018/// Returns the index of the active field, given the current tag value
src/Zcu/PerThread.zig+25-1
......@@ -911,6 +911,11 @@ fn createFileRootStruct(
911911
912912 try pt.scanNamespace(namespace_index, decls);
913913 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
914 codegen_type: {
915 if (zcu.comp.config.use_llvm) break :codegen_type;
916 if (file.mod.strip) break :codegen_type;
917 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
918 }
914919 zcu.setFileRootType(file_index, wip_ty.index);
915920 return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index);
916921}
......@@ -1332,7 +1337,10 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
13321337 // to the `codegen_nav` job.
13331338 try decl_ty.resolveFully(pt);
13341339
1335 if (!decl_ty.isFnOrHasRuntimeBits(pt)) break :queue_codegen;
1340 if (!decl_ty.isFnOrHasRuntimeBits(pt)) {
1341 if (zcu.comp.config.use_llvm) break :queue_codegen;
1342 if (file.mod.strip) break :queue_codegen;
1343 }
13361344
13371345 try zcu.comp.queueJob(.{ .codegen_nav = nav_index });
13381346 }
......@@ -2588,6 +2596,22 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void
25882596 }
25892597}
25902598
2599pub fn linkerUpdateContainerType(pt: Zcu.PerThread, ty: InternPool.Index) !void {
2600 const zcu = pt.zcu;
2601 const comp = zcu.comp;
2602 const ip = &zcu.intern_pool;
2603
2604 const codegen_prog_node = zcu.codegen_prog_node.start(Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), 0);
2605 defer codegen_prog_node.end();
2606
2607 if (comp.bin_file) |lf| {
2608 lf.updateContainerType(pt, ty) catch |err| switch (err) {
2609 error.OutOfMemory => return error.OutOfMemory,
2610 else => |e| log.err("codegen type failed: {s}", .{@errorName(e)}),
2611 };
2612 }
2613}
2614
25912615pub fn reportRetryableAstGenError(
25922616 pt: Zcu.PerThread,
25932617 src: Zcu.AstGenSrc,
src/arch/aarch64/CodeGen.zig+20-31
......@@ -18,7 +18,6 @@ const ErrorMsg = Zcu.ErrorMsg;
1818const Target = std.Target;
1919const Allocator = mem.Allocator;
2020const trace = @import("../../tracy.zig").trace;
21const DW = std.dwarf;
2221const leb128 = std.leb;
2322const log = std.log.scoped(.codegen);
2423const build_options = @import("build_options");
......@@ -181,11 +180,11 @@ const DbgInfoReloc = struct {
181180 }
182181 }
183182
184 fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void {
183 fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
185184 switch (function.debug_output) {
186185 .dwarf => |dw| {
187 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (reloc.mcv) {
188 .register => |reg| .{ .register = reg.dwarfLocOp() },
186 const loc: link.File.Dwarf.Loc = switch (reloc.mcv) {
187 .register => |reg| .{ .reg = reg.dwarfNum() },
189188 .stack_offset,
190189 .stack_argument_offset,
191190 => |offset| blk: {
......@@ -194,15 +193,15 @@ const DbgInfoReloc = struct {
194193 .stack_argument_offset => @as(i32, @intCast(function.saved_regs_stack_space + offset)),
195194 else => unreachable,
196195 };
197 break :blk .{ .stack = .{
198 .fp_register = Register.x29.dwarfLocOpDeref(),
199 .offset = adjusted_offset,
196 break :blk .{ .plus = .{
197 &.{ .breg = Register.x29.dwarfNum() },
198 &.{ .consts = adjusted_offset },
200199 } };
201200 },
202201 else => unreachable, // not a possible argument
203202
204203 };
205 try dw.genArgDbgInfo(reloc.name, reloc.ty, function.owner_nav, loc);
204 try dw.genVarDebugInfo(.local_arg, reloc.name, reloc.ty, loc);
206205 },
207206 .plan9 => {},
208207 .none => {},
......@@ -210,16 +209,10 @@ const DbgInfoReloc = struct {
210209 }
211210
212211 fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
213 const is_ptr = switch (reloc.tag) {
214 .dbg_var_ptr => true,
215 .dbg_var_val => false,
216 else => unreachable,
217 };
218
219212 switch (function.debug_output) {
220 .dwarf => |dw| {
221 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (reloc.mcv) {
222 .register => |reg| .{ .register = reg.dwarfLocOp() },
213 .dwarf => |dwarf| {
214 const loc: link.File.Dwarf.Loc = switch (reloc.mcv) {
215 .register => |reg| .{ .reg = reg.dwarfNum() },
223216 .ptr_stack_offset,
224217 .stack_offset,
225218 .stack_argument_offset,
......@@ -231,24 +224,20 @@ const DbgInfoReloc = struct {
231224 .stack_argument_offset => @as(i32, @intCast(function.saved_regs_stack_space + offset)),
232225 else => unreachable,
233226 };
234 break :blk .{
235 .stack = .{
236 .fp_register = Register.x29.dwarfLocOpDeref(),
237 .offset = adjusted_offset,
238 },
239 };
227 break :blk .{ .plus = .{
228 &.{ .reg = Register.x29.dwarfNum() },
229 &.{ .consts = adjusted_offset },
230 } };
240231 },
241 .memory => |address| .{ .memory = address },
242 .linker_load => |linker_load| .{ .linker_load = linker_load },
243 .immediate => |x| .{ .immediate = x },
244 .undef => .undef,
245 .none => .none,
232 .memory => |address| .{ .constu = address },
233 .immediate => |x| .{ .constu = x },
234 .none => .empty,
246235 else => blk: {
247236 log.debug("TODO generate debug info for {}", .{reloc.mcv});
248 break :blk .nop;
237 break :blk .empty;
249238 },
250239 };
251 try dw.genVarDbgInfo(reloc.name, reloc.ty, function.owner_nav, is_ptr, loc);
240 try dwarf.genVarDebugInfo(.local_var, reloc.name, reloc.ty, loc);
252241 },
253242 .plan9 => {},
254243 .none => {},
......@@ -6207,7 +6196,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
62076196 .memory => |addr| .{ .memory = addr },
62086197 .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },
62096198 .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } },
6210 .load_symbol, .load_tlv, .lea_symbol => unreachable, // TODO
6199 .load_symbol, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO
62116200 },
62126201 .fail => |msg| {
62136202 self.err_msg = msg;
src/arch/aarch64/bits.zig+2-10
......@@ -1,6 +1,5 @@
11const std = @import("std");
22const builtin = @import("builtin");
3const DW = std.dwarf;
43const assert = std.debug.assert;
54const testing = std.testing;
65
......@@ -295,15 +294,8 @@ pub const Register = enum(u8) {
295294 };
296295 }
297296
298 pub fn dwarfLocOp(self: Register) u8 {
299 return @as(u8, self.enc()) + DW.OP.reg0;
300 }
301
302 /// DWARF encodings that push a value onto the DWARF stack that is either
303 /// the contents of a register or the result of adding the contents a given
304 /// register to a given signed offset.
305 pub fn dwarfLocOpDeref(self: Register) u8 {
306 return @as(u8, self.enc()) + DW.OP.breg0;
297 pub fn dwarfNum(self: Register) u5 {
298 return self.enc();
307299 }
308300};
309301
src/arch/arm/CodeGen.zig+18-26
......@@ -18,7 +18,6 @@ const ErrorMsg = Zcu.ErrorMsg;
1818const Target = std.Target;
1919const Allocator = mem.Allocator;
2020const trace = @import("../../tracy.zig").trace;
21const DW = std.dwarf;
2221const leb128 = std.leb;
2322const log = std.log.scoped(.codegen);
2423const build_options = @import("build_options");
......@@ -259,11 +258,11 @@ const DbgInfoReloc = struct {
259258 }
260259 }
261260
262 fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void {
261 fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
263262 switch (function.debug_output) {
264263 .dwarf => |dw| {
265 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (reloc.mcv) {
266 .register => |reg| .{ .register = reg.dwarfLocOp() },
264 const loc: link.File.Dwarf.Loc = switch (reloc.mcv) {
265 .register => |reg| .{ .reg = reg.dwarfNum() },
267266 .stack_offset,
268267 .stack_argument_offset,
269268 => blk: {
......@@ -272,15 +271,15 @@ const DbgInfoReloc = struct {
272271 .stack_argument_offset => |offset| @as(i32, @intCast(function.saved_regs_stack_space + offset)),
273272 else => unreachable,
274273 };
275 break :blk .{ .stack = .{
276 .fp_register = DW.OP.breg11,
277 .offset = adjusted_stack_offset,
274 break :blk .{ .plus = .{
275 &.{ .reg = 11 },
276 &.{ .consts = adjusted_stack_offset },
278277 } };
279278 },
280279 else => unreachable, // not a possible argument
281280 };
282281
283 try dw.genArgDbgInfo(reloc.name, reloc.ty, function.pt.zcu.funcInfo(function.func_index).owner_nav, loc);
282 try dw.genVarDebugInfo(.local_arg, reloc.name, reloc.ty, loc);
284283 },
285284 .plan9 => {},
286285 .none => {},
......@@ -288,16 +287,10 @@ const DbgInfoReloc = struct {
288287 }
289288
290289 fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
291 const is_ptr = switch (reloc.tag) {
292 .dbg_var_ptr => true,
293 .dbg_var_val => false,
294 else => unreachable,
295 };
296
297290 switch (function.debug_output) {
298291 .dwarf => |dw| {
299 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (reloc.mcv) {
300 .register => |reg| .{ .register = reg.dwarfLocOp() },
292 const loc: link.File.Dwarf.Loc = switch (reloc.mcv) {
293 .register => |reg| .{ .reg = reg.dwarfNum() },
301294 .ptr_stack_offset,
302295 .stack_offset,
303296 .stack_argument_offset,
......@@ -309,21 +302,20 @@ const DbgInfoReloc = struct {
309302 .stack_argument_offset => @as(i32, @intCast(function.saved_regs_stack_space + offset)),
310303 else => unreachable,
311304 };
312 break :blk .{ .stack = .{
313 .fp_register = DW.OP.breg11,
314 .offset = adjusted_offset,
305 break :blk .{ .plus = .{
306 &.{ .reg = 11 },
307 &.{ .consts = adjusted_offset },
315308 } };
316309 },
317 .memory => |address| .{ .memory = address },
318 .immediate => |x| .{ .immediate = x },
319 .undef => .undef,
320 .none => .none,
310 .memory => |address| .{ .constu = address },
311 .immediate => |x| .{ .constu = x },
312 .none => .empty,
321313 else => blk: {
322314 log.debug("TODO generate debug info for {}", .{reloc.mcv});
323 break :blk .nop;
315 break :blk .empty;
324316 },
325317 };
326 try dw.genVarDbgInfo(reloc.name, reloc.ty, function.pt.zcu.funcInfo(function.func_index).owner_nav, is_ptr, loc);
318 try dw.genVarDebugInfo(.local_var, reloc.name, reloc.ty, loc);
327319 },
328320 .plan9 => {},
329321 .none => {},
......@@ -6170,7 +6162,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
61706162 .mcv => |mcv| switch (mcv) {
61716163 .none => .none,
61726164 .undef => .undef,
6173 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol => unreachable, // TODO
6165 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO
61746166 .immediate => |imm| .{ .immediate = @truncate(imm) },
61756167 .memory => |addr| .{ .memory = addr },
61766168 },
src/arch/arm/bits.zig+4-5
......@@ -1,5 +1,4 @@
11const std = @import("std");
2const DW = std.dwarf;
32const assert = std.debug.assert;
43const testing = std.testing;
54
......@@ -158,12 +157,12 @@ pub const Register = enum(u5) {
158157
159158 /// Returns the unique 4-bit ID of this register which is used in
160159 /// the machine code
161 pub fn id(self: Register) u4 {
162 return @as(u4, @truncate(@intFromEnum(self)));
160 pub fn id(reg: Register) u4 {
161 return @truncate(@intFromEnum(reg));
163162 }
164163
165 pub fn dwarfLocOp(self: Register) u8 {
166 return @as(u8, self.id()) + DW.OP.reg0;
164 pub fn dwarfNum(reg: Register) u4 {
165 return reg.id();
167166 }
168167};
169168
src/arch/riscv64/CodeGen.zig+12-27
......@@ -4677,9 +4677,7 @@ fn genArgDbgInfo(func: Func, inst: Air.Inst.Index, mcv: MCValue) !void {
46774677
46784678 switch (func.debug_output) {
46794679 .dwarf => |dw| switch (mcv) {
4680 .register => |reg| try dw.genArgDbgInfo(name, ty, func.owner.nav_index, .{
4681 .register = reg.dwarfLocOp(),
4682 }),
4680 .register => |reg| try dw.genVarDebugInfo(.local_arg, name, ty, .{ .reg = reg.dwarfNum() }),
46834681 .load_frame => {},
46844682 else => {},
46854683 },
......@@ -5184,43 +5182,30 @@ fn airDbgVar(func: *Func, inst: Air.Inst.Index) !void {
51845182
51855183 const name = func.air.nullTerminatedString(pl_op.payload);
51865184
5187 const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)];
5188 try func.genVarDbgInfo(tag, ty, mcv, name);
5185 try func.genVarDbgInfo(ty, mcv, name);
51895186
51905187 return func.finishAir(inst, .unreach, .{ operand, .none, .none });
51915188}
51925189
51935190fn genVarDbgInfo(
51945191 func: Func,
5195 tag: Air.Inst.Tag,
51965192 ty: Type,
51975193 mcv: MCValue,
5198 name: [:0]const u8,
5194 name: []const u8,
51995195) !void {
5200 const is_ptr = switch (tag) {
5201 .dbg_var_ptr => true,
5202 .dbg_var_val => false,
5203 else => unreachable,
5204 };
5205
52065196 switch (func.debug_output) {
5207 .dwarf => |dw| {
5208 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (mcv) {
5209 .register => |reg| .{ .register = reg.dwarfLocOp() },
5210 .memory => |address| .{ .memory = address },
5211 .load_symbol => |sym_off| loc: {
5212 assert(sym_off.off == 0);
5213 break :loc .{ .linker_load = .{ .type = .direct, .sym_index = sym_off.sym } };
5214 },
5215 .immediate => |x| .{ .immediate = x },
5216 .undef => .undef,
5217 .none => .none,
5197 .dwarf => |dwarf| {
5198 const loc: link.File.Dwarf.Loc = switch (mcv) {
5199 .register => |reg| .{ .reg = reg.dwarfNum() },
5200 .memory => |address| .{ .constu = address },
5201 .immediate => |x| .{ .constu = x },
5202 .none => .empty,
52185203 else => blk: {
52195204 // log.warn("TODO generate debug info for {}", .{mcv});
5220 break :blk .nop;
5205 break :blk .empty;
52215206 },
52225207 };
5223 try dw.genVarDbgInfo(name, ty, func.owner.nav_index, is_ptr, loc);
5208 try dwarf.genVarDebugInfo(.local_var, name, ty, loc);
52245209 },
52255210 .plan9 => {},
52265211 .none => {},
......@@ -8031,7 +8016,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
80318016 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
80328017 .immediate => |imm| .{ .immediate = imm },
80338018 .memory => |addr| .{ .memory = addr },
8034 .load_got, .load_direct => {
8019 .load_got, .load_direct, .lea_direct => {
80358020 return func.fail("TODO: genTypedValue {s}", .{@tagName(mcv)});
80368021 },
80378022 },
src/arch/riscv64/bits.zig+2-3
......@@ -1,5 +1,4 @@
11const std = @import("std");
2const DW = std.dwarf;
32const assert = std.debug.assert;
43const testing = std.testing;
54const Target = std.Target;
......@@ -207,8 +206,8 @@ pub const Register = enum(u8) {
207206 return @truncate(@intFromEnum(reg));
208207 }
209208
210 pub fn dwarfLocOp(reg: Register) u8 {
211 return @as(u8, reg.id());
209 pub fn dwarfNum(reg: Register) u8 {
210 return reg.id();
212211 }
213212
214213 pub fn bitSize(reg: Register, zcu: *const Zcu) u32 {
src/arch/sparc64/CodeGen.zig+3-6
......@@ -3579,18 +3579,15 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
35793579}
35803580
35813581fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
3582 const pt = self.pt;
3583 const mod = pt.zcu;
35843582 const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg;
35853583 const ty = arg.ty.toType();
3586 const owner_nav = mod.funcInfo(self.func_index).owner_nav;
35873584 if (arg.name == .none) return;
35883585 const name = self.air.nullTerminatedString(@intFromEnum(arg.name));
35893586
35903587 switch (self.debug_output) {
35913588 .dwarf => |dw| switch (mcv) {
3592 .register => |reg| try dw.genArgDbgInfo(name, ty, owner_nav, .{
3593 .register = reg.dwarfLocOp(),
3589 .register => |reg| try dw.genVarDebugInfo(.local_arg, name, ty, .{
3590 .reg = reg.dwarfNum(),
35943591 }),
35953592 else => {},
35963593 },
......@@ -4127,7 +4124,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
41274124 .mcv => |mcv| switch (mcv) {
41284125 .none => .none,
41294126 .undef => .undef,
4130 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol => unreachable, // TODO
4127 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO
41314128 .immediate => |imm| .{ .immediate = imm },
41324129 .memory => |addr| .{ .memory = addr },
41334130 },
src/arch/sparc64/bits.zig+6-7
......@@ -1,5 +1,4 @@
11const std = @import("std");
2const DW = std.dwarf;
32const assert = std.debug.assert;
43const testing = std.testing;
54
......@@ -15,17 +14,17 @@ pub const Register = enum(u6) {
1514 fp = 62, // frame pointer (i6)
1615 // zig fmt: on
1716
18 pub fn id(self: Register) u5 {
19 return @as(u5, @truncate(@intFromEnum(self)));
17 pub fn id(reg: Register) u5 {
18 return @truncate(@intFromEnum(reg));
2019 }
2120
22 pub fn enc(self: Register) u5 {
21 pub fn enc(reg: Register) u5 {
2322 // For integer registers, enc() == id().
24 return self.id();
23 return reg.id();
2524 }
2625
27 pub fn dwarfLocOp(reg: Register) u8 {
28 return @as(u8, reg.id()) + DW.OP.reg0;
26 pub fn dwarfNum(reg: Register) u5 {
27 return reg.id();
2928 }
3029};
3130
src/arch/wasm/CodeGen.zig+8-7
......@@ -742,7 +742,7 @@ const InnerError = error{
742742 CodegenFail,
743743 /// Compiler implementation could not handle a large integer.
744744 Overflow,
745};
745} || link.File.UpdateDebugInfoError;
746746
747747pub fn deinit(func: *CodeGen) void {
748748 // in case of an error and we still have branches
......@@ -2588,8 +2588,8 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
25882588 const name_nts = func.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
25892589 if (name_nts != .none) {
25902590 const name = func.air.nullTerminatedString(@intFromEnum(name_nts));
2591 try dwarf.genArgDbgInfo(name, arg_ty, func.owner_nav, .{
2592 .wasm_local = arg.local.value,
2591 try dwarf.genVarDebugInfo(.local_arg, name, arg_ty, .{
2592 .wasm_ext = .{ .local = arg.local.value },
25932593 });
25942594 }
25952595 },
......@@ -6455,6 +6455,7 @@ fn airDbgInlineBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
64556455}
64566456
64576457fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void {
6458 _ = is_ptr;
64586459 if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{});
64596460
64606461 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
......@@ -6466,14 +6467,14 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void
64666467 const name = func.air.nullTerminatedString(pl_op.payload);
64676468 log.debug(" var name = ({s})", .{name});
64686469
6469 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (operand) {
6470 .local => |local| .{ .wasm_local = local.value },
6470 const loc: link.File.Dwarf.Loc = switch (operand) {
6471 .local => |local| .{ .wasm_ext = .{ .local = local.value } },
64716472 else => blk: {
64726473 log.debug("TODO generate debug info for {}", .{operand});
6473 break :blk .nop;
6474 break :blk .empty;
64746475 },
64756476 };
6476 try func.debug_output.dwarf.genVarDbgInfo(name, ty, func.owner_nav, is_ptr, loc);
6477 try func.debug_output.dwarf.genVarDebugInfo(.local_var, name, ty, loc);
64776478
64786479 return func.finishAir(inst, .none, &.{});
64796480}
src/arch/x86/bits.zig+3-14
......@@ -1,5 +1,4 @@
11const std = @import("std");
2const DW = std.dwarf;
32
43// zig fmt: off
54pub const Register = enum(u8) {
......@@ -44,18 +43,8 @@ pub const Register = enum(u8) {
4443 return @enumFromInt(@as(u8, self.id()) + 16);
4544 }
4645
47 pub fn dwarfLocOp(reg: Register) u8 {
48 return switch (reg.to32()) {
49 .eax => DW.OP.reg0,
50 .ecx => DW.OP.reg1,
51 .edx => DW.OP.reg2,
52 .ebx => DW.OP.reg3,
53 .esp => DW.OP.reg4,
54 .ebp => DW.OP.reg5,
55 .esi => DW.OP.reg6,
56 .edi => DW.OP.reg7,
57 else => unreachable,
58 };
46 pub fn dwarfNum(reg: Register) u8 {
47 return @intFromEnum(reg.to32());
5948 }
6049};
6150
......@@ -64,7 +53,7 @@ pub const Register = enum(u8) {
6453/// TODO this set is actually a set of caller-saved registers.
6554pub const callee_preserved_regs = [_]Register{ .eax, .ecx, .edx, .esi, .edi };
6655
67// TODO add these to Register enum and corresponding dwarfLocOp
56// TODO add these to Register enum and corresponding dwarfNum
6857// // Return Address register. This is stored in `0(%esp, "")` and is not a physical register.
6958// RA = (8, "RA"),
7059//
src/arch/x86_64/CodeGen.zig+183-129
......@@ -18,7 +18,6 @@ const Allocator = mem.Allocator;
1818const CodeGenError = codegen.CodeGenError;
1919const Compilation = @import("../../Compilation.zig");
2020const DebugInfoOutput = codegen.DebugInfoOutput;
21const DW = std.dwarf;
2221const ErrorMsg = Zcu.ErrorMsg;
2322const Result = codegen.Result;
2423const Emit = @import("Emit.zig");
......@@ -82,6 +81,9 @@ mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
8281/// MIR extra data
8382mir_extra: std.ArrayListUnmanaged(u32) = .{},
8483
84stack_args: std.ArrayListUnmanaged(StackVar) = .{},
85stack_vars: std.ArrayListUnmanaged(StackVar) = .{},
86
8587/// Byte offset within the source file of the ending curly.
8688end_di_line: u32,
8789end_di_column: u32,
......@@ -726,6 +728,12 @@ const InstTracking = struct {
726728 }
727729};
728730
731const StackVar = struct {
732 name: []const u8,
733 type: Type,
734 frame_addr: FrameAddr,
735};
736
729737const FrameAlloc = struct {
730738 abi_size: u31,
731739 spill_pad: u3,
......@@ -831,6 +839,8 @@ pub fn generate(
831839 function.exitlude_jump_relocs.deinit(gpa);
832840 function.mir_instructions.deinit(gpa);
833841 function.mir_extra.deinit(gpa);
842 function.stack_args.deinit(gpa);
843 function.stack_vars.deinit(gpa);
834844 }
835845
836846 wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)});
......@@ -903,14 +913,17 @@ pub fn generate(
903913 else => |e| return e,
904914 };
905915
906 var mir = Mir{
916 try function.genStackVarDebugInfo(.local_arg, function.stack_args.items);
917 try function.genStackVarDebugInfo(.local_var, function.stack_vars.items);
918
919 var mir: Mir = .{
907920 .instructions = function.mir_instructions.toOwnedSlice(),
908921 .extra = try function.mir_extra.toOwnedSlice(gpa),
909922 .frame_locs = function.frame_locs.toOwnedSlice(),
910923 };
911924 defer mir.deinit(gpa);
912925
913 var emit = Emit{
926 var emit: Emit = .{
914927 .lower = .{
915928 .bin_file = bin_file,
916929 .allocator = gpa,
......@@ -1956,12 +1969,46 @@ fn gen(self: *Self) InnerError!void {
19561969 });
19571970}
19581971
1972fn checkInvariantsAfterAirInst(self: *Self, inst: Air.Inst.Index, old_air_bookkeeping: @TypeOf(air_bookkeeping_init)) void {
1973 assert(!self.register_manager.lockedRegsExist());
1974
1975 if (std.debug.runtime_safety) {
1976 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
1977 std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, self.air.instructions.items(.tag)[@intFromEnum(inst)] });
1978 }
1979
1980 { // check consistency of tracked registers
1981 var it = self.register_manager.free_registers.iterator(.{ .kind = .unset });
1982 while (it.next()) |index| {
1983 const tracked_inst = self.register_manager.registers[index];
1984 const tracking = self.getResolvedInstValue(tracked_inst);
1985 for (tracking.getRegs()) |reg| {
1986 if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break;
1987 } else unreachable; // tracked register not in use
1988 }
1989 }
1990 }
1991}
1992
19591993fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
19601994 const pt = self.pt;
19611995 const mod = pt.zcu;
19621996 const ip = &mod.intern_pool;
19631997 const air_tags = self.air.instructions.items(.tag);
19641998
1999 for (body) |inst| {
2000 wip_mir_log.debug("{}", .{self.fmtAir(inst)});
2001 verbose_tracking_log.debug("{}", .{self.fmtTracking()});
2002
2003 const old_air_bookkeeping = self.air_bookkeeping;
2004 try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1);
2005 switch (air_tags[@intFromEnum(inst)]) {
2006 .arg => try self.airArg(inst),
2007 else => break,
2008 }
2009 self.checkInvariantsAfterAirInst(inst, old_air_bookkeeping);
2010 }
2011
19652012 for (body) |inst| {
19662013 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue;
19672014 wip_mir_log.debug("{}", .{self.fmtAir(inst)});
......@@ -2041,7 +2088,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
20412088
20422089 .alloc => try self.airAlloc(inst),
20432090 .ret_ptr => try self.airRetPtr(inst),
2044 .arg => try self.airArg(inst),
2091 .arg => try self.airDbgArg(inst),
20452092 .assembly => try self.airAsm(inst),
20462093 .bitcast => try self.airBitCast(inst),
20472094 .block => try self.airBlock(inst),
......@@ -2205,25 +2252,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
22052252 .work_group_id => unreachable,
22062253 // zig fmt: on
22072254 }
2208
2209 assert(!self.register_manager.lockedRegsExist());
2210
2211 if (std.debug.runtime_safety) {
2212 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
2213 std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, air_tags[@intFromEnum(inst)] });
2214 }
2215
2216 { // check consistency of tracked registers
2217 var it = self.register_manager.free_registers.iterator(.{ .kind = .unset });
2218 while (it.next()) |index| {
2219 const tracked_inst = self.register_manager.registers[index];
2220 const tracking = self.getResolvedInstValue(tracked_inst);
2221 for (tracking.getRegs()) |reg| {
2222 if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break;
2223 } else unreachable; // tracked register not in use
2224 }
2225 }
2226 }
2255 self.checkInvariantsAfterAirInst(inst, old_air_bookkeeping);
22272256 }
22282257 verbose_tracking_log.debug("{}", .{self.fmtTracking()});
22292258}
......@@ -2338,7 +2367,7 @@ fn finishAirBookkeeping(self: *Self) void {
23382367}
23392368
23402369fn finishAirResult(self: *Self, inst: Air.Inst.Index, result: MCValue) void {
2341 if (self.liveness.isUnused(inst)) switch (result) {
2370 if (self.liveness.isUnused(inst) and self.air.instructions.items(.tag)[@intFromEnum(inst)] != .arg) switch (result) {
23422371 .none, .dead, .unreach => {},
23432372 else => unreachable, // Why didn't the result die?
23442373 } else {
......@@ -2425,7 +2454,7 @@ fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayo
24252454 const callee_preserved_regs =
24262455 abi.getCalleePreservedRegs(abi.resolveCallingConvention(cc, self.target.*));
24272456 for (callee_preserved_regs) |reg| {
2428 if (self.register_manager.isRegAllocated(reg) or true) {
2457 if (self.register_manager.isRegAllocated(reg)) {
24292458 save_reg_list.push(callee_preserved_regs, reg);
24302459 }
24312460 }
......@@ -5985,10 +6014,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
59856014 switch (operand) {
59866015 .load_frame => |frame_addr| {
59876016 if (tag_abi_size <= 8) {
5988 const off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))
5989 @intCast(layout.payload_size)
5990 else
5991 0;
6017 const off: i32 = @intCast(layout.tagOffset());
59926018 break :blk try self.copyToRegisterWithInstTracking(inst, tag_ty, .{
59936019 .load_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off },
59946020 });
......@@ -6000,10 +6026,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
60006026 );
60016027 },
60026028 .register => {
6003 const shift: u6 = if (layout.tag_align.compare(.lt, layout.payload_align))
6004 @intCast(layout.payload_size * 8)
6005 else
6006 0;
6029 const shift: u6 = @intCast(layout.tagOffset() * 8);
60076030 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
60086031 try self.genShiftBinOpMir(
60096032 .{ ._r, .sh },
......@@ -11813,30 +11836,30 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
1181311836
1181411837fn airArg(self: *Self, inst: Air.Inst.Index) !void {
1181511838 const pt = self.pt;
11816 const mod = pt.zcu;
11839 const zcu = pt.zcu;
1181711840 // skip zero-bit arguments as they don't have a corresponding arg instruction
1181811841 var arg_index = self.arg_index;
1181911842 while (self.args[arg_index] == .none) arg_index += 1;
1182011843 self.arg_index = arg_index + 1;
1182111844
11822 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
11845 const result: MCValue = if (self.debug_output == .none and self.liveness.isUnused(inst)) .unreach else result: {
1182311846 const arg_ty = self.typeOfIndex(inst);
1182411847 const src_mcv = self.args[arg_index];
11825 const dst_mcv = switch (src_mcv) {
11826 .register, .register_pair, .load_frame => dst: {
11848 switch (src_mcv) {
11849 .register, .register_pair, .load_frame => {
1182711850 for (src_mcv.getRegs()) |reg| self.register_manager.getRegAssumeFree(reg, inst);
11828 break :dst src_mcv;
11851 break :result src_mcv;
1182911852 },
11830 .indirect => |reg_off| dst: {
11853 .indirect => |reg_off| {
1183111854 self.register_manager.getRegAssumeFree(reg_off.reg, inst);
1183211855 const dst_mcv = try self.allocRegOrMem(inst, false);
1183311856 try self.genCopy(arg_ty, dst_mcv, src_mcv, .{});
11834 break :dst dst_mcv;
11857 break :result dst_mcv;
1183511858 },
11836 .elementwise_regs_then_frame => |regs_frame_addr| dst: {
11859 .elementwise_regs_then_frame => |regs_frame_addr| {
1183711860 try self.spillEflagsIfOccupied();
1183811861
11839 const fn_info = mod.typeToFunc(self.fn_type).?;
11862 const fn_info = zcu.typeToFunc(self.fn_type).?;
1184011863 const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*);
1184111864 const param_int_regs = abi.getCAbiIntParamRegs(cc);
1184211865 var prev_reg: Register = undefined;
......@@ -11913,99 +11936,99 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
1191311936 try self.asmRegisterImmediate(
1191411937 .{ ._, .cmp },
1191511938 index_reg.to32(),
11916 Immediate.u(arg_ty.vectorLen(mod)),
11939 Immediate.u(arg_ty.vectorLen(zcu)),
1191711940 );
1191811941 _ = try self.asmJccReloc(.b, loop);
1191911942
11920 break :dst dst_mcv;
11943 break :result dst_mcv;
1192111944 },
1192211945 else => return self.fail("TODO implement arg for {}", .{src_mcv}),
11923 };
11924
11925 const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
11926 switch (name_nts) {
11927 .none => {},
11928 _ => try self.genArgDbgInfo(arg_ty, self.air.nullTerminatedString(@intFromEnum(name_nts)), src_mcv),
1192911946 }
11930
11931 break :result dst_mcv;
1193211947 };
1193311948 return self.finishAir(inst, result, .{ .none, .none, .none });
1193411949}
1193511950
11936fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
11937 switch (self.debug_output) {
11938 .dwarf => |dw| {
11939 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (mcv) {
11940 .register => |reg| .{ .register = reg.dwarfNum() },
11941 .register_pair => |regs| .{ .register_pair = .{
11942 regs[0].dwarfNum(), regs[1].dwarfNum(),
11943 } },
11944 // TODO use a frame index
11945 .load_frame, .elementwise_regs_then_frame => return,
11946 //.stack_offset => |off| .{
11947 // .stack = .{
11948 // // TODO handle -fomit-frame-pointer
11949 // .fp_register = Register.rbp.dwarfNum(),
11950 // .offset = -off,
11951 // },
11952 //},
11953 else => unreachable, // not a valid function parameter
11954 };
11955 // TODO: this might need adjusting like the linkers do.
11956 // Instead of flattening the owner and passing Decl.Index here we may
11957 // want to special case LazySymbol in DWARF linker too.
11958 try dw.genArgDbgInfo(name, ty, self.owner.nav_index, loc);
11959 },
11960 .plan9 => {},
11961 .none => {},
11951fn airDbgArg(self: *Self, inst: Air.Inst.Index) !void {
11952 defer self.finishAirBookkeeping();
11953 if (self.debug_output == .none) return;
11954 const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
11955 const name = self.air.nullTerminatedString(@intFromEnum(name_nts));
11956 if (name.len > 0) {
11957 const arg_ty = self.typeOfIndex(inst);
11958 const arg_mcv = self.getResolvedInstValue(inst).short;
11959 try self.genVarDebugInfo(.local_arg, .dbg_var_val, name, arg_ty, arg_mcv);
1196211960 }
11961 if (self.liveness.isUnused(inst)) try self.processDeath(inst);
1196311962}
1196411963
11965fn genVarDbgInfo(
11966 self: Self,
11964fn genVarDebugInfo(
11965 self: *Self,
11966 var_tag: link.File.Dwarf.WipNav.VarTag,
1196711967 tag: Air.Inst.Tag,
11968 name: []const u8,
1196811969 ty: Type,
1196911970 mcv: MCValue,
11970 name: [:0]const u8,
1197111971) !void {
11972 const is_ptr = switch (tag) {
11973 .dbg_var_ptr => true,
11974 .dbg_var_val => false,
11975 else => unreachable,
11972 const stack_vars = switch (var_tag) {
11973 .local_arg => &self.stack_args,
11974 .local_var => &self.stack_vars,
1197611975 };
11977
1197811976 switch (self.debug_output) {
11979 .dwarf => |dw| {
11980 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (mcv) {
11981 .register => |reg| .{ .register = reg.dwarfNum() },
11982 // TODO use a frame index
11983 .load_frame, .lea_frame => return,
11984 //=> |off| .{ .stack = .{
11985 // .fp_register = Register.rbp.dwarfNum(),
11986 // .offset = -off,
11987 //} },
11988 .memory => |address| .{ .memory = address },
11989 .load_symbol => |sym_off| loc: {
11990 assert(sym_off.off == 0);
11991 break :loc .{ .linker_load = .{ .type = .direct, .sym_index = sym_off.sym } };
11992 }, // TODO
11993 .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },
11994 .load_direct => |sym_index| .{
11995 .linker_load = .{ .type = .direct, .sym_index = sym_index },
11996 },
11997 .immediate => |x| .{ .immediate = x },
11998 .undef => .undef,
11999 .none => .none,
12000 else => blk: {
12001 log.debug("TODO generate debug info for {}", .{mcv});
12002 break :blk .nop;
11977 .dwarf => |dwarf| switch (tag) {
11978 else => unreachable,
11979 .dbg_var_ptr => {
11980 const var_ty = ty.childType(self.pt.zcu);
11981 switch (mcv) {
11982 else => {
11983 log.info("dbg_var_ptr({s}({}))", .{ @tagName(mcv), mcv });
11984 unreachable;
11985 },
11986 .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
11987 .lea_frame => |frame_addr| try stack_vars.append(self.gpa, .{
11988 .name = name,
11989 .type = var_ty,
11990 .frame_addr = frame_addr,
11991 }),
11992 .lea_symbol => |sym_off| try dwarf.genVarDebugInfo(var_tag, name, var_ty, .{ .plus = .{
11993 &.{ .addr = .{ .sym = sym_off.sym } },
11994 &.{ .consts = sym_off.off },
11995 } }),
11996 }
11997 },
11998 .dbg_var_val => switch (mcv) {
11999 .none => try dwarf.genVarDebugInfo(var_tag, name, ty, .empty),
12000 .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
12001 .immediate => |immediate| try dwarf.genVarDebugInfo(var_tag, name, ty, .{ .stack_value = &.{
12002 .constu = immediate,
12003 } }),
12004 else => {
12005 const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(ty, self.pt));
12006 try self.genSetMem(.{ .frame = frame_index }, 0, ty, mcv, .{});
12007 try stack_vars.append(self.gpa, .{
12008 .name = name,
12009 .type = ty,
12010 .frame_addr = .{ .index = frame_index },
12011 });
1200312012 },
12004 };
12005 // TODO: this might need adjusting like the linkers do.
12006 // Instead of flattening the owner and passing Decl.Index here we may
12007 // want to special case LazySymbol in DWARF linker too.
12008 try dw.genVarDbgInfo(name, ty, self.owner.nav_index, is_ptr, loc);
12013 },
12014 },
12015 .plan9 => {},
12016 .none => {},
12017 }
12018}
12019
12020fn genStackVarDebugInfo(
12021 self: Self,
12022 var_tag: link.File.Dwarf.WipNav.VarTag,
12023 stack_vars: []const StackVar,
12024) !void {
12025 switch (self.debug_output) {
12026 .dwarf => |dwarf| for (stack_vars) |stack_var| {
12027 const frame_loc = self.frame_locs.get(@intFromEnum(stack_var.frame_addr.index));
12028 try dwarf.genVarDebugInfo(var_tag, stack_var.name, stack_var.type, .{ .plus = .{
12029 &.{ .breg = frame_loc.base.dwarfNum() },
12030 &.{ .consts = @as(i33, frame_loc.disp) + stack_var.frame_addr.off },
12031 } });
1200912032 },
1201012033 .plan9 => {},
1201112034 .none => {},
......@@ -13045,7 +13068,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
1304513068 const name = self.air.nullTerminatedString(pl_op.payload);
1304613069
1304713070 const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
13048 try self.genVarDbgInfo(tag, ty, mcv, name);
13071 try self.genVarDebugInfo(.local_var, tag, name, ty, mcv);
1304913072
1305013073 return self.finishAir(inst, .unreach, .{ operand, .none, .none });
1305113074}
......@@ -13154,13 +13177,17 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
1315413177 .lea_direct,
1315513178 .lea_got,
1315613179 .lea_tlv,
13157 .lea_frame,
1315813180 .lea_symbol,
1315913181 .elementwise_regs_then_frame,
1316013182 .reserved_frame,
1316113183 .air_ref,
1316213184 => unreachable,
1316313185
13186 .lea_frame => {
13187 self.eflags_inst = null;
13188 return .{ .immediate = @intFromBool(false) };
13189 },
13190
1316413191 .register => |opt_reg| {
1316513192 if (some_info.off == 0) {
1316613193 const some_abi_size: u32 = @intCast(some_info.ty.abiSize(pt));
......@@ -13402,7 +13429,8 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
1340213429 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
1340313430 const operand = try self.resolveInst(un_op);
1340413431 const ty = self.typeOf(un_op);
13405 const result = switch (try self.isNull(inst, ty, operand)) {
13432 const result: MCValue = switch (try self.isNull(inst, ty, operand)) {
13433 .immediate => |imm| .{ .immediate = @intFromBool(imm == 0) },
1340613434 .eflags => |cc| .{ .eflags = cc.negate() },
1340713435 else => unreachable,
1340813436 };
......@@ -15156,7 +15184,7 @@ fn genSetMem(
1515615184 })).write(
1515715185 self,
1515815186 .{ .base = base, .mod = .{ .rm = .{
15159 .size = self.memSize(ty),
15187 .size = Memory.Size.fromBitSize(@min(self.memSize(ty).bitSize(), src_alias.bitSize())),
1516015188 .disp = disp,
1516115189 } } },
1516215190 src_alias,
......@@ -15202,7 +15230,33 @@ fn genSetMem(
1520215230 @tagName(src_mcv), ty.fmt(pt),
1520315231 }),
1520415232 },
15205 .register_offset,
15233 .register_offset => |reg_off| {
15234 const src_reg = self.copyToTmpRegister(ty, src_mcv) catch |err| switch (err) {
15235 error.OutOfRegisters => {
15236 const src_reg = registerAlias(reg_off.reg, abi_size);
15237 try self.asmRegisterMemory(.{ ._, .lea }, src_reg, .{
15238 .base = .{ .reg = src_reg },
15239 .mod = .{ .rm = .{
15240 .size = .qword,
15241 .disp = reg_off.off,
15242 } },
15243 });
15244 try self.genSetMem(base, disp, ty, .{ .register = reg_off.reg }, opts);
15245 return self.asmRegisterMemory(.{ ._, .lea }, src_reg, .{
15246 .base = .{ .reg = src_reg },
15247 .mod = .{ .rm = .{
15248 .size = .qword,
15249 .disp = -reg_off.off,
15250 } },
15251 });
15252 },
15253 else => |e| return e,
15254 };
15255 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
15256 defer self.register_manager.unlockReg(src_lock);
15257
15258 try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts);
15259 },
1520615260 .memory,
1520715261 .indirect,
1520815262 .load_direct,
......@@ -15422,9 +15476,14 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
1542215476 const src_ty = self.typeOf(ty_op.operand);
1542315477
1542415478 const result = result: {
15479 const src_mcv = try self.resolveInst(ty_op.operand);
15480 if (dst_ty.isPtrAtRuntime(mod) and src_ty.isPtrAtRuntime(mod)) switch (src_mcv) {
15481 .lea_frame => break :result src_mcv,
15482 else => if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv,
15483 };
15484
1542515485 const dst_rc = self.regClassForType(dst_ty);
1542615486 const src_rc = self.regClassForType(src_ty);
15427 const src_mcv = try self.resolveInst(ty_op.operand);
1542815487
1542915488 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
1543015489 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -18236,10 +18295,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
1823618295 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
1823718296 const tag_int_val = try tag_val.intFromEnum(tag_ty, pt);
1823818297 const tag_int = tag_int_val.toUnsignedInt(pt);
18239 const tag_off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))
18240 @intCast(layout.payload_size)
18241 else
18242 0;
18298 const tag_off: i32 = @intCast(layout.tagOffset());
1824318299 try self.genCopy(
1824418300 tag_ty,
1824518301 dst_mcv.address().offset(tag_off).deref(),
......@@ -18247,10 +18303,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
1824718303 .{},
1824818304 );
1824918305
18250 const pl_off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))
18251 0
18252 else
18253 @intCast(layout.tag_size);
18306 const pl_off: i32 = @intCast(layout.payloadOffset());
1825418307 try self.genCopy(src_ty, dst_mcv.address().offset(pl_off).deref(), src_mcv, .{});
1825518308
1825618309 break :result dst_mcv;
......@@ -18790,6 +18843,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
1879018843 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
1879118844 .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } },
1879218845 .load_direct => |sym_index| .{ .load_direct = sym_index },
18846 .lea_direct => |sym_index| .{ .lea_direct = sym_index },
1879318847 .load_got => |sym_index| .{ .lea_got = sym_index },
1879418848 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
1879518849 },
src/arch/x86_64/Emit.zig+2-8
......@@ -14,7 +14,7 @@ relocs: std.ArrayListUnmanaged(Reloc) = .{},
1414
1515pub const Error = Lower.Error || error{
1616 EmitFail,
17};
17} || link.File.UpdateDebugInfoError;
1818
1919pub fn emitMir(emit: *Emit) Error!void {
2020 for (0..emit.lower.mir.instructions.len) |mir_i| {
......@@ -222,13 +222,7 @@ pub fn emitMir(emit: *Emit) Error!void {
222222 else => unreachable,
223223 .pseudo_dbg_prologue_end_none => {
224224 switch (emit.debug_output) {
225 .dwarf => |dw| {
226 try dw.setPrologueEnd();
227 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
228 emit.prev_di_line, emit.prev_di_column,
229 });
230 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
231 },
225 .dwarf => |dw| try dw.setPrologueEnd(),
232226 .plan9 => {},
233227 .none => {},
234228 }
src/arch/x86_64/Mir.zig+1-1
......@@ -1204,7 +1204,7 @@ pub const FrameLoc = struct {
12041204pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
12051205 return switch (mem.info.base) {
12061206 .none, .reg, .reloc => mem,
1207 .frame => if (mir.frame_locs.len > 0) Memory{
1207 .frame => if (mir.frame_locs.len > 0) .{
12081208 .info = .{
12091209 .base = .reg,
12101210 .mod = mem.info.mod,
src/arch/x86_64/bits.zig-1
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44
55const Allocator = std.mem.Allocator;
66const ArrayList = std.ArrayList;
7const DW = std.dwarf;
87
98/// EFLAGS condition codes
109pub const Condition = enum(u5) {
src/codegen.zig+47-38
......@@ -36,10 +36,10 @@ pub const CodeGenError = error{
3636 OutOfMemory,
3737 Overflow,
3838 CodegenFail,
39};
39} || link.File.UpdateDebugInfoError;
4040
4141pub const DebugInfoOutput = union(enum) {
42 dwarf: *link.File.Dwarf.NavState,
42 dwarf: *link.File.Dwarf.WipNav,
4343 plan9: *link.File.Plan9.DebugInfoOutput,
4444 none,
4545};
......@@ -819,6 +819,9 @@ pub const GenResult = union(enum) {
819819 /// Decl with address deferred until the linker allocates everything in virtual memory.
820820 /// Payload is a symbol index.
821821 load_direct: u32,
822 /// Decl with address deferred until the linker allocates everything in virtual memory.
823 /// Payload is a symbol index.
824 lea_direct: u32,
822825 /// Decl referenced via GOT with address deferred until the linker allocates
823826 /// everything in virtual memory.
824827 /// Payload is a symbol index.
......@@ -833,10 +836,6 @@ pub const GenResult = union(enum) {
833836 lea_symbol: u32,
834837 };
835838
836 fn mcv(val: MCValue) GenResult {
837 return .{ .mcv = val };
838 }
839
840839 fn fail(
841840 gpa: Allocator,
842841 src_loc: Zcu.LazySrcLoc,
......@@ -869,7 +868,7 @@ fn genNavRef(
869868 8 => 0xaaaaaaaaaaaaaaaa,
870869 else => unreachable,
871870 };
872 return GenResult.mcv(.{ .immediate = imm });
871 return .{ .mcv = .{ .immediate = imm } };
873872 }
874873
875874 const comp = lf.comp;
......@@ -878,12 +877,12 @@ fn genNavRef(
878877 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
879878 if (ty.castPtrToFn(zcu)) |fn_ty| {
880879 if (zcu.typeToFunc(fn_ty).?.is_generic) {
881 return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(pt).toByteUnits().? });
880 return .{ .mcv = .{ .immediate = fn_ty.abiAlignment(pt).toByteUnits().? } };
882881 }
883882 } else if (ty.zigTypeTag(zcu) == .Pointer) {
884883 const elem_ty = ty.elemType2(zcu);
885884 if (!elem_ty.hasRuntimeBits(pt)) {
886 return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(pt).toByteUnits().? });
885 return .{ .mcv = .{ .immediate = elem_ty.abiAlignment(pt).toByteUnits().? } };
887886 }
888887 }
889888
......@@ -900,40 +899,40 @@ fn genNavRef(
900899 if (is_extern) {
901900 const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
902901 zo.symbol(sym_index).flags.is_extern_ptr = true;
903 return GenResult.mcv(.{ .lea_symbol = sym_index });
902 return .{ .mcv = .{ .lea_symbol = sym_index } };
904903 }
905904 const sym_index = try zo.getOrCreateMetadataForNav(elf_file, nav_index);
906905 if (!single_threaded and is_threadlocal) {
907 return GenResult.mcv(.{ .load_tlv = sym_index });
906 return .{ .mcv = .{ .load_tlv = sym_index } };
908907 }
909 return GenResult.mcv(.{ .lea_symbol = sym_index });
908 return .{ .mcv = .{ .lea_symbol = sym_index } };
910909 } else if (lf.cast(.macho)) |macho_file| {
911910 const zo = macho_file.getZigObject().?;
912911 if (is_extern) {
913912 const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
914913 zo.symbols.items[sym_index].setSectionFlags(.{ .needs_got = true });
915 return GenResult.mcv(.{ .load_symbol = sym_index });
914 return .{ .mcv = .{ .load_symbol = sym_index } };
916915 }
917916 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
918917 const sym = zo.symbols.items[sym_index];
919918 if (!single_threaded and is_threadlocal) {
920 return GenResult.mcv(.{ .load_tlv = sym.nlist_idx });
919 return .{ .mcv = .{ .load_tlv = sym.nlist_idx } };
921920 }
922 return GenResult.mcv(.{ .load_symbol = sym.nlist_idx });
921 return .{ .mcv = .{ .load_symbol = sym.nlist_idx } };
923922 } else if (lf.cast(.coff)) |coff_file| {
924923 if (is_extern) {
925924 // TODO audit this
926925 const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
927926 try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT
928 return GenResult.mcv(.{ .load_got = link.File.Coff.global_symbol_bit | global_index });
927 return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_index } };
929928 }
930929 const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);
931930 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
932 return GenResult.mcv(.{ .load_got = sym_index });
931 return .{ .mcv = .{ .load_got = sym_index } };
933932 } else if (lf.cast(.plan9)) |p9| {
934933 const atom_index = try p9.seeNav(pt, nav_index);
935934 const atom = p9.getAtom(atom_index);
936 return GenResult.mcv(.{ .memory = atom.getOffsetTableAddress(p9) });
935 return .{ .mcv = .{ .memory = atom.getOffsetTableAddress(p9) } };
937936 } else {
938937 return GenResult.fail(gpa, src_loc, "TODO genNavRef for target {}", .{target});
939938 }
......@@ -952,30 +951,40 @@ pub fn genTypedValue(
952951
953952 log.debug("genTypedValue: val = {}", .{val.fmtValue(pt)});
954953
955 if (val.isUndef(zcu)) {
956 return GenResult.mcv(.undef);
957 }
958
959 if (!ty.isSlice(zcu)) switch (ip.indexToKey(val.toIntern())) {
960 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
961 .nav => |nav| return genNavRef(lf, pt, src_loc, val, nav, target),
962 else => {},
963 },
964 else => {},
965 };
954 if (val.isUndef(zcu)) return .{ .mcv = .undef };
966955
967956 switch (ty.zigTypeTag(zcu)) {
968 .Void => return GenResult.mcv(.none),
957 .Void => return .{ .mcv = .none },
969958 .Pointer => switch (ty.ptrSize(zcu)) {
970959 .Slice => {},
971960 else => switch (val.toIntern()) {
972961 .null_value => {
973 return GenResult.mcv(.{ .immediate = 0 });
962 return .{ .mcv = .{ .immediate = 0 } };
974963 },
975 .none => {},
976964 else => switch (ip.indexToKey(val.toIntern())) {
977965 .int => {
978 return GenResult.mcv(.{ .immediate = val.toUnsignedInt(pt) });
966 return .{ .mcv = .{ .immediate = val.toUnsignedInt(pt) } };
967 },
968 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
969 .nav => |nav| return genNavRef(lf, pt, src_loc, val, nav, target),
970 .uav => |uav| if (Value.fromInterned(uav.val).typeOf(zcu).hasRuntimeBits(pt))
971 return switch (try lf.lowerUav(
972 pt,
973 uav.val,
974 Type.fromInterned(uav.orig_ty).ptrAlignment(pt),
975 src_loc,
976 )) {
977 .mcv => |mcv| return .{ .mcv = switch (mcv) {
978 .load_direct => |sym_index| .{ .lea_direct = sym_index },
979 .load_symbol => |sym_index| .{ .lea_symbol = sym_index },
980 else => unreachable,
981 } },
982 .fail => |em| return .{ .fail = em },
983 }
984 else
985 return .{ .mcv = .{ .immediate = Type.fromInterned(uav.orig_ty).ptrAlignment(pt)
986 .forward(@intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() | 1)) / 3)) } },
987 else => {},
979988 },
980989 else => {},
981990 },
......@@ -988,11 +997,11 @@ pub fn genTypedValue(
988997 .signed => @bitCast(val.toSignedInt(pt)),
989998 .unsigned => val.toUnsignedInt(pt),
990999 };
991 return GenResult.mcv(.{ .immediate = unsigned });
1000 return .{ .mcv = .{ .immediate = unsigned } };
9921001 }
9931002 },
9941003 .Bool => {
995 return GenResult.mcv(.{ .immediate = @intFromBool(val.toBool()) });
1004 return .{ .mcv = .{ .immediate = @intFromBool(val.toBool()) } };
9961005 },
9971006 .Optional => {
9981007 if (ty.isPtrLikeOptional(zcu)) {
......@@ -1000,11 +1009,11 @@ pub fn genTypedValue(
10001009 lf,
10011010 pt,
10021011 src_loc,
1003 val.optionalValue(zcu) orelse return GenResult.mcv(.{ .immediate = 0 }),
1012 val.optionalValue(zcu) orelse return .{ .mcv = .{ .immediate = 0 } },
10041013 target,
10051014 );
10061015 } else if (ty.abiSize(pt) == 1) {
1007 return GenResult.mcv(.{ .immediate = @intFromBool(!val.isNull(zcu)) });
1016 return .{ .mcv = .{ .immediate = @intFromBool(!val.isNull(zcu)) } };
10081017 }
10091018 },
10101019 .Enum => {
......@@ -1020,7 +1029,7 @@ pub fn genTypedValue(
10201029 .ErrorSet => {
10211030 const err_name = ip.indexToKey(val.toIntern()).err.name;
10221031 const error_index = try pt.getErrorValue(err_name);
1023 return GenResult.mcv(.{ .immediate = error_index });
1032 return .{ .mcv = .{ .immediate = error_index } };
10241033 },
10251034 .ErrorUnion => {
10261035 const err_type = ty.errorUnionSet(zcu);
src/link.zig+15-1
......@@ -329,6 +329,9 @@ pub const File = struct {
329329 }
330330 }
331331
332 pub const UpdateDebugInfoError = Dwarf.UpdateError;
333 pub const FlushDebugInfoError = Dwarf.FlushError;
334
332335 pub const UpdateNavError = error{
333336 OutOfMemory,
334337 Overflow,
......@@ -365,7 +368,7 @@ pub const File = struct {
365368 DeviceBusy,
366369 InvalidArgument,
367370 HotSwapUnavailableOnHostOperatingSystem,
368 };
371 } || UpdateDebugInfoError;
369372
370373 /// Called from within CodeGen to retrieve the symbol index of a global symbol.
371374 /// If no symbol exists yet with this name, a new undefined global symbol will
......@@ -398,6 +401,16 @@ pub const File = struct {
398401 }
399402 }
400403
404 pub fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateNavError!void {
405 switch (base.tag) {
406 else => {},
407 inline .elf => |tag| {
408 dev.check(tag.devFeature());
409 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateContainerType(pt, ty);
410 },
411 }
412 }
413
401414 /// May be called before or after updateExports for any given Decl.
402415 pub fn updateFunc(
403416 base: *File,
......@@ -570,6 +583,7 @@ pub const File = struct {
570583 Unseekable,
571584 UnsupportedCpuArchitecture,
572585 UnsupportedVersion,
586 UnexpectedEndOfFile,
573587 } ||
574588 fs.File.WriteFileError ||
575589 fs.File.OpenError ||
src/link/Coff.zig+32-29
......@@ -1205,10 +1205,11 @@ pub fn updateNav(
12051205 const ip = &zcu.intern_pool;
12061206 const nav = ip.getNav(nav_index);
12071207
1208 const init_val = switch (ip.indexToKey(nav.status.resolved.val)) {
1209 .variable => |variable| variable.init,
1208 const nav_val = zcu.navValue(nav_index);
1209 const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
1210 .variable => |variable| Value.fromInterned(variable.init),
12101211 .@"extern" => |@"extern"| {
1211 if (ip.isFunctionType(nav.typeOf(ip))) return;
1212 if (ip.isFunctionType(@"extern".ty)) return;
12121213 // TODO make this part of getGlobalSymbol
12131214 const name = nav.name.toSlice(ip);
12141215 const lib_name = @"extern".lib_name.toSlice(ip);
......@@ -1216,34 +1217,36 @@ pub fn updateNav(
12161217 try self.need_got_table.put(gpa, global_index, {});
12171218 return;
12181219 },
1219 else => nav.status.resolved.val,
1220 else => nav_val,
12201221 };
12211222
1222 const atom_index = try self.getOrCreateAtomForNav(nav_index);
1223 Atom.freeRelocations(self, atom_index);
1224 const atom = self.getAtom(atom_index);
1223 if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
1224 const atom_index = try self.getOrCreateAtomForNav(nav_index);
1225 Atom.freeRelocations(self, atom_index);
1226 const atom = self.getAtom(atom_index);
12251227
1226 var code_buffer = std.ArrayList(u8).init(gpa);
1227 defer code_buffer.deinit();
1228 var code_buffer = std.ArrayList(u8).init(gpa);
1229 defer code_buffer.deinit();
12281230
1229 const res = try codegen.generateSymbol(
1230 &self.base,
1231 pt,
1232 zcu.navSrcLoc(nav_index),
1233 Value.fromInterned(init_val),
1234 &code_buffer,
1235 .none,
1236 .{ .parent_atom_index = atom.getSymbolIndex().? },
1237 );
1238 const code = switch (res) {
1239 .ok => code_buffer.items,
1240 .fail => |em| {
1241 try zcu.failed_codegen.put(gpa, nav_index, em);
1242 return;
1243 },
1244 };
1231 const res = try codegen.generateSymbol(
1232 &self.base,
1233 pt,
1234 zcu.navSrcLoc(nav_index),
1235 nav_init,
1236 &code_buffer,
1237 .none,
1238 .{ .parent_atom_index = atom.getSymbolIndex().? },
1239 );
1240 const code = switch (res) {
1241 .ok => code_buffer.items,
1242 .fail => |em| {
1243 try zcu.failed_codegen.put(gpa, nav_index, em);
1244 return;
1245 },
1246 };
12451247
1246 try self.updateNavCode(pt, nav_index, code, .NULL);
1248 try self.updateNavCode(pt, nav_index, code, .NULL);
1249 }
12471250
12481251 // Exports will be updated by `Zcu.processExports` after the update.
12491252}
......@@ -1290,10 +1293,10 @@ fn updateLazySymbolAtom(
12901293 },
12911294 };
12921295
1293 const code_len = @as(u32, @intCast(code.len));
1296 const code_len: u32 = @intCast(code.len);
12941297 const symbol = atom.getSymbolPtr(self);
12951298 try self.setSymbolName(symbol, name);
1296 symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1));
1299 symbol.section_number = @enumFromInt(section_index + 1);
12971300 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };
12981301
12991302 const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
......@@ -1691,7 +1694,7 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
16911694 .tid = tid,
16921695 };
16931696
1694 if (self.lazy_syms.getPtr(.none)) |metadata| {
1697 if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {
16951698 // Most lazy symbols can be updated on first use, but
16961699 // anyerror needs to wait for everything to be flushed.
16971700 if (metadata.text_state != .unused) self.updateLazySymbolAtom(
src/link/Dwarf.zig+3594-2658
......@@ -1,2884 +1,3820 @@
1allocator: Allocator,
2bin_file: *File,
3format: Format,
4ptr_width: PtrWidth,
5
6/// A list of `Atom`s whose Line Number Programs have surplus capacity.
7/// This is the same concept as `Section.free_list` in Elf; see those doc comments.
8src_fn_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{},
9src_fn_first_index: ?Atom.Index = null,
10src_fn_last_index: ?Atom.Index = null,
11src_fns: std.ArrayListUnmanaged(Atom) = .{},
12src_fn_navs: AtomTable = .{},
13
14/// A list of `Atom`s whose corresponding .debug_info tags have surplus capacity.
15/// This is the same concept as `text_block_free_list`; see those doc comments.
16di_atom_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{},
17di_atom_first_index: ?Atom.Index = null,
18di_atom_last_index: ?Atom.Index = null,
19di_atoms: std.ArrayListUnmanaged(Atom) = .{},
20di_atom_navs: AtomTable = .{},
21
22dbg_line_header: DbgLineHeader,
23
24abbrev_table_offset: ?u64 = null,
25
26/// TODO replace with InternPool
27/// Table of debug symbol names.
28strtab: StringTable = .{},
29
30/// Quick lookup array of all defined source files referenced by at least one Nav.
31/// They will end up in the DWARF debug_line header as two lists:
32/// * []include_directory
33/// * []file_names
34di_files: std.AutoArrayHashMapUnmanaged(*const Zcu.File, void) = .{},
35
36global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
37
38const AtomTable = std.AutoHashMapUnmanaged(InternPool.Nav.Index, Atom.Index);
39
40const Atom = struct {
41 /// Offset into .debug_info pointing to the tag for this Nav, or
42 /// offset from the beginning of the Debug Line Program header that contains this function.
43 off: u32,
44 /// Size of the .debug_info tag for this Nav, not including padding, or
45 /// size of the line number program component belonging to this function, not
46 /// including padding.
47 len: u32,
1gpa: std.mem.Allocator,
2bin_file: *link.File,
3format: DW.Format,
4endian: std.builtin.Endian,
5address_size: AddressSize,
6
7mods: std.AutoArrayHashMapUnmanaged(*Module, ModInfo),
8types: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index),
9navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index),
10
11debug_abbrev: DebugAbbrev,
12debug_aranges: DebugAranges,
13debug_info: DebugInfo,
14debug_line: DebugLine,
15debug_line_str: StringSection,
16debug_loclists: DebugLocLists,
17debug_rnglists: DebugRngLists,
18debug_str: StringSection,
19
20pub const UpdateError =
21 std.fs.File.OpenError ||
22 std.fs.File.SetEndPosError ||
23 std.fs.File.CopyRangeError ||
24 std.fs.File.PWriteError ||
25 error{ Overflow, Underflow, UnexpectedEndOfFile };
26
27pub const FlushError =
28 UpdateError ||
29 std.process.GetCwdError;
30
31pub const RelocError =
32 std.fs.File.PWriteError;
33
34pub const AddressSize = enum(u8) {
35 @"32" = 4,
36 @"64" = 8,
37 _,
38};
39
40const ModInfo = struct {
41 root_dir_path: Entry.Index,
42 dirs: std.AutoArrayHashMapUnmanaged(Unit.Index, void),
43 files: Files,
4844
49 prev_index: ?Index,
50 next_index: ?Index,
45 const Files = std.AutoArrayHashMapUnmanaged(Zcu.File.Index, void);
5146
52 pub const Index = u32;
47 fn deinit(mod_info: *ModInfo, gpa: std.mem.Allocator) void {
48 mod_info.dirs.deinit(gpa);
49 mod_info.files.deinit(gpa);
50 mod_info.* = undefined;
51 }
5352};
5453
55const DbgLineHeader = struct {
56 minimum_instruction_length: u8,
57 maximum_operations_per_instruction: u8,
58 default_is_stmt: bool,
59 line_base: i8,
60 line_range: u8,
61 opcode_base: u8,
54const DebugAbbrev = struct {
55 section: Section,
56 const unit: Unit.Index = @enumFromInt(0);
57 const entry: Entry.Index = @enumFromInt(0);
6258};
6359
64/// Represents state of the analysed Nav.
65/// Includes Nav's abbrev table of type Types, matching arena
66/// and a set of relocations that will be resolved once this
67/// Nav's inner Atom is assigned an offset within the DWARF section.
68pub const NavState = struct {
69 dwarf: *Dwarf,
70 pt: Zcu.PerThread,
71 di_atom_navs: *const AtomTable,
72 dbg_line_func: InternPool.Index,
73 dbg_line: std.ArrayList(u8),
74 dbg_info: std.ArrayList(u8),
75 abbrev_type_arena: std.heap.ArenaAllocator,
76 abbrev_table: std.ArrayListUnmanaged(AbbrevEntry),
77 abbrev_resolver: std.AutoHashMapUnmanaged(InternPool.Index, u32),
78 abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation),
79 exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation),
80
81 pub fn deinit(ns: *NavState) void {
82 const gpa = ns.dwarf.allocator;
83 ns.dbg_line.deinit();
84 ns.dbg_info.deinit();
85 ns.abbrev_type_arena.deinit();
86 ns.abbrev_table.deinit(gpa);
87 ns.abbrev_resolver.deinit(gpa);
88 ns.abbrev_relocs.deinit(gpa);
89 ns.exprloc_relocs.deinit(gpa);
90 }
91
92 /// Adds local type relocation of the form: @offset => @this + addend
93 /// @this signifies the offset within the .debug_abbrev section of the containing atom.
94 fn addTypeRelocLocal(self: *NavState, atom_index: Atom.Index, offset: u32, addend: u32) !void {
95 log.debug("{x}: @this + {x}", .{ offset, addend });
96 try self.abbrev_relocs.append(self.dwarf.allocator, .{
97 .target = null,
98 .atom_index = atom_index,
99 .offset = offset,
100 .addend = addend,
101 });
60const DebugAranges = struct {
61 section: Section,
62
63 fn headerBytes(dwarf: *Dwarf) u32 {
64 return std.mem.alignForwardAnyAlign(
65 u32,
66 dwarf.unitLengthBytes() + 2 + dwarf.sectionOffsetBytes() + 1 + 1,
67 @intFromEnum(dwarf.address_size) * 2,
68 );
10269 }
10370
104 /// Adds global type relocation of the form: @offset => @symbol + 0
105 /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section
106 /// which we use as our target of the relocation.
107 fn addTypeRelocGlobal(self: *NavState, atom_index: Atom.Index, ty: Type, offset: u32) !void {
108 const gpa = self.dwarf.allocator;
109 const resolv = self.abbrev_resolver.get(ty.toIntern()) orelse blk: {
110 const sym_index: u32 = @intCast(self.abbrev_table.items.len);
111 try self.abbrev_table.append(gpa, .{
112 .atom_index = atom_index,
113 .type = ty,
114 .offset = undefined,
115 });
116 log.debug("%{d}: {}", .{ sym_index, ty.fmt(self.pt) });
117 try self.abbrev_resolver.putNoClobber(gpa, ty.toIntern(), sym_index);
118 break :blk sym_index;
119 };
120 log.debug("{x}: %{d} + 0", .{ offset, resolv });
121 try self.abbrev_relocs.append(gpa, .{
122 .target = resolv,
123 .atom_index = atom_index,
124 .offset = offset,
125 .addend = 0,
126 });
71 fn trailerBytes(dwarf: *Dwarf) u32 {
72 return @intFromEnum(dwarf.address_size) * 2;
12773 }
74};
12875
129 fn addDbgInfoType(
130 self: *NavState,
131 pt: Zcu.PerThread,
132 atom_index: Atom.Index,
133 ty: Type,
134 ) error{OutOfMemory}!void {
135 const zcu = pt.zcu;
136 const dbg_info_buffer = &self.dbg_info;
137 const target = zcu.getTarget();
138 const target_endian = target.cpu.arch.endian();
139 const ip = &zcu.intern_pool;
76const DebugInfo = struct {
77 section: Section,
14078
141 switch (ty.zigTypeTag(zcu)) {
142 .NoReturn => unreachable,
143 .Void => {
144 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.zero_bit_type));
145 },
146 .Bool => {
147 try dbg_info_buffer.ensureUnusedCapacity(12);
148 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.base_type));
149 // DW.AT.encoding, DW.FORM.data1
150 dbg_info_buffer.appendAssumeCapacity(DW.ATE.boolean);
151 // DW.AT.byte_size, DW.FORM.udata
152 try leb128.writeUleb128(dbg_info_buffer.writer(), ty.abiSize(pt));
153 // DW.AT.name, DW.FORM.string
154 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)});
155 },
156 .Int => {
157 const info = ty.intInfo(zcu);
158 try dbg_info_buffer.ensureUnusedCapacity(12);
159 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.base_type));
160 // DW.AT.encoding, DW.FORM.data1
161 dbg_info_buffer.appendAssumeCapacity(switch (info.signedness) {
162 .signed => DW.ATE.signed,
163 .unsigned => DW.ATE.unsigned,
164 });
165 // DW.AT.byte_size, DW.FORM.udata
166 try leb128.writeUleb128(dbg_info_buffer.writer(), ty.abiSize(pt));
167 // DW.AT.name, DW.FORM.string
168 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)});
169 },
170 .Optional => {
171 if (ty.isPtrLikeOptional(zcu)) {
172 try dbg_info_buffer.ensureUnusedCapacity(12);
173 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.base_type));
174 // DW.AT.encoding, DW.FORM.data1
175 dbg_info_buffer.appendAssumeCapacity(DW.ATE.address);
176 // DW.AT.byte_size, DW.FORM.udata
177 try leb128.writeUleb128(dbg_info_buffer.writer(), ty.abiSize(pt));
178 // DW.AT.name, DW.FORM.string
179 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)});
180 } else {
181 // Non-pointer optionals are structs: struct { .maybe = *, .val = * }
182 const payload_ty = ty.optionalChild(zcu);
183 // DW.AT.structure_type
184 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_type));
185 // DW.AT.byte_size, DW.FORM.udata
186 const abi_size = ty.abiSize(pt);
187 try leb128.writeUleb128(dbg_info_buffer.writer(), abi_size);
188 // DW.AT.name, DW.FORM.string
189 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)});
190 // DW.AT.member
191 try dbg_info_buffer.ensureUnusedCapacity(21);
192 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member));
193 // DW.AT.name, DW.FORM.string
194 dbg_info_buffer.appendSliceAssumeCapacity("maybe");
195 dbg_info_buffer.appendAssumeCapacity(0);
196 // DW.AT.type, DW.FORM.ref4
197 var index = dbg_info_buffer.items.len;
198 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4);
199 try self.addTypeRelocGlobal(atom_index, Type.bool, @intCast(index));
200 // DW.AT.data_member_location, DW.FORM.udata
201 dbg_info_buffer.appendAssumeCapacity(0);
202 // DW.AT.member
203 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member));
204 // DW.AT.name, DW.FORM.string
205 dbg_info_buffer.appendSliceAssumeCapacity("val");
206 dbg_info_buffer.appendAssumeCapacity(0);
207 // DW.AT.type, DW.FORM.ref4
208 index = dbg_info_buffer.items.len;
209 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4);
210 try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(index));
211 // DW.AT.data_member_location, DW.FORM.udata
212 const offset = abi_size - payload_ty.abiSize(pt);
213 try leb128.writeUleb128(dbg_info_buffer.writer(), offset);
214 // DW.AT.structure_type delimit children
215 try dbg_info_buffer.append(0);
216 }
217 },
218 .Pointer => {
219 if (ty.isSlice(zcu)) {
220 // Slices are structs: struct { .ptr = *, .len = N }
221 const ptr_bits = target.ptrBitWidth();
222 const ptr_bytes: u8 = @intCast(@divExact(ptr_bits, 8));
223 // DW.AT.structure_type
224 try dbg_info_buffer.ensureUnusedCapacity(2);
225 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_type));
226 // DW.AT.byte_size, DW.FORM.udata
227 try leb128.writeUleb128(dbg_info_buffer.writer(), ty.abiSize(pt));
228 // DW.AT.name, DW.FORM.string
229 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)});
230 // DW.AT.member
231 try dbg_info_buffer.ensureUnusedCapacity(21);
232 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member));
233 // DW.AT.name, DW.FORM.string
234 dbg_info_buffer.appendSliceAssumeCapacity("ptr");
235 dbg_info_buffer.appendAssumeCapacity(0);
236 // DW.AT.type, DW.FORM.ref4
237 var index = dbg_info_buffer.items.len;
238 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4);
239 const ptr_ty = ty.slicePtrFieldType(zcu);
240 try self.addTypeRelocGlobal(atom_index, ptr_ty, @intCast(index));
241 // DW.AT.data_member_location, DW.FORM.udata
242 dbg_info_buffer.appendAssumeCapacity(0);
243 // DW.AT.member
244 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member));
245 // DW.AT.name, DW.FORM.string
246 dbg_info_buffer.appendSliceAssumeCapacity("len");
247 dbg_info_buffer.appendAssumeCapacity(0);
248 // DW.AT.type, DW.FORM.ref4
249 index = dbg_info_buffer.items.len;
250 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4);
251 try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(index));
252 // DW.AT.data_member_location, DW.FORM.udata
253 dbg_info_buffer.appendAssumeCapacity(ptr_bytes);
254 // DW.AT.structure_type delimit children
255 dbg_info_buffer.appendAssumeCapacity(0);
256 } else {
257 try dbg_info_buffer.ensureUnusedCapacity(9);
258 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.ptr_type));
259 // DW.AT.type, DW.FORM.ref4
260 const index = dbg_info_buffer.items.len;
261 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4);
262 try self.addTypeRelocGlobal(atom_index, ty.childType(zcu), @intCast(index));
263 }
264 },
265 .Array => {
266 // DW.AT.array_type
267 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.array_type));
268 // DW.AT.name, DW.FORM.string
269 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)});
270 // DW.AT.type, DW.FORM.ref4
271 var index = dbg_info_buffer.items.len;
272 try dbg_info_buffer.ensureUnusedCapacity(9);
273 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4);
274 try self.addTypeRelocGlobal(atom_index, ty.childType(zcu), @intCast(index));
275 // DW.AT.subrange_type
276 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.array_dim));
277 // DW.AT.type, DW.FORM.ref4
278 index = dbg_info_buffer.items.len;
279 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4);
280 try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(index));
281 // DW.AT.count, DW.FORM.udata
282 const len = ty.arrayLenIncludingSentinel(pt.zcu);
283 try leb128.writeUleb128(dbg_info_buffer.writer(), len);
284 // DW.AT.array_type delimit children
285 try dbg_info_buffer.append(0);
286 },
287 .Struct => {
288 // DW.AT.structure_type
289 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_type));
290 // DW.AT.byte_size, DW.FORM.udata
291 try leb128.writeUleb128(dbg_info_buffer.writer(), ty.abiSize(pt));
292
293 blk: {
294 switch (ip.indexToKey(ty.ip_index)) {
295 .anon_struct_type => |fields| {
296 // DW.AT.name, DW.FORM.string
297 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(pt)});
298
299 for (fields.types.get(ip), 0..) |field_ty, field_index| {
300 // DW.AT.member
301 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_member));
302 // DW.AT.name, DW.FORM.string
303 try dbg_info_buffer.writer().print("{d}\x00", .{field_index});
304 // DW.AT.type, DW.FORM.ref4
305 const index = dbg_info_buffer.items.len;
306 try dbg_info_buffer.appendNTimes(0, 4);
307 try self.addTypeRelocGlobal(atom_index, Type.fromInterned(field_ty), @intCast(index));
308 // DW.AT.data_member_location, DW.FORM.udata
309 const field_off = ty.structFieldOffset(field_index, pt);
310 try leb128.writeUleb128(dbg_info_buffer.writer(), field_off);
311 }
312 },
313 .struct_type => {
314 const struct_type = ip.loadStructType(ty.toIntern());
315 // DW.AT.name, DW.FORM.string
316 try ty.print(dbg_info_buffer.writer(), pt);
317 try dbg_info_buffer.append(0);
318
319 if (struct_type.layout == .@"packed") {
320 log.debug("TODO implement .debug_info for packed structs", .{});
321 break :blk;
322 }
79 fn headerBytes(dwarf: *Dwarf) u32 {
80 return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() +
81 uleb128Bytes(@intFromEnum(AbbrevCode.compile_unit)) + 1 + dwarf.sectionOffsetBytes() * 6 + uleb128Bytes(0) +
82 uleb128Bytes(@intFromEnum(AbbrevCode.module)) + dwarf.sectionOffsetBytes() + uleb128Bytes(0);
83 }
32384
324 if (struct_type.isTuple(ip)) {
325 for (struct_type.field_types.get(ip), struct_type.offsets.get(ip), 0..) |field_ty, field_off, field_index| {
326 if (!Type.fromInterned(field_ty).hasRuntimeBits(pt)) continue;
327 // DW.AT.member
328 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_member));
329 // DW.AT.name, DW.FORM.string
330 try dbg_info_buffer.writer().print("{d}\x00", .{field_index});
331 // DW.AT.type, DW.FORM.ref4
332 const index = dbg_info_buffer.items.len;
333 try dbg_info_buffer.appendNTimes(0, 4);
334 try self.addTypeRelocGlobal(atom_index, Type.fromInterned(field_ty), @intCast(index));
335 // DW.AT.data_member_location, DW.FORM.udata
336 try leb128.writeUleb128(dbg_info_buffer.writer(), field_off);
337 }
338 } else {
339 for (
340 struct_type.field_names.get(ip),
341 struct_type.field_types.get(ip),
342 struct_type.offsets.get(ip),
343 ) |field_name, field_ty, field_off| {
344 if (!Type.fromInterned(field_ty).hasRuntimeBits(pt)) continue;
345 const field_name_slice = field_name.toSlice(ip);
346 // DW.AT.member
347 try dbg_info_buffer.ensureUnusedCapacity(field_name_slice.len + 2);
348 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member));
349 // DW.AT.name, DW.FORM.string
350 dbg_info_buffer.appendSliceAssumeCapacity(field_name_slice[0 .. field_name_slice.len + 1]);
351 // DW.AT.type, DW.FORM.ref4
352 const index = dbg_info_buffer.items.len;
353 try dbg_info_buffer.appendNTimes(0, 4);
354 try self.addTypeRelocGlobal(atom_index, Type.fromInterned(field_ty), @intCast(index));
355 // DW.AT.data_member_location, DW.FORM.udata
356 try leb128.writeUleb128(dbg_info_buffer.writer(), field_off);
357 }
358 }
359 },
360 else => unreachable,
361 }
362 }
85 fn declEntryLineOff(dwarf: *Dwarf) u32 {
86 return AbbrevCode.decl_bytes + dwarf.sectionOffsetBytes();
87 }
36388
364 // DW.AT.structure_type delimit children
365 try dbg_info_buffer.append(0);
366 },
367 .Enum => {
368 // DW.AT.enumeration_type
369 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.enum_type));
370 // DW.AT.byte_size, DW.FORM.udata
371 try leb128.writeUleb128(dbg_info_buffer.writer(), ty.abiSize(pt));
372 // DW.AT.name, DW.FORM.string
373 try ty.print(dbg_info_buffer.writer(), pt);
374 try dbg_info_buffer.append(0);
375
376 const enum_type = ip.loadEnumType(ty.ip_index);
377 for (enum_type.names.get(ip), 0..) |field_name, field_i| {
378 const field_name_slice = field_name.toSlice(ip);
379 // DW.AT.enumerator
380 try dbg_info_buffer.ensureUnusedCapacity(field_name_slice.len + 2 + @sizeOf(u64));
381 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.enum_variant));
382 // DW.AT.name, DW.FORM.string
383 dbg_info_buffer.appendSliceAssumeCapacity(field_name_slice[0 .. field_name_slice.len + 1]);
384 // DW.AT.const_value, DW.FORM.data8
385 const value: u64 = value: {
386 if (enum_type.values.len == 0) break :value field_i; // auto-numbered
387 const value = enum_type.values.get(ip)[field_i];
388 // TODO do not assume a 64bit enum value - could be bigger.
389 // See https://github.com/ziglang/zig/issues/645
390 const field_int_val = try Value.fromInterned(value).intFromEnum(ty, pt);
391 break :value @bitCast(field_int_val.toSignedInt(pt));
392 };
393 mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian);
394 }
89 const trailer_bytes = 1 + 1;
90};
39591
396 // DW.AT.enumeration_type delimit children
397 try dbg_info_buffer.append(0);
398 },
399 .Union => {
400 const union_obj = zcu.typeToUnion(ty).?;
401 const layout = pt.getUnionLayout(union_obj);
402 const payload_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) layout.tag_size else 0;
403 const tag_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) 0 else layout.payload_size;
404 // TODO this is temporary to match current state of unions in Zig - we don't yet have
405 // safety checks implemented meaning the implicit tag is not yet stored and generated
406 // for untagged unions.
407 const is_tagged = layout.tag_size > 0;
408 if (is_tagged) {
409 // DW.AT.structure_type
410 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_type));
411 // DW.AT.byte_size, DW.FORM.udata
412 try leb128.writeUleb128(dbg_info_buffer.writer(), layout.abi_size);
413 // DW.AT.name, DW.FORM.string
414 try ty.print(dbg_info_buffer.writer(), pt);
415 try dbg_info_buffer.append(0);
416
417 // DW.AT.member
418 try dbg_info_buffer.ensureUnusedCapacity(13);
419 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member));
420 // DW.AT.name, DW.FORM.string
421 dbg_info_buffer.appendSliceAssumeCapacity("payload");
422 dbg_info_buffer.appendAssumeCapacity(0);
423 // DW.AT.type, DW.FORM.ref4
424 const inner_union_index = dbg_info_buffer.items.len;
425 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4);
426 try self.addTypeRelocLocal(atom_index, @intCast(inner_union_index), 5);
427 // DW.AT.data_member_location, DW.FORM.udata
428 try leb128.writeUleb128(dbg_info_buffer.writer(), payload_offset);
429 }
92const DebugLine = struct {
93 header: Header,
94 section: Section,
95
96 const Header = struct {
97 minimum_instruction_length: u8,
98 maximum_operations_per_instruction: u8,
99 default_is_stmt: bool,
100 line_base: i8,
101 line_range: u8,
102 opcode_base: u8,
103 };
430104
431 // DW.AT.union_type
432 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.union_type));
433 // DW.AT.byte_size, DW.FORM.udata,
434 try leb128.writeUleb128(dbg_info_buffer.writer(), layout.payload_size);
435 // DW.AT.name, DW.FORM.string
436 if (is_tagged) {
437 try dbg_info_buffer.writer().print("AnonUnion\x00", .{});
438 } else {
439 try ty.print(dbg_info_buffer.writer(), pt);
440 try dbg_info_buffer.append(0);
441 }
105 fn dirIndexInfo(dir_count: u32) struct { bytes: u8, form: DeclValEnum(DW.FORM) } {
106 return if (dir_count <= 1 << 8)
107 .{ .bytes = 1, .form = .data1 }
108 else if (dir_count <= 1 << 16)
109 .{ .bytes = 2, .form = .data2 }
110 else
111 unreachable;
112 }
442113
443 for (union_obj.field_types.get(ip), union_obj.loadTagType(ip).names.get(ip)) |field_ty, field_name| {
444 if (!Type.fromInterned(field_ty).hasRuntimeBits(pt)) continue;
445 const field_name_slice = field_name.toSlice(ip);
446 // DW.AT.member
447 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_member));
448 // DW.AT.name, DW.FORM.string
449 try dbg_info_buffer.appendSlice(field_name_slice[0 .. field_name_slice.len + 1]);
450 // DW.AT.type, DW.FORM.ref4
451 const index = dbg_info_buffer.items.len;
452 try dbg_info_buffer.appendNTimes(0, 4);
453 try self.addTypeRelocGlobal(atom_index, Type.fromInterned(field_ty), @intCast(index));
454 // DW.AT.data_member_location, DW.FORM.udata
455 try dbg_info_buffer.append(0);
456 }
457 // DW.AT.union_type delimit children
458 try dbg_info_buffer.append(0);
459
460 if (is_tagged) {
461 // DW.AT.member
462 try dbg_info_buffer.ensureUnusedCapacity(9);
463 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member));
464 // DW.AT.name, DW.FORM.string
465 dbg_info_buffer.appendSliceAssumeCapacity("tag");
466 dbg_info_buffer.appendAssumeCapacity(0);
467 // DW.AT.type, DW.FORM.ref4
468 const index = dbg_info_buffer.items.len;
469 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4);
470 try self.addTypeRelocGlobal(atom_index, Type.fromInterned(union_obj.enum_tag_ty), @intCast(index));
471 // DW.AT.data_member_location, DW.FORM.udata
472 try leb128.writeUleb128(dbg_info_buffer.writer(), tag_offset);
473
474 // DW.AT.structure_type delimit children
475 try dbg_info_buffer.append(0);
476 }
477 },
478 .ErrorSet => try addDbgInfoErrorSet(pt, ty, target, &self.dbg_info),
479 .ErrorUnion => {
480 const error_ty = ty.errorUnionSet(zcu);
481 const payload_ty = ty.errorUnionPayload(zcu);
482 const payload_align = if (payload_ty.isNoReturn(zcu)) .none else payload_ty.abiAlignment(pt);
483 const error_align = Type.anyerror.abiAlignment(pt);
484 const abi_size = ty.abiSize(pt);
485 const payload_off = if (error_align.compare(.gte, payload_align)) Type.anyerror.abiSize(pt) else 0;
486 const error_off = if (error_align.compare(.gte, payload_align)) 0 else payload_ty.abiSize(pt);
487
488 // DW.AT.structure_type
489 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_type));
490 // DW.AT.byte_size, DW.FORM.udata
491 try leb128.writeUleb128(dbg_info_buffer.writer(), abi_size);
492 // DW.AT.name, DW.FORM.string
493 try ty.print(dbg_info_buffer.writer(), pt);
494 try dbg_info_buffer.append(0);
495
496 if (!payload_ty.isNoReturn(zcu)) {
497 // DW.AT.member
498 try dbg_info_buffer.ensureUnusedCapacity(11);
499 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member));
500 // DW.AT.name, DW.FORM.string
501 dbg_info_buffer.appendSliceAssumeCapacity("value");
502 dbg_info_buffer.appendAssumeCapacity(0);
503 // DW.AT.type, DW.FORM.ref4
504 const index = dbg_info_buffer.items.len;
505 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4);
506 try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(index));
507 // DW.AT.data_member_location, DW.FORM.udata
508 try leb128.writeUleb128(dbg_info_buffer.writer(), payload_off);
509 }
114 fn headerBytes(dwarf: *Dwarf, dir_count: u32, file_count: u32) u32 {
115 const dir_index_info = dirIndexInfo(dir_count);
116 return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() + 1 + 1 + 1 + 1 + 1 + 1 + 1 * (dwarf.debug_line.header.opcode_base - 1) +
117 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(dir_count) + (dwarf.sectionOffsetBytes()) * dir_count +
118 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(DW.LNCT.directory_index) + uleb128Bytes(@intFromEnum(dir_index_info.form)) + uleb128Bytes(DW.LNCT.LLVM_source) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(file_count) + (dwarf.sectionOffsetBytes() + dir_index_info.bytes + dwarf.sectionOffsetBytes()) * file_count;
119 }
510120
511 {
512 // DW.AT.member
513 try dbg_info_buffer.ensureUnusedCapacity(9);
514 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member));
515 // DW.AT.name, DW.FORM.string
516 dbg_info_buffer.appendSliceAssumeCapacity("err");
517 dbg_info_buffer.appendAssumeCapacity(0);
518 // DW.AT.type, DW.FORM.ref4
519 const index = dbg_info_buffer.items.len;
520 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4);
521 try self.addTypeRelocGlobal(atom_index, error_ty, @intCast(index));
522 // DW.AT.data_member_location, DW.FORM.udata
523 try leb128.writeUleb128(dbg_info_buffer.writer(), error_off);
524 }
121 const trailer_bytes = 1 + uleb128Bytes(0) +
122 1 + uleb128Bytes(1) + 1;
123};
525124
526 // DW.AT.structure_type delimit children
527 try dbg_info_buffer.append(0);
528 },
529 else => {
530 log.debug("TODO implement .debug_info for type '{}'", .{ty.fmt(pt)});
531 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.zero_bit_type));
532 },
533 }
125const DebugLocLists = struct {
126 section: Section,
127
128 fn baseOffset(dwarf: *Dwarf) u32 {
129 return dwarf.unitLengthBytes() + 2 + 1 + 1 + 4;
534130 }
535131
536 pub const DbgInfoLoc = union(enum) {
537 register: u8,
538 register_pair: [2]u8,
539 stack: struct {
540 fp_register: u8,
541 offset: i32,
542 },
543 wasm_local: u32,
544 memory: u64,
545 linker_load: LinkerLoad,
546 immediate: u64,
547 undef,
548 none,
549 nop,
550 };
132 fn headerBytes(dwarf: *Dwarf) u32 {
133 return baseOffset(dwarf);
134 }
551135
552 pub fn genArgDbgInfo(
553 self: *NavState,
554 name: [:0]const u8,
555 ty: Type,
556 owner_nav: InternPool.Nav.Index,
557 loc: DbgInfoLoc,
558 ) error{OutOfMemory}!void {
559 const pt = self.pt;
560 const dbg_info = &self.dbg_info;
561 const atom_index = self.di_atom_navs.get(owner_nav).?;
562 const name_with_null = name.ptr[0 .. name.len + 1];
136 const trailer_bytes = 0;
137};
563138
564 switch (loc) {
565 .register => |reg| {
566 try dbg_info.ensureUnusedCapacity(4);
567 dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevCode.parameter));
568 // DW.AT.location, DW.FORM.exprloc
569 var expr_len = std.io.countingWriter(std.io.null_writer);
570 if (reg < 32) {
571 expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable;
572 } else {
573 expr_len.writer().writeByte(DW.OP.regx) catch unreachable;
574 leb128.writeUleb128(expr_len.writer(), reg) catch unreachable;
575 }
576 leb128.writeUleb128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
577 if (reg < 32) {
578 dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg);
579 } else {
580 dbg_info.appendAssumeCapacity(DW.OP.regx);
581 leb128.writeUleb128(dbg_info.writer(), reg) catch unreachable;
582 }
583 },
584 .register_pair => |regs| {
585 const reg_bits = pt.zcu.getTarget().ptrBitWidth();
586 const reg_bytes: u8 = @intCast(@divExact(reg_bits, 8));
587 const abi_size = ty.abiSize(pt);
588 try dbg_info.ensureUnusedCapacity(10);
589 dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevCode.parameter));
590 // DW.AT.location, DW.FORM.exprloc
591 var expr_len = std.io.countingWriter(std.io.null_writer);
592 for (regs, 0..) |reg, reg_i| {
593 if (reg < 32) {
594 expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable;
595 } else {
596 expr_len.writer().writeByte(DW.OP.regx) catch unreachable;
597 leb128.writeUleb128(expr_len.writer(), reg) catch unreachable;
598 }
599 expr_len.writer().writeByte(DW.OP.piece) catch unreachable;
600 leb128.writeUleb128(
601 expr_len.writer(),
602 @min(abi_size - reg_i * reg_bytes, reg_bytes),
603 ) catch unreachable;
604 }
605 leb128.writeUleb128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
606 for (regs, 0..) |reg, reg_i| {
607 if (reg < 32) {
608 dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg);
609 } else {
610 dbg_info.appendAssumeCapacity(DW.OP.regx);
611 leb128.writeUleb128(dbg_info.writer(), reg) catch unreachable;
612 }
613 dbg_info.appendAssumeCapacity(DW.OP.piece);
614 leb128.writeUleb128(
615 dbg_info.writer(),
616 @min(abi_size - reg_i * reg_bytes, reg_bytes),
617 ) catch unreachable;
618 }
619 },
620 .stack => |info| {
621 try dbg_info.ensureUnusedCapacity(9);
622 dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevCode.parameter));
623 // DW.AT.location, DW.FORM.exprloc
624 var expr_len = std.io.countingWriter(std.io.null_writer);
625 if (info.fp_register < 32) {
626 expr_len.writer().writeByte(DW.OP.breg0 + info.fp_register) catch unreachable;
627 } else {
628 expr_len.writer().writeByte(DW.OP.bregx) catch unreachable;
629 leb128.writeUleb128(expr_len.writer(), info.fp_register) catch unreachable;
630 }
631 leb128.writeIleb128(expr_len.writer(), info.offset) catch unreachable;
632 leb128.writeUleb128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
633 if (info.fp_register < 32) {
634 dbg_info.appendAssumeCapacity(DW.OP.breg0 + info.fp_register);
635 } else {
636 dbg_info.appendAssumeCapacity(DW.OP.bregx);
637 leb128.writeUleb128(dbg_info.writer(), info.fp_register) catch unreachable;
638 }
639 leb128.writeIleb128(dbg_info.writer(), info.offset) catch unreachable;
640 },
641 .wasm_local => |value| {
642 @import("../dev.zig").check(.wasm_linker);
643 const leb_size = link.File.Wasm.getUleb128Size(value);
644 try dbg_info.ensureUnusedCapacity(3 + leb_size);
645 // wasm locations are encoded as follow:
646 // DW_OP_WASM_location wasm-op
647 // where wasm-op is defined as
648 // wasm-op := wasm-local | wasm-global | wasm-operand_stack
649 // where each argument is encoded as
650 // <opcode> i:uleb128
651 dbg_info.appendSliceAssumeCapacity(&.{
652 @intFromEnum(AbbrevCode.parameter),
653 DW.OP.WASM_location,
654 DW.OP.WASM_local,
655 });
656 leb128.writeUleb128(dbg_info.writer(), value) catch unreachable;
657 },
658 else => unreachable,
659 }
139const DebugRngLists = struct {
140 section: Section,
660141
661 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
662 const index = dbg_info.items.len;
663 dbg_info.appendNTimesAssumeCapacity(0, 4);
664 try self.addTypeRelocGlobal(atom_index, ty, @intCast(index)); // DW.AT.type, DW.FORM.ref4
665 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
666 }
142 const baseOffset = DebugLocLists.baseOffset;
667143
668 pub fn genVarDbgInfo(
669 self: *NavState,
670 name: [:0]const u8,
671 ty: Type,
672 owner_nav: InternPool.Nav.Index,
673 is_ptr: bool,
674 loc: DbgInfoLoc,
675 ) error{OutOfMemory}!void {
676 const dbg_info = &self.dbg_info;
677 const atom_index = self.di_atom_navs.get(owner_nav).?;
678 const name_with_null = name.ptr[0 .. name.len + 1];
679 try dbg_info.append(@intFromEnum(AbbrevCode.variable));
680 const gpa = self.dwarf.allocator;
681 const pt = self.pt;
682 const target = pt.zcu.getTarget();
683 const endian = target.cpu.arch.endian();
684 const child_ty = if (is_ptr) ty.childType(pt.zcu) else ty;
144 fn headerBytes(dwarf: *Dwarf) u32 {
145 return baseOffset(dwarf) + dwarf.sectionOffsetBytes() * 1;
146 }
685147
686 switch (loc) {
687 .register => |reg| {
688 try dbg_info.ensureUnusedCapacity(3);
689 // DW.AT.location, DW.FORM.exprloc
690 var expr_len = std.io.countingWriter(std.io.null_writer);
691 if (reg < 32) {
692 expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable;
693 } else {
694 expr_len.writer().writeByte(DW.OP.regx) catch unreachable;
695 leb128.writeUleb128(expr_len.writer(), reg) catch unreachable;
696 }
697 leb128.writeUleb128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
698 if (reg < 32) {
699 dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg);
700 } else {
701 dbg_info.appendAssumeCapacity(DW.OP.regx);
702 leb128.writeUleb128(dbg_info.writer(), reg) catch unreachable;
703 }
704 },
148 const trailer_bytes = 1;
149};
705150
706 .register_pair => |regs| {
707 const reg_bits = pt.zcu.getTarget().ptrBitWidth();
708 const reg_bytes: u8 = @intCast(@divExact(reg_bits, 8));
709 const abi_size = child_ty.abiSize(pt);
710 try dbg_info.ensureUnusedCapacity(9);
711 // DW.AT.location, DW.FORM.exprloc
712 var expr_len = std.io.countingWriter(std.io.null_writer);
713 for (regs, 0..) |reg, reg_i| {
714 if (reg < 32) {
715 expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable;
716 } else {
717 expr_len.writer().writeByte(DW.OP.regx) catch unreachable;
718 leb128.writeUleb128(expr_len.writer(), reg) catch unreachable;
719 }
720 expr_len.writer().writeByte(DW.OP.piece) catch unreachable;
721 leb128.writeUleb128(
722 expr_len.writer(),
723 @min(abi_size - reg_i * reg_bytes, reg_bytes),
724 ) catch unreachable;
725 }
726 leb128.writeUleb128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
727 for (regs, 0..) |reg, reg_i| {
728 if (reg < 32) {
729 dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg);
730 } else {
731 dbg_info.appendAssumeCapacity(DW.OP.regx);
732 leb128.writeUleb128(dbg_info.writer(), reg) catch unreachable;
733 }
734 dbg_info.appendAssumeCapacity(DW.OP.piece);
735 leb128.writeUleb128(
736 dbg_info.writer(),
737 @min(abi_size - reg_i * reg_bytes, reg_bytes),
738 ) catch unreachable;
739 }
740 },
151const StringSection = struct {
152 contents: std.ArrayListUnmanaged(u8),
153 map: std.AutoArrayHashMapUnmanaged(void, void),
154 section: Section,
741155
742 .stack => |info| {
743 try dbg_info.ensureUnusedCapacity(9);
744 // DW.AT.location, DW.FORM.exprloc
745 var expr_len = std.io.countingWriter(std.io.null_writer);
746 if (info.fp_register < 32) {
747 expr_len.writer().writeByte(DW.OP.breg0 + info.fp_register) catch unreachable;
748 } else {
749 expr_len.writer().writeByte(DW.OP.bregx) catch unreachable;
750 leb128.writeUleb128(expr_len.writer(), info.fp_register) catch unreachable;
751 }
752 leb128.writeIleb128(expr_len.writer(), info.offset) catch unreachable;
753 leb128.writeUleb128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
754 if (info.fp_register < 32) {
755 dbg_info.appendAssumeCapacity(DW.OP.breg0 + info.fp_register);
756 } else {
757 dbg_info.appendAssumeCapacity(DW.OP.bregx);
758 leb128.writeUleb128(dbg_info.writer(), info.fp_register) catch unreachable;
759 }
760 leb128.writeIleb128(dbg_info.writer(), info.offset) catch unreachable;
761 },
762
763 .wasm_local => |value| {
764 const leb_size = link.File.Wasm.getUleb128Size(value);
765 try dbg_info.ensureUnusedCapacity(2 + leb_size);
766 // wasm locals are encoded as follow:
767 // DW_OP_WASM_location wasm-op
768 // where wasm-op is defined as
769 // wasm-op := wasm-local | wasm-global | wasm-operand_stack
770 // where wasm-local is encoded as
771 // wasm-local := 0x00 i:uleb128
772 dbg_info.appendSliceAssumeCapacity(&.{
773 DW.OP.WASM_location,
774 DW.OP.WASM_local,
775 });
776 leb128.writeUleb128(dbg_info.writer(), value) catch unreachable;
777 },
156 const unit: Unit.Index = @enumFromInt(0);
778157
779 .memory,
780 .linker_load,
781 => {
782 const ptr_width: u8 = @intCast(@divExact(target.ptrBitWidth(), 8));
783 try dbg_info.ensureUnusedCapacity(2 + ptr_width);
784 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
785 1 + ptr_width + @intFromBool(is_ptr),
786 DW.OP.addr, // literal address
787 });
788 const offset: u32 = @intCast(dbg_info.items.len);
789 const addr = switch (loc) {
790 .memory => |x| x,
791 else => 0,
792 };
793 switch (ptr_width) {
794 0...4 => {
795 try dbg_info.writer().writeInt(u32, @intCast(addr), endian);
796 },
797 5...8 => {
798 try dbg_info.writer().writeInt(u64, addr, endian);
799 },
800 else => unreachable,
801 }
802 if (is_ptr) {
803 // We need deref the address as we point to the value via GOT entry.
804 try dbg_info.append(DW.OP.deref);
805 }
806 switch (loc) {
807 .linker_load => |load_struct| switch (load_struct.type) {
808 .direct => {
809 log.debug("{x}: target sym %{d}", .{ offset, load_struct.sym_index });
810 try self.exprloc_relocs.append(gpa, .{
811 .type = .direct_load,
812 .target = load_struct.sym_index,
813 .offset = offset,
814 });
815 },
816 .got => {
817 log.debug("{x}: target sym %{d} via GOT", .{ offset, load_struct.sym_index });
818 try self.exprloc_relocs.append(gpa, .{
819 .type = .got_load,
820 .target = load_struct.sym_index,
821 .offset = offset,
822 });
823 },
824 else => {}, // TODO
825 },
826 else => {},
827 }
828 },
158 const init: StringSection = .{
159 .contents = .{},
160 .map = .{},
161 .section = Section.init,
162 };
829163
830 .immediate => |x| {
831 try dbg_info.ensureUnusedCapacity(2);
832 const fixup = dbg_info.items.len;
833 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
834 1,
835 if (child_ty.isSignedInt(pt.zcu)) DW.OP.consts else DW.OP.constu,
836 });
837 if (child_ty.isSignedInt(pt.zcu)) {
838 try leb128.writeIleb128(dbg_info.writer(), @as(i64, @bitCast(x)));
839 } else {
840 try leb128.writeUleb128(dbg_info.writer(), x);
841 }
842 try dbg_info.append(DW.OP.stack_value);
843 dbg_info.items[fixup] += @intCast(dbg_info.items.len - fixup - 2);
844 },
845
846 .undef => {
847 // DW.AT.location, DW.FORM.exprloc
848 // uleb128(exprloc_len)
849 // DW.OP.implicit_value uleb128(len_of_bytes) bytes
850 const abi_size: u32 = @intCast(child_ty.abiSize(self.pt));
851 var implicit_value_len = std.ArrayList(u8).init(gpa);
852 defer implicit_value_len.deinit();
853 try leb128.writeUleb128(implicit_value_len.writer(), abi_size);
854 const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
855 try leb128.writeUleb128(dbg_info.writer(), total_exprloc_len);
856 try dbg_info.ensureUnusedCapacity(total_exprloc_len);
857 dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
858 dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
859 dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
860 },
861
862 .none => {
863 try dbg_info.ensureUnusedCapacity(3);
864 dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
865 2, DW.OP.lit0, DW.OP.stack_value,
866 });
867 },
164 fn deinit(str_sec: *StringSection, gpa: std.mem.Allocator) void {
165 str_sec.contents.deinit(gpa);
166 str_sec.map.deinit(gpa);
167 str_sec.section.deinit(gpa);
168 }
868169
869 .nop => {
870 try dbg_info.ensureUnusedCapacity(2);
871 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
872 1, DW.OP.nop,
873 });
874 },
170 fn addString(str_sec: *StringSection, dwarf: *Dwarf, str: []const u8) UpdateError!Entry.Index {
171 const gop = try str_sec.map.getOrPutAdapted(dwarf.gpa, str, Adapter{ .str_sec = str_sec });
172 errdefer _ = str_sec.map.pop();
173 const entry: Entry.Index = @enumFromInt(gop.index);
174 if (!gop.found_existing) {
175 assert(try str_sec.section.addEntry(unit, dwarf) == entry);
176 errdefer _ = str_sec.section.getUnit(unit).entries.pop();
177 const entry_ptr = str_sec.section.getUnit(unit).getEntry(entry);
178 assert(entry_ptr.off == str_sec.contents.items.len);
179 entry_ptr.len = @intCast(str.len + 1);
180 try str_sec.contents.ensureUnusedCapacity(dwarf.gpa, str.len + 1);
181 str_sec.contents.appendSliceAssumeCapacity(str);
182 str_sec.contents.appendAssumeCapacity(0);
183 str_sec.section.dirty = true;
875184 }
876
877 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
878 const index = dbg_info.items.len;
879 dbg_info.appendNTimesAssumeCapacity(0, 4); // dw.at.type, dw.form.ref4
880 try self.addTypeRelocGlobal(atom_index, child_ty, @intCast(index));
881 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
185 return entry;
882186 }
883187
884 pub fn advancePCAndLine(
885 self: *NavState,
886 delta_line: i33,
887 delta_pc: u64,
888 ) error{OutOfMemory}!void {
889 const dbg_line = &self.dbg_line;
890 try dbg_line.ensureUnusedCapacity(5 + 5 + 1);
188 const Adapter = struct {
189 str_sec: *StringSection,
891190
892 const header = self.dwarf.dbg_line_header;
893 assert(header.maximum_operations_per_instruction == 1);
894 const delta_op: u64 = 0;
191 pub fn hash(_: Adapter, key: []const u8) u32 {
192 return @truncate(std.hash.Wyhash.hash(0, key));
193 }
895194
896 const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or
897 delta_line - header.line_base >= header.line_range)
898 remaining: {
899 assert(delta_line != 0);
900 dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
901 leb128.writeIleb128(dbg_line.writer(), delta_line) catch unreachable;
902 break :remaining 0;
903 } else delta_line);
195 pub fn eql(adapter: Adapter, key: []const u8, _: void, rhs_index: usize) bool {
196 const entry = adapter.str_sec.section.getUnit(unit).getEntry(@enumFromInt(rhs_index));
197 return std.mem.eql(u8, key, adapter.str_sec.contents.items[entry.off..][0 .. entry.len - 1 :0]);
198 }
199 };
200};
904201
905 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
906 header.maximum_operations_per_instruction + delta_op;
907 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
908 const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: {
909 dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
910 leb128.writeUleb128(dbg_line.writer(), op_advance) catch unreachable;
911 break :remaining 0;
912 } else if (op_advance >= max_op_advance) remaining: {
913 dbg_line.appendAssumeCapacity(DW.LNS.const_add_pc);
914 break :remaining op_advance - max_op_advance;
915 } else op_advance);
202/// A linker section containing a sequence of `Unit`s.
203const Section = struct {
204 dirty: bool,
205 pad_to_ideal: bool,
206 alignment: InternPool.Alignment,
207 index: u32,
208 first: Unit.Index.Optional,
209 last: Unit.Index.Optional,
210 off: u64,
211 len: u64,
212 units: std.ArrayListUnmanaged(Unit),
213
214 const Index = enum {
215 debug_abbrev,
216 debug_info,
217 debug_line,
218 debug_line_str,
219 debug_loclists,
220 debug_rnglists,
221 debug_str,
222 };
916223
917 if (remaining_delta_line == 0 and remaining_op_advance == 0) {
918 dbg_line.appendAssumeCapacity(DW.LNS.copy);
919 } else {
920 dbg_line.appendAssumeCapacity(@intCast((remaining_delta_line - header.line_base) +
921 (header.line_range * remaining_op_advance) + header.opcode_base));
922 }
224 const init: Section = .{
225 .dirty = true,
226 .pad_to_ideal = true,
227 .alignment = .@"1",
228 .index = std.math.maxInt(u32),
229 .first = .none,
230 .last = .none,
231 .off = 0,
232 .len = 0,
233 .units = .{},
234 };
235
236 fn deinit(sec: *Section, gpa: std.mem.Allocator) void {
237 for (sec.units.items) |*unit| unit.deinit(gpa);
238 sec.units.deinit(gpa);
239 sec.* = undefined;
923240 }
924241
925 pub fn setColumn(self: *NavState, column: u32) error{OutOfMemory}!void {
926 try self.dbg_line.ensureUnusedCapacity(1 + 5);
927 self.dbg_line.appendAssumeCapacity(DW.LNS.set_column);
928 leb128.writeUleb128(self.dbg_line.writer(), column + 1) catch unreachable;
242 fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index {
243 const unit: Unit.Index = @enumFromInt(sec.units.items.len);
244 const unit_ptr = try sec.units.addOne(dwarf.gpa);
245 errdefer sec.popUnit();
246 unit_ptr.* = .{
247 .prev = sec.last,
248 .next = .none,
249 .first = .none,
250 .last = .none,
251 .off = 0,
252 .header_len = header_len,
253 .trailer_len = trailer_len,
254 .len = header_len + trailer_len,
255 .entries = .{},
256 .cross_entry_relocs = .{},
257 .cross_unit_relocs = .{},
258 .cross_section_relocs = .{},
259 .external_relocs = .{},
260 };
261 if (sec.last.unwrap()) |last_unit| {
262 const last_unit_ptr = sec.getUnit(last_unit);
263 last_unit_ptr.next = unit.toOptional();
264 unit_ptr.off = last_unit_ptr.off + sec.padToIdeal(last_unit_ptr.len);
265 }
266 if (sec.first == .none)
267 sec.first = unit.toOptional();
268 sec.last = unit.toOptional();
269 try sec.resize(dwarf, unit_ptr.off + sec.padToIdeal(unit_ptr.len));
270 return unit;
929271 }
930272
931 pub fn setPrologueEnd(self: *NavState) error{OutOfMemory}!void {
932 try self.dbg_line.append(DW.LNS.set_prologue_end);
273 fn unlinkUnit(sec: *Section, unit: Unit.Index) void {
274 const unit_ptr = sec.getUnit(unit);
275 if (unit_ptr.prev.unwrap()) |prev_unit| sec.getUnit(prev_unit).next = unit_ptr.next;
276 if (unit_ptr.next.unwrap()) |next_unit| sec.getUnit(next_unit).prev = unit_ptr.prev;
277 if (sec.first.unwrap().? == unit) sec.first = unit_ptr.next;
278 if (sec.last.unwrap().? == unit) sec.last = unit_ptr.prev;
933279 }
934280
935 pub fn setEpilogueBegin(self: *NavState) error{OutOfMemory}!void {
936 try self.dbg_line.append(DW.LNS.set_epilogue_begin);
281 fn popUnit(sec: *Section) void {
282 const unit: Unit.Index = @enumFromInt(sec.units.items.len - 1);
283 sec.unlinkUnit(unit);
284 _ = sec.units.pop();
937285 }
938286
939 pub fn setInlineFunc(self: *NavState, func: InternPool.Index) error{OutOfMemory}!void {
940 const zcu = self.pt.zcu;
941 if (self.dbg_line_func == func) return;
287 fn addEntry(sec: *Section, unit: Unit.Index, dwarf: *Dwarf) UpdateError!Entry.Index {
288 return sec.getUnit(unit).addEntry(sec, dwarf);
289 }
942290
943 try self.dbg_line.ensureUnusedCapacity((1 + 4) + (1 + 5));
291 fn getUnit(sec: *Section, unit: Unit.Index) *Unit {
292 return &sec.units.items[@intFromEnum(unit)];
293 }
944294
945 const old_func_info = zcu.funcInfo(self.dbg_line_func);
946 const new_func_info = zcu.funcInfo(func);
295 fn replaceEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
296 const unit_ptr = sec.getUnit(unit);
297 try unit_ptr.getEntry(entry).replace(unit_ptr, sec, dwarf, contents);
298 }
947299
948 const old_file = try self.dwarf.addDIFile(zcu, old_func_info.owner_nav);
949 const new_file = try self.dwarf.addDIFile(zcu, new_func_info.owner_nav);
950 if (old_file != new_file) {
951 self.dbg_line.appendAssumeCapacity(DW.LNS.set_file);
952 leb128.writeUnsignedFixed(4, self.dbg_line.addManyAsArrayAssumeCapacity(4), new_file);
300 fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {
301 if (dwarf.bin_file.cast(.elf)) |elf_file| {
302 try elf_file.growNonAllocSection(sec.index, len, @intCast(sec.alignment.toByteUnits().?), true);
303 const shdr = &elf_file.shdrs.items[sec.index];
304 sec.off = shdr.sh_offset;
305 sec.len = shdr.sh_size;
306 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
307 const header = if (macho_file.d_sym) |*d_sym| header: {
308 try d_sym.growSection(@intCast(sec.index), len, true, macho_file);
309 break :header &d_sym.sections.items[sec.index];
310 } else header: {
311 try macho_file.growSection(@intCast(sec.index), len);
312 break :header &macho_file.sections.items(.header)[sec.index];
313 };
314 sec.off = header.offset;
315 sec.len = header.size;
953316 }
317 }
954318
955 const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav);
956 const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav);
957 if (new_src_line != old_src_line) {
958 self.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
959 leb128.writeSignedFixed(5, self.dbg_line.addManyAsArrayAssumeCapacity(5), new_src_line - old_src_line);
319 fn trim(sec: *Section, dwarf: *Dwarf) void {
320 const len = sec.getUnit(sec.first.unwrap() orelse return).off;
321 if (len == 0) return;
322 for (sec.units.items) |*unit| unit.off -= len;
323 sec.off += len;
324 sec.len -= len;
325 if (dwarf.bin_file.cast(.elf)) |elf_file| {
326 const shdr = &elf_file.shdrs.items[sec.index];
327 shdr.sh_offset = sec.off;
328 shdr.sh_size = sec.len;
329 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
330 const header = if (macho_file.d_sym) |*d_sym|
331 &d_sym.sections.items[sec.index]
332 else
333 &macho_file.sections.items(.header)[sec.index];
334 header.offset = @intCast(sec.off);
335 header.size = sec.len;
960336 }
961
962 self.dbg_line_func = func;
963337 }
964};
965338
966pub const AbbrevEntry = struct {
967 atom_index: Atom.Index,
968 type: Type,
969 offset: u32,
970};
339 fn resolveRelocs(sec: *Section, dwarf: *Dwarf) RelocError!void {
340 for (sec.units.items) |*unit| try unit.resolveRelocs(sec, dwarf);
341 }
971342
972pub const AbbrevRelocation = struct {
973 /// If target is null, we deal with a local relocation that is based on simple offset + addend
974 /// only.
975 target: ?u32,
976 atom_index: Atom.Index,
977 offset: u32,
978 addend: u32,
343 fn padToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) {
344 return if (sec.pad_to_ideal) Dwarf.padToIdeal(actual_size) else actual_size;
345 }
979346};
980347
981pub const ExprlocRelocation = struct {
982 /// Type of the relocation: direct load ref, or GOT load ref (via GOT table)
983 type: enum {
984 direct_load,
985 got_load,
986 },
987 /// Index of the target in the linker's locals symbol table.
988 target: u32,
989 /// Offset within the debug info buffer where to patch up the address value.
990 offset: u32,
991};
348/// A unit within a `Section` containing a sequence of `Entry`s.
349const Unit = struct {
350 prev: Index.Optional,
351 next: Index.Optional,
352 first: Entry.Index.Optional,
353 last: Entry.Index.Optional,
354 /// offset within containing section
355 off: u32,
356 header_len: u32,
357 trailer_len: u32,
358 /// data length in bytes
359 len: u32,
360 entries: std.ArrayListUnmanaged(Entry),
361 cross_entry_relocs: std.ArrayListUnmanaged(CrossEntryReloc),
362 cross_unit_relocs: std.ArrayListUnmanaged(CrossUnitReloc),
363 cross_section_relocs: std.ArrayListUnmanaged(CrossSectionReloc),
364 external_relocs: std.ArrayListUnmanaged(ExternalReloc),
365
366 const Index = enum(u32) {
367 main,
368 _,
369
370 const Optional = enum(u32) {
371 none = std.math.maxInt(u32),
372 _,
373
374 fn unwrap(uio: Optional) ?Index {
375 return if (uio != .none) @enumFromInt(@intFromEnum(uio)) else null;
376 }
377 };
992378
993pub const PtrWidth = enum { p32, p64 };
379 fn toOptional(ui: Index) Optional {
380 return @enumFromInt(@intFromEnum(ui));
381 }
382 };
994383
995pub const AbbrevCode = enum(u8) {
996 null,
997 padding,
998 compile_unit,
999 subprogram,
1000 subprogram_retvoid,
1001 base_type,
1002 ptr_type,
1003 struct_type,
1004 struct_member,
1005 enum_type,
1006 enum_variant,
1007 union_type,
1008 zero_bit_type,
1009 parameter,
1010 variable,
1011 array_type,
1012 array_dim,
1013};
384 fn deinit(unit: *Unit, gpa: std.mem.Allocator) void {
385 unit.entries.deinit(gpa);
386 unit.cross_entry_relocs.deinit(gpa);
387 unit.cross_unit_relocs.deinit(gpa);
388 unit.cross_section_relocs.deinit(gpa);
389 unit.external_relocs.deinit(gpa);
390 unit.* = undefined;
391 }
1014392
1015/// The reloc offset for the virtual address of a function in its Line Number Program.
1016/// Size is a virtual address integer.
1017const dbg_line_vaddr_reloc_index = 3;
1018/// The reloc offset for the virtual address of a function in its .debug_info TAG.subprogram.
1019/// Size is a virtual address integer.
1020const dbg_info_low_pc_reloc_index = 1;
393 fn addEntry(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!Entry.Index {
394 const entry: Entry.Index = @enumFromInt(unit.entries.items.len);
395 const entry_ptr = try unit.entries.addOne(dwarf.gpa);
396 entry_ptr.* = .{
397 .prev = unit.last,
398 .next = .none,
399 .off = 0,
400 .len = 0,
401 };
402 if (unit.last.unwrap()) |last_entry| {
403 const last_entry_ptr = unit.getEntry(last_entry);
404 last_entry_ptr.next = entry.toOptional();
405 entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);
406 }
407 if (unit.first == .none)
408 unit.first = entry.toOptional();
409 unit.last = entry.toOptional();
410 return entry;
411 }
1021412
1022const min_nop_size = 2;
413 fn getEntry(unit: *Unit, entry: Entry.Index) *Entry {
414 return &unit.entries.items[@intFromEnum(entry)];
415 }
1023416
1024/// When allocating, the ideal_capacity is calculated by
1025/// actual_capacity + (actual_capacity / ideal_factor)
1026const ideal_factor = 3;
417 fn resize(unit_ptr: *Unit, sec: *Section, dwarf: *Dwarf, extra_header_len: u32, len: u32) UpdateError!void {
418 const end = if (unit_ptr.next.unwrap()) |next_unit|
419 sec.getUnit(next_unit).off
420 else
421 sec.len;
422 if (extra_header_len > 0 or unit_ptr.off + len > end) {
423 unit_ptr.len = @min(unit_ptr.len, len);
424 var new_off = unit_ptr.off;
425 if (unit_ptr.next.unwrap()) |next_unit| {
426 const next_unit_ptr = sec.getUnit(next_unit);
427 if (unit_ptr.prev.unwrap()) |prev_unit|
428 sec.getUnit(prev_unit).next = unit_ptr.next
429 else
430 sec.first = unit_ptr.next;
431 const unit = next_unit_ptr.prev;
432 next_unit_ptr.prev = unit_ptr.prev;
433 const last_unit_ptr = sec.getUnit(sec.last.unwrap().?);
434 last_unit_ptr.next = unit;
435 unit_ptr.prev = sec.last;
436 unit_ptr.next = .none;
437 new_off = last_unit_ptr.off + sec.padToIdeal(last_unit_ptr.len);
438 sec.last = unit;
439 sec.dirty = true;
440 } else if (extra_header_len > 0) {
441 // `copyRangeAll` in `move` does not support overlapping ranges
442 // so make sure new location is disjoint from current location.
443 new_off += unit_ptr.len -| extra_header_len;
444 }
445 try sec.resize(dwarf, new_off + len);
446 try unit_ptr.move(sec, dwarf, new_off + extra_header_len);
447 unit_ptr.off -= extra_header_len;
448 unit_ptr.header_len += extra_header_len;
449 sec.trim(dwarf);
450 }
451 unit_ptr.len = len;
452 }
1027453
1028pub fn init(lf: *File, format: Format) Dwarf {
1029 const comp = lf.comp;
1030 const gpa = comp.gpa;
1031 const target = comp.root_mod.resolved_target.result;
1032 const ptr_width: PtrWidth = switch (target.ptrBitWidth()) {
1033 0...32 => .p32,
1034 33...64 => .p64,
1035 else => unreachable,
1036 };
1037 return .{
1038 .allocator = gpa,
1039 .bin_file = lf,
1040 .format = format,
1041 .ptr_width = ptr_width,
1042 .dbg_line_header = switch (target.cpu.arch) {
1043 .x86_64, .aarch64 => .{
1044 .minimum_instruction_length = 1,
1045 .maximum_operations_per_instruction = 1,
1046 .default_is_stmt = true,
1047 .line_base = -5,
1048 .line_range = 14,
1049 .opcode_base = DW.LNS.set_isa + 1,
1050 },
1051 else => .{
1052 .minimum_instruction_length = 1,
1053 .maximum_operations_per_instruction = 1,
1054 .default_is_stmt = true,
1055 .line_base = 1,
1056 .line_range = 1,
1057 .opcode_base = DW.LNS.set_isa + 1,
1058 },
1059 },
1060 };
1061}
454 fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {
455 if (unit.off == new_off) return;
456 if (try dwarf.getFile().?.copyRangeAll(
457 sec.off + unit.off,
458 dwarf.getFile().?,
459 sec.off + new_off,
460 unit.len,
461 ) != unit.len) return error.InputOutput;
462 unit.off = new_off;
463 }
1062464
1063pub fn deinit(self: *Dwarf) void {
1064 const gpa = self.allocator;
465 fn resizeHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void {
466 if (unit.header_len == len) return;
467 const available_len = if (unit.prev.unwrap()) |prev_unit| prev_excess: {
468 const prev_unit_ptr = sec.getUnit(prev_unit);
469 break :prev_excess unit.off - prev_unit_ptr.off - prev_unit_ptr.len;
470 } else 0;
471 if (available_len + unit.header_len < len)
472 try unit.resize(sec, dwarf, len - unit.header_len, unit.len - unit.header_len + len);
473 if (unit.header_len > len) {
474 const excess_header_len = unit.header_len - len;
475 unit.off += excess_header_len;
476 unit.header_len -= excess_header_len;
477 unit.len -= excess_header_len;
478 } else if (unit.header_len < len) {
479 const needed_header_len = len - unit.header_len;
480 unit.off -= needed_header_len;
481 unit.header_len += needed_header_len;
482 unit.len += needed_header_len;
483 }
484 assert(unit.header_len == len);
485 sec.trim(dwarf);
486 }
1065487
1066 self.src_fn_free_list.deinit(gpa);
1067 self.src_fns.deinit(gpa);
1068 self.src_fn_navs.deinit(gpa);
488 fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
489 assert(contents.len == unit.header_len);
490 try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off);
491 }
1069492
1070 self.di_atom_free_list.deinit(gpa);
1071 self.di_atoms.deinit(gpa);
1072 self.di_atom_navs.deinit(gpa);
493 fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
494 const start = unit.off + unit.header_len + if (unit.last.unwrap()) |last_entry| end: {
495 const last_entry_ptr = unit.getEntry(last_entry);
496 break :end last_entry_ptr.off + last_entry_ptr.len;
497 } else 0;
498 const end = if (unit.next.unwrap()) |next_unit|
499 sec.getUnit(next_unit).off
500 else
501 sec.len;
502 const trailer_len: usize = @intCast(end - start);
503 assert(trailer_len >= unit.trailer_len);
504 var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, trailer_len);
505 defer trailer.deinit();
506 const fill_byte: u8 = if (sec == &dwarf.debug_aranges.section) fill: {
507 trailer.appendNTimesAssumeCapacity(0, @intFromEnum(dwarf.address_size) * 2);
508 break :fill 0;
509 } else if (sec == &dwarf.debug_info.section) fill: {
510 assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1);
511 trailer.appendNTimesAssumeCapacity(@intFromEnum(AbbrevCode.null), 2);
512 break :fill @intFromEnum(AbbrevCode.null);
513 } else if (sec == &dwarf.debug_line.section) fill: {
514 unit.len -= unit.trailer_len;
515 const extra_len: u32 = @intCast((trailer_len - DebugLine.trailer_bytes) & 1);
516 unit.trailer_len = DebugLine.trailer_bytes + extra_len;
517 unit.len += unit.trailer_len;
518
519 // prevent end sequence from emitting an invalid file index
520 trailer.appendAssumeCapacity(DW.LNS.set_file);
521 uleb128(trailer.fixedWriter(), 0) catch unreachable;
522
523 trailer.appendAssumeCapacity(DW.LNS.extended_op);
524 std.leb.writeUnsignedExtended(trailer.addManyAsSliceAssumeCapacity(uleb128Bytes(1) + extra_len), 1);
525 trailer.appendAssumeCapacity(DW.LNE.end_sequence);
526 break :fill DW.LNS.extended_op;
527 } else if (sec == &dwarf.debug_rnglists.section) fill: {
528 trailer.appendAssumeCapacity(DW.RLE.end_of_list);
529 break :fill DW.RLE.end_of_list;
530 } else unreachable;
531 assert(trailer.items.len == unit.trailer_len);
532 trailer.appendNTimesAssumeCapacity(fill_byte, trailer_len - trailer.items.len);
533 assert(trailer.items.len == trailer_len);
534 try dwarf.getFile().?.pwriteAll(trailer.items, sec.off + start);
535 }
1073536
1074 self.strtab.deinit(gpa);
1075 self.di_files.deinit(gpa);
1076 self.global_abbrev_relocs.deinit(gpa);
1077}
537 fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {
538 for (unit.cross_entry_relocs.items) |reloc| {
539 try dwarf.resolveReloc(
540 sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry|
541 unit.header_len + unit.getEntry(source_entry).off
542 else
543 0) + reloc.source_off,
544 unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off,
545 dwarf.sectionOffsetBytes(),
546 );
547 }
548 for (unit.cross_unit_relocs.items) |reloc| {
549 const target_unit = sec.getUnit(reloc.target_unit);
550 try dwarf.resolveReloc(
551 sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry|
552 unit.header_len + unit.getEntry(source_entry).off
553 else
554 0) + reloc.source_off,
555 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
556 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off
557 else
558 0) + reloc.target_off,
559 dwarf.sectionOffsetBytes(),
560 );
561 }
562 for (unit.cross_section_relocs.items) |reloc| {
563 const target_sec = switch (reloc.target_sec) {
564 inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section,
565 };
566 const target_unit = target_sec.getUnit(reloc.target_unit);
567 try dwarf.resolveReloc(
568 sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry|
569 unit.header_len + unit.getEntry(source_entry).off
570 else
571 0) + reloc.source_off,
572 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
573 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off
574 else
575 0) + reloc.target_off,
576 dwarf.sectionOffsetBytes(),
577 );
578 }
579 if (dwarf.bin_file.cast(.elf)) |elf_file| {
580 const zo = elf_file.zigObjectPtr().?;
581 for (unit.external_relocs.items) |reloc| {
582 const symbol = zo.symbol(reloc.target_sym);
583 try dwarf.resolveReloc(
584 sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off,
585 @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) -
586 if (symbol.flags.is_tls) elf_file.dtpAddress() else 0),
587 @intFromEnum(dwarf.address_size),
588 );
589 }
590 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
591 const zo = macho_file.getZigObject().?;
592 for (unit.external_relocs.items) |reloc| {
593 const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
594 try dwarf.resolveReloc(
595 sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off,
596 ref.getSymbol(macho_file).?.getAddress(.{}, macho_file),
597 @intFromEnum(dwarf.address_size),
598 );
599 }
600 }
601 }
1078602
1079/// Initializes Nav's state and its matching output buffers.
1080/// Call this before `commitNavState`.
1081pub fn initNavState(self: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !NavState {
1082 const tracy = trace(@src());
1083 defer tracy.end();
603 const CrossEntryReloc = struct {
604 source_entry: Entry.Index.Optional = .none,
605 source_off: u32 = 0,
606 target_entry: Entry.Index,
607 target_off: u32 = 0,
608 };
609 const CrossUnitReloc = struct {
610 source_entry: Entry.Index.Optional = .none,
611 source_off: u32 = 0,
612 target_unit: Unit.Index,
613 target_entry: Entry.Index.Optional = .none,
614 target_off: u32 = 0,
615 };
616 const CrossSectionReloc = struct {
617 source_entry: Entry.Index.Optional = .none,
618 source_off: u32 = 0,
619 target_sec: Section.Index,
620 target_unit: Unit.Index,
621 target_entry: Entry.Index.Optional = .none,
622 target_off: u32 = 0,
623 };
624 const ExternalReloc = struct {
625 source_entry: Entry.Index,
626 source_off: u32 = 0,
627 target_sym: u32,
628 target_off: u64 = 0,
629 };
630};
1084631
1085 const nav = pt.zcu.intern_pool.getNav(nav_index);
1086 log.debug("initNavState {}", .{nav.fqn.fmt(&pt.zcu.intern_pool)});
632/// An indivisible entry within a `Unit` containing section-specific data.
633const Entry = struct {
634 prev: Index.Optional,
635 next: Index.Optional,
636 /// offset from end of containing unit header
637 off: u32,
638 /// data length in bytes
639 len: u32,
1087640
1088 const gpa = self.allocator;
1089 var nav_state: NavState = .{
1090 .dwarf = self,
1091 .pt = pt,
1092 .di_atom_navs = &self.di_atom_navs,
1093 .dbg_line_func = undefined,
1094 .dbg_line = std.ArrayList(u8).init(gpa),
1095 .dbg_info = std.ArrayList(u8).init(gpa),
1096 .abbrev_type_arena = std.heap.ArenaAllocator.init(gpa),
1097 .abbrev_table = .{},
1098 .abbrev_resolver = .{},
1099 .abbrev_relocs = .{},
1100 .exprloc_relocs = .{},
1101 };
1102 errdefer nav_state.deinit();
1103 const dbg_line_buffer = &nav_state.dbg_line;
1104 const dbg_info_buffer = &nav_state.dbg_info;
641 const Index = enum(u32) {
642 _,
1105643
1106 const di_atom_index = try self.getOrCreateAtomForNav(.di_atom, nav_index);
644 const Optional = enum(u32) {
645 none = std.math.maxInt(u32),
646 _,
1107647
1108 const nav_val = Value.fromInterned(nav.status.resolved.val);
648 fn unwrap(eio: Optional) ?Index {
649 return if (eio != .none) @enumFromInt(@intFromEnum(eio)) else null;
650 }
651 };
1109652
1110 switch (nav_val.typeOf(pt.zcu).zigTypeTag(pt.zcu)) {
1111 .Fn => {
1112 _ = try self.getOrCreateAtomForNav(.src_fn, nav_index);
653 fn toOptional(ei: Index) Optional {
654 return @enumFromInt(@intFromEnum(ei));
655 }
656 };
1113657
1114 // For functions we need to add a prologue to the debug line program.
1115 const ptr_width_bytes = self.ptrWidthBytes();
1116 try dbg_line_buffer.ensureTotalCapacity((3 + ptr_width_bytes) + (1 + 4) + (1 + 4) + (1 + 5) + 1);
658 fn pad(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
659 const start = entry.off + entry.len;
660 const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;
661 if (sec == &dwarf.debug_info.section) {
662 var buf: [
663 @max(
664 uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)),
665 uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) + uleb128Bytes(std.math.maxInt(u32)),
666 )
667 ]u8 = undefined;
668 var fbs = std.io.fixedBufferStream(&buf);
669 switch (len) {
670 0 => {},
671 1 => uleb128(fbs.writer(), @intFromEnum(AbbrevCode.pad_1)) catch unreachable,
672 else => {
673 uleb128(fbs.writer(), @intFromEnum(AbbrevCode.pad_n)) catch unreachable;
674 const abbrev_code_bytes = fbs.pos;
675 var block_len_bytes: u5 = 1;
676 while (true) switch (std.math.order(len - abbrev_code_bytes - block_len_bytes, @as(u32, 1) << 7 * block_len_bytes)) {
677 .lt => break uleb128(fbs.writer(), len - abbrev_code_bytes - block_len_bytes) catch unreachable,
678 .eq => {
679 // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
680 block_len_bytes += 1;
681 std.leb.writeUnsignedExtended(buf[fbs.pos..][0..block_len_bytes], len - abbrev_code_bytes - block_len_bytes);
682 fbs.pos += block_len_bytes;
683 break;
684 },
685 .gt => block_len_bytes += 1,
686 };
687 assert(fbs.pos == abbrev_code_bytes + block_len_bytes);
688 },
689 }
690 assert(fbs.pos <= len);
691 try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start);
692 } else if (sec == &dwarf.debug_line.section) {
693 const buf = try dwarf.gpa.alloc(u8, len);
694 defer dwarf.gpa.free(buf);
695 @memset(buf, DW.LNS.const_add_pc);
696 try dwarf.getFile().?.pwriteAll(buf, sec.off + unit.off + unit.header_len + start);
697 } else assert(!sec.pad_to_ideal and len == 0);
698 }
1117699
1118 nav_state.dbg_line_func = nav_val.toIntern();
1119 const func = nav_val.getFunction(pt.zcu).?;
1120 log.debug("src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{
1121 pt.zcu.navSrcLine(nav_index),
1122 func.lbrace_line,
1123 func.rbrace_line,
700 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
701 const end = if (entry_ptr.next.unwrap()) |next_entry|
702 unit.getEntry(next_entry).off
703 else
704 unit.len -| (unit.header_len + unit.trailer_len);
705 if (entry_ptr.off + contents.len > end) {
706 if (entry_ptr.next.unwrap()) |next_entry| {
707 if (entry_ptr.prev.unwrap()) |prev_entry| {
708 const prev_entry_ptr = unit.getEntry(prev_entry);
709 prev_entry_ptr.next = entry_ptr.next;
710 try prev_entry_ptr.pad(unit, sec, dwarf);
711 } else unit.first = entry_ptr.next;
712 const next_entry_ptr = unit.getEntry(next_entry);
713 const entry = next_entry_ptr.prev;
714 next_entry_ptr.prev = entry_ptr.prev;
715 const last_entry_ptr = unit.getEntry(unit.last.unwrap().?);
716 last_entry_ptr.next = entry;
717 entry_ptr.prev = unit.last;
718 entry_ptr.next = .none;
719 entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);
720 unit.last = entry;
721 }
722 try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padToIdeal(contents.len) + unit.trailer_len));
723 }
724 entry_ptr.len = @intCast(contents.len);
725 {
726 var prev_entry_ptr = entry_ptr;
727 while (prev_entry_ptr.prev.unwrap()) |prev_entry| {
728 prev_entry_ptr = unit.getEntry(prev_entry);
729 if (prev_entry_ptr.len == 0) continue;
730 try prev_entry_ptr.pad(unit, sec, dwarf);
731 break;
732 }
733 }
734 try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off);
735 try entry_ptr.pad(unit, sec, dwarf);
736 if (false) {
737 const buf = try dwarf.gpa.alloc(u8, sec.len);
738 defer dwarf.gpa.free(buf);
739 _ = try dwarf.getFile().?.preadAll(buf, sec.off);
740 log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{
741 @intFromEnum(sec.first),
742 @intFromEnum(sec.last),
743 sec.off,
744 sec.len,
1124745 });
1125 const line: u28 = @intCast(pt.zcu.navSrcLine(nav_index) + func.lbrace_line);
746 for (sec.units.items) |*unit_ptr| {
747 log.info(" Unit{{ .prev = {}, .next = {}, .first = {}, .last = {}, .off = 0x{x}, .header_len = 0x{x}, .trailer_len = 0x{x}, .len = 0x{x} }}", .{
748 @intFromEnum(unit_ptr.prev),
749 @intFromEnum(unit_ptr.next),
750 @intFromEnum(unit_ptr.first),
751 @intFromEnum(unit_ptr.last),
752 unit_ptr.off,
753 unit_ptr.header_len,
754 unit_ptr.trailer_len,
755 unit_ptr.len,
756 });
757 for (unit_ptr.entries.items) |*entry| {
758 log.info(" Entry{{ .prev = {}, .next = {}, .off = 0x{x}, .len = 0x{x} }}", .{
759 @intFromEnum(entry.prev),
760 @intFromEnum(entry.next),
761 entry.off,
762 entry.len,
763 });
764 }
765 }
766 std.debug.dumpHex(buf);
767 }
768 }
1126769
1127 dbg_line_buffer.appendSliceAssumeCapacity(&.{
1128 DW.LNS.extended_op,
1129 ptr_width_bytes + 1,
1130 DW.LNE.set_address,
770 fn assertNonEmpty(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) *Entry {
771 if (entry.len > 0) return entry;
772 if (std.debug.runtime_safety) {
773 log.err("missing {} from {s}", .{
774 @as(Entry.Index, @enumFromInt(entry - unit.entries.items.ptr)),
775 std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file|
776 elf_file.shstrtab.items[elf_file.shdrs.items[sec.index].sh_name..]
777 else if (dwarf.bin_file.cast(.macho)) |macho_file|
778 if (macho_file.d_sym) |*d_sym|
779 &d_sym.sections.items[sec.index].segname
780 else
781 &macho_file.sections.items(.header)[sec.index].segname
782 else
783 "?", 0),
1131784 });
1132 // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`.
1133 assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len);
1134 dbg_line_buffer.appendNTimesAssumeCapacity(0, ptr_width_bytes);
1135
1136 dbg_line_buffer.appendAssumeCapacity(DW.LNS.advance_line);
1137 // This is the "relocatable" relative line offset from the previous function's end curly
1138 // to this function's begin curly.
1139 assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len);
1140 // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later.
1141 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line);
1142
1143 dbg_line_buffer.appendAssumeCapacity(DW.LNS.set_file);
1144 assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len);
1145 // Once we support more than one source file, this will have the ability to be more
1146 // than one possible value.
1147 const file_index = try self.addDIFile(pt.zcu, nav_index);
1148 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);
1149
1150 dbg_line_buffer.appendAssumeCapacity(DW.LNS.set_column);
1151 leb128.writeUleb128(dbg_line_buffer.writer(), func.lbrace_column + 1) catch unreachable;
1152
1153 // Emit a line for the begin curly with prologue_end=false. The codegen will
1154 // do the work of setting prologue_end=true and epilogue_begin=true.
1155 dbg_line_buffer.appendAssumeCapacity(DW.LNS.copy);
1156
1157 // .debug_info subprogram
1158 const nav_name_slice = nav.name.toSlice(&pt.zcu.intern_pool);
1159 const nav_linkage_name_slice = nav.fqn.toSlice(&pt.zcu.intern_pool);
1160 try dbg_info_buffer.ensureUnusedCapacity(1 + ptr_width_bytes + 4 + 4 +
1161 (nav_name_slice.len + 1) + (nav_linkage_name_slice.len + 1));
1162
1163 const fn_ret_type = nav_val.typeOf(pt.zcu).fnReturnType(pt.zcu);
1164 const fn_ret_has_bits = fn_ret_type.hasRuntimeBits(pt);
1165 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(
1166 @as(AbbrevCode, if (fn_ret_has_bits) .subprogram else .subprogram_retvoid),
1167 ));
1168 // These get overwritten after generating the machine code. These values are
1169 // "relocations" and have to be in this fixed place so that functions can be
1170 // moved in virtual address space.
1171 assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len);
1172 dbg_info_buffer.appendNTimesAssumeCapacity(0, ptr_width_bytes); // DW.AT.low_pc, DW.FORM.addr
1173 assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
1174 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); // DW.AT.high_pc, DW.FORM.data4
1175 if (fn_ret_has_bits) {
1176 try nav_state.addTypeRelocGlobal(di_atom_index, fn_ret_type, @intCast(dbg_info_buffer.items.len));
1177 dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); // DW.AT.type, DW.FORM.ref4
785 const zcu = dwarf.bin_file.comp.module.?;
786 const ip = &zcu.intern_pool;
787 for (dwarf.types.keys(), dwarf.types.values()) |ty, other_entry| {
788 const ty_unit: Unit.Index = if (Type.fromInterned(ty).typeDeclInst(zcu)) |inst_index|
789 dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFull(ip).file).mod) catch unreachable
790 else
791 .main;
792 if (sec.getUnit(ty_unit) == unit and unit.getEntry(other_entry) == entry)
793 log.err("missing Type({}({d}))", .{
794 Type.fromInterned(ty).fmt(.{ .tid = .main, .zcu = zcu }),
795 @intFromEnum(ty),
796 });
1178797 }
1179 dbg_info_buffer.appendSliceAssumeCapacity(
1180 nav_name_slice[0 .. nav_name_slice.len + 1],
1181 ); // DW.AT.name, DW.FORM.string
1182 dbg_info_buffer.appendSliceAssumeCapacity(
1183 nav_linkage_name_slice[0 .. nav_linkage_name_slice.len + 1],
1184 ); // DW.AT.linkage_name, DW.FORM.string
1185 },
1186 else => {
1187 // TODO implement .debug_info for global variables
1188 },
798 for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| {
799 const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFull(ip).file).mod) catch unreachable;
800 if (sec.getUnit(nav_unit) == unit and unit.getEntry(other_entry) == entry)
801 log.err("missing Nav({}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) });
802 }
803 }
804 @panic("missing dwarf relocation target");
1189805 }
806};
1190807
1191 return nav_state;
1192}
808pub const Loc = union(enum) {
809 empty,
810 addr: union(enum) { sym: u32 },
811 constu: u64,
812 consts: i64,
813 plus: Bin,
814 reg: u32,
815 breg: u32,
816 push_object_address,
817 form_tls_address: *const Loc,
818 implicit_value: []const u8,
819 stack_value: *const Loc,
820 wasm_ext: union(enum) {
821 local: u32,
822 global: u32,
823 operand_stack: u32,
824 },
1193825
1194pub fn commitNavState(
1195 self: *Dwarf,
1196 pt: Zcu.PerThread,
1197 nav_index: InternPool.Nav.Index,
1198 sym_addr: u64,
1199 sym_size: u64,
1200 nav_state: *NavState,
1201) !void {
1202 const tracy = trace(@src());
1203 defer tracy.end();
1204
1205 const gpa = self.allocator;
1206 const zcu = pt.zcu;
1207 const ip = &zcu.intern_pool;
1208 const nav = ip.getNav(nav_index);
1209 const target = zcu.navFileScope(nav_index).mod.resolved_target.result;
1210 const target_endian = target.cpu.arch.endian();
826 pub const Bin = struct { *const Loc, *const Loc };
1211827
1212 var dbg_line_buffer = &nav_state.dbg_line;
1213 var dbg_info_buffer = &nav_state.dbg_info;
828 fn getConst(loc: Loc, comptime Int: type) ?Int {
829 return switch (loc) {
830 .constu => |constu| std.math.cast(Int, constu),
831 .consts => |consts| std.math.cast(Int, consts),
832 else => null,
833 };
834 }
1214835
1215 const nav_val = Value.fromInterned(nav.status.resolved.val);
1216 switch (nav_val.typeOf(zcu).zigTypeTag(zcu)) {
1217 .Fn => {
1218 try nav_state.setInlineFunc(nav_val.toIntern());
836 fn getBaseReg(loc: Loc) ?u32 {
837 return switch (loc) {
838 .breg => |breg| breg,
839 else => null,
840 };
841 }
1219842
1220 // Since the Nav is a function, we need to update the .debug_line program.
1221 // Perform the relocations based on vaddr.
1222 switch (self.ptr_width) {
1223 .p32 => {
1224 {
1225 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];
1226 mem.writeInt(u32, ptr, @intCast(sym_addr), target_endian);
1227 }
1228 {
1229 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4];
1230 mem.writeInt(u32, ptr, @intCast(sym_addr), target_endian);
1231 }
1232 },
1233 .p64 => {
1234 {
1235 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8];
1236 mem.writeInt(u64, ptr, sym_addr, target_endian);
1237 }
1238 {
1239 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8];
1240 mem.writeInt(u64, ptr, sym_addr, target_endian);
1241 }
1242 },
1243 }
1244 {
1245 log.debug("relocating subprogram high PC value: {x} => {x}", .{
1246 self.getRelocDbgInfoSubprogramHighPC(),
1247 sym_size,
1248 });
1249 const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];
1250 mem.writeInt(u32, ptr, @intCast(sym_size), target_endian);
1251 }
843 fn writeReg(reg: u32, op0: u8, opx: u8, writer: anytype) @TypeOf(writer).Error!void {
844 if (std.math.cast(u5, reg)) |small_reg| {
845 try writer.writeByte(op0 + small_reg);
846 } else {
847 try writer.writeByte(opx);
848 try uleb128(writer, reg);
849 }
850 }
1252851
1253 try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS.extended_op, 1, DW.LNE.end_sequence });
1254
1255 // Now we have the full contents and may allocate a region to store it.
1256
1257 // This logic is nearly identical to the logic below in `updateNavDebugInfo` for
1258 // `TextBlock` and the .debug_info. If you are editing this logic, you
1259 // probably need to edit that logic too.
1260 const src_fn_index = self.src_fn_navs.get(nav_index).?;
1261 const src_fn = self.getAtomPtr(.src_fn, src_fn_index);
1262 src_fn.len = @intCast(dbg_line_buffer.items.len);
1263
1264 if (self.src_fn_last_index) |last_index| blk: {
1265 if (src_fn_index == last_index) break :blk;
1266 if (src_fn.next_index) |next_index| {
1267 const next = self.getAtomPtr(.src_fn, next_index);
1268 // Update existing function - non-last item.
1269 if (src_fn.off + src_fn.len + min_nop_size > next.off) {
1270 // It grew too big, so we move it to a new location.
1271 if (src_fn.prev_index) |prev_index| {
1272 self.src_fn_free_list.put(gpa, prev_index, {}) catch {};
1273 self.getAtomPtr(.src_fn, prev_index).next_index = src_fn.next_index;
1274 }
1275 next.prev_index = src_fn.prev_index;
1276 src_fn.next_index = null;
1277 // Populate where it used to be with NOPs.
1278 if (self.bin_file.cast(.elf)) |elf_file| {
1279 const debug_line_sect = &elf_file.shdrs.items[elf_file.debug_line_section_index.?];
1280 const file_pos = debug_line_sect.sh_offset + src_fn.off;
1281 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
1282 } else if (self.bin_file.cast(.macho)) |macho_file| {
1283 if (macho_file.base.isRelocatable()) {
1284 const debug_line_sect = &macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?];
1285 const file_pos = debug_line_sect.offset + src_fn.off;
1286 try pwriteDbgLineNops(macho_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
1287 } else {
1288 const d_sym = macho_file.getDebugSymbols().?;
1289 const debug_line_sect = d_sym.getSectionPtr(d_sym.debug_line_section_index.?);
1290 const file_pos = debug_line_sect.offset + src_fn.off;
1291 try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len);
1292 }
1293 } else if (self.bin_file.cast(.wasm)) |wasm_file| {
1294 _ = wasm_file;
1295 // const debug_line = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
1296 // writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len);
1297 } else unreachable;
1298 // TODO Look at the free list before appending at the end.
1299 src_fn.prev_index = last_index;
1300 const last = self.getAtomPtr(.src_fn, last_index);
1301 last.next_index = src_fn_index;
1302 self.src_fn_last_index = src_fn_index;
1303
1304 src_fn.off = last.off + padToIdeal(last.len);
1305 }
1306 } else if (src_fn.prev_index == null) {
1307 // Append new function.
1308 // TODO Look at the free list before appending at the end.
1309 src_fn.prev_index = last_index;
1310 const last = self.getAtomPtr(.src_fn, last_index);
1311 last.next_index = src_fn_index;
1312 self.src_fn_last_index = src_fn_index;
1313
1314 src_fn.off = last.off + padToIdeal(last.len);
852 fn write(loc: Loc, wip: anytype) UpdateError!void {
853 const writer = wip.infoWriter();
854 switch (loc) {
855 .empty => unreachable,
856 .addr => |addr| {
857 try writer.writeByte(DW.OP.addr);
858 switch (addr) {
859 .sym => |sym_index| try wip.addrSym(sym_index),
1315860 }
861 },
862 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
863 try writer.writeByte(@as(u8, DW.OP.lit0) + lit);
864 } else if (std.math.cast(u8, constu)) |const1u| {
865 try writer.writeAll(&.{ DW.OP.const1u, const1u });
866 } else if (std.math.cast(u16, constu)) |const2u| {
867 try writer.writeByte(DW.OP.const2u);
868 try writer.writeInt(u16, const2u, wip.dwarf.endian);
869 } else if (std.math.cast(u21, constu)) |const3u| {
870 try writer.writeByte(DW.OP.constu);
871 try uleb128(writer, const3u);
872 } else if (std.math.cast(u32, constu)) |const4u| {
873 try writer.writeByte(DW.OP.const4u);
874 try writer.writeInt(u32, const4u, wip.dwarf.endian);
875 } else if (std.math.cast(u49, constu)) |const7u| {
876 try writer.writeByte(DW.OP.constu);
877 try uleb128(writer, const7u);
1316878 } else {
1317 // This is the first function of the Line Number Program.
1318 self.src_fn_first_index = src_fn_index;
1319 self.src_fn_last_index = src_fn_index;
1320
1321 src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{}));
1322 }
1323
1324 const last_src_fn_index = self.src_fn_last_index.?;
1325 const last_src_fn = self.getAtom(.src_fn, last_src_fn_index);
1326 const needed_size = last_src_fn.off + last_src_fn.len;
1327 const prev_padding_size: u32 = if (src_fn.prev_index) |prev_index| blk: {
1328 const prev = self.getAtom(.src_fn, prev_index);
1329 break :blk src_fn.off - (prev.off + prev.len);
1330 } else 0;
1331 const next_padding_size: u32 = if (src_fn.next_index) |next_index| blk: {
1332 const next = self.getAtom(.src_fn, next_index);
1333 break :blk next.off - (src_fn.off + src_fn.len);
1334 } else 0;
1335
1336 // We only have support for one compilation unit so far, so the offsets are directly
1337 // from the .debug_line section.
1338 if (self.bin_file.cast(.elf)) |elf_file| {
1339 const shdr_index = elf_file.debug_line_section_index.?;
1340 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
1341 const debug_line_sect = elf_file.shdrs.items[shdr_index];
1342 const file_pos = debug_line_sect.sh_offset + src_fn.off;
1343 try pwriteDbgLineNops(
1344 elf_file.base.file.?,
1345 file_pos,
1346 prev_padding_size,
1347 dbg_line_buffer.items,
1348 next_padding_size,
1349 );
1350 } else if (self.bin_file.cast(.macho)) |macho_file| {
1351 if (macho_file.base.isRelocatable()) {
1352 const sect_index = macho_file.debug_line_sect_index.?;
1353 try macho_file.growSection(sect_index, needed_size);
1354 const sect = macho_file.sections.items(.header)[sect_index];
1355 const file_pos = sect.offset + src_fn.off;
1356 try pwriteDbgLineNops(
1357 macho_file.base.file.?,
1358 file_pos,
1359 prev_padding_size,
1360 dbg_line_buffer.items,
1361 next_padding_size,
1362 );
1363 } else {
1364 const d_sym = macho_file.getDebugSymbols().?;
1365 const sect_index = d_sym.debug_line_section_index.?;
1366 try d_sym.growSection(sect_index, needed_size, true, macho_file);
1367 const sect = d_sym.getSection(sect_index);
1368 const file_pos = sect.offset + src_fn.off;
1369 try pwriteDbgLineNops(
1370 d_sym.file,
1371 file_pos,
1372 prev_padding_size,
1373 dbg_line_buffer.items,
1374 next_padding_size,
1375 );
879 try writer.writeByte(DW.OP.const8u);
880 try writer.writeInt(u64, constu, wip.dwarf.endian);
881 },
882 .consts => |consts| if (std.math.cast(i8, consts)) |const1s| {
883 try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) });
884 } else if (std.math.cast(i16, consts)) |const2s| {
885 try writer.writeByte(DW.OP.const2s);
886 try writer.writeInt(i16, const2s, wip.dwarf.endian);
887 } else if (std.math.cast(i21, consts)) |const3s| {
888 try writer.writeByte(DW.OP.consts);
889 try sleb128(writer, const3s);
890 } else if (std.math.cast(i32, consts)) |const4s| {
891 try writer.writeByte(DW.OP.const4s);
892 try writer.writeInt(i32, const4s, wip.dwarf.endian);
893 } else if (std.math.cast(i49, consts)) |const7s| {
894 try writer.writeByte(DW.OP.consts);
895 try sleb128(writer, const7s);
896 } else {
897 try writer.writeByte(DW.OP.const8s);
898 try writer.writeInt(i64, consts, wip.dwarf.endian);
899 },
900 .plus => |plus| done: {
901 if (plus[0].getConst(u0)) |_| {
902 try plus[1].write(wip);
903 break :done;
904 }
905 if (plus[1].getConst(u0)) |_| {
906 try plus[0].write(wip);
907 break :done;
908 }
909 if (plus[0].getBaseReg()) |breg| {
910 if (plus[1].getConst(i65)) |offset| {
911 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
912 try sleb128(writer, offset);
913 break :done;
914 }
915 }
916 if (plus[1].getBaseReg()) |breg| {
917 if (plus[0].getConst(i65)) |offset| {
918 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
919 try sleb128(writer, offset);
920 break :done;
921 }
922 }
923 if (plus[0].getConst(u64)) |uconst| {
924 try plus[1].write(wip);
925 try writer.writeByte(DW.OP.plus_uconst);
926 try uleb128(writer, uconst);
927 break :done;
928 }
929 if (plus[1].getConst(u64)) |uconst| {
930 try plus[0].write(wip);
931 try writer.writeByte(DW.OP.plus_uconst);
932 try uleb128(writer, uconst);
933 break :done;
934 }
935 try plus[0].write(wip);
936 try plus[1].write(wip);
937 try writer.writeByte(DW.OP.plus);
938 },
939 .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer),
940 .breg => |breg| {
941 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
942 try sleb128(writer, 0);
943 },
944 .push_object_address => try writer.writeByte(DW.OP.push_object_address),
945 .form_tls_address => |addr| {
946 try addr.write(wip);
947 try writer.writeByte(DW.OP.form_tls_address);
948 },
949 .implicit_value => |value| {
950 try writer.writeByte(DW.OP.implicit_value);
951 try uleb128(writer, value.len);
952 try writer.writeAll(value);
953 },
954 .stack_value => |value| {
955 try value.write(wip);
956 try writer.writeByte(DW.OP.stack_value);
957 },
958 .wasm_ext => |wasm_ext| {
959 try writer.writeByte(DW.OP.WASM_location);
960 switch (wasm_ext) {
961 .local => |local| {
962 try writer.writeByte(DW.OP.WASM_local);
963 try uleb128(writer, local);
964 },
965 .global => |global| if (std.math.cast(u21, global)) |global_u21| {
966 try writer.writeByte(DW.OP.WASM_global);
967 try uleb128(writer, global_u21);
968 } else {
969 try writer.writeByte(DW.OP.WASM_global_u32);
970 try writer.writeInt(u32, global, wip.dwarf.endian);
971 },
972 .operand_stack => |operand_stack| {
973 try writer.writeByte(DW.OP.WASM_operand_stack);
974 try uleb128(writer, operand_stack);
975 },
1376976 }
1377 } else if (self.bin_file.cast(.wasm)) |wasm_file| {
1378 _ = wasm_file;
1379 // const atom = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?);
1380 // const debug_line = &atom.code;
1381 // const segment_size = debug_line.items.len;
1382 // if (needed_size != segment_size) {
1383 // log.debug(" needed size does not equal allocated size: {d}", .{needed_size});
1384 // if (needed_size > segment_size) {
1385 // log.debug(" allocating {d} bytes for 'debug line' information", .{needed_size - segment_size});
1386 // try debug_line.resize(self.allocator, needed_size);
1387 // @memset(debug_line.items[segment_size..], 0);
1388 // }
1389 // debug_line.items.len = needed_size;
1390 // }
1391 // writeDbgLineNopsBuffered(
1392 // debug_line.items,
1393 // src_fn.off,
1394 // prev_padding_size,
1395 // dbg_line_buffer.items,
1396 // next_padding_size,
1397 // );
1398 } else unreachable;
1399
1400 // .debug_info - End the TAG.subprogram children.
1401 try dbg_info_buffer.append(0);
1402 },
1403 else => {},
1404 }
1405
1406 if (dbg_info_buffer.items.len == 0)
1407 return;
1408
1409 const di_atom_index = self.di_atom_navs.get(nav_index).?;
1410 if (nav_state.abbrev_table.items.len > 0) {
1411 // Now we emit the .debug_info types of the Nav. These will count towards the size of
1412 // the buffer, so we have to do it before computing the offset, and we can't perform the actual
1413 // relocations yet.
1414 var sym_index: usize = 0;
1415 while (sym_index < nav_state.abbrev_table.items.len) : (sym_index += 1) {
1416 const symbol = &nav_state.abbrev_table.items[sym_index];
1417 const ty = symbol.type;
1418 if (ip.isErrorSetType(ty.toIntern())) continue;
1419
1420 symbol.offset = @intCast(dbg_info_buffer.items.len);
1421 try nav_state.addDbgInfoType(pt, di_atom_index, ty);
977 },
1422978 }
1423979 }
980};
1424981
1425 try self.updateNavDebugInfoAllocation(di_atom_index, @intCast(dbg_info_buffer.items.len));
982pub const WipNav = struct {
983 dwarf: *Dwarf,
984 pt: Zcu.PerThread,
985 unit: Unit.Index,
986 entry: Entry.Index,
987 any_children: bool,
988 func: InternPool.Index,
989 func_high_reloc: u32,
990 debug_info: std.ArrayListUnmanaged(u8),
991 debug_line: std.ArrayListUnmanaged(u8),
992 debug_loclists: std.ArrayListUnmanaged(u8),
993 pending_types: std.ArrayListUnmanaged(InternPool.Index),
994
995 pub fn deinit(wip_nav: *WipNav) void {
996 const gpa = wip_nav.dwarf.gpa;
997 wip_nav.debug_info.deinit(gpa);
998 wip_nav.debug_line.deinit(gpa);
999 wip_nav.debug_loclists.deinit(gpa);
1000 wip_nav.pending_types.deinit(gpa);
1001 }
14261002
1427 while (nav_state.abbrev_relocs.popOrNull()) |reloc| {
1428 if (reloc.target) |reloc_target| {
1429 const symbol = nav_state.abbrev_table.items[reloc_target];
1430 const ty = symbol.type;
1431 if (ip.isErrorSetType(ty.toIntern())) {
1432 log.debug("resolving %{d} deferred until flush", .{reloc_target});
1433 try self.global_abbrev_relocs.append(gpa, .{
1434 .target = null,
1435 .offset = reloc.offset,
1436 .atom_index = reloc.atom_index,
1437 .addend = reloc.addend,
1438 });
1439 } else {
1440 const atom = self.getAtom(.di_atom, symbol.atom_index);
1441 const value = atom.off + symbol.offset + reloc.addend;
1442 log.debug("{x}: [() => {x}] (%{d}, '{}')", .{
1443 reloc.offset,
1444 value,
1445 reloc_target,
1446 ty.fmt(pt),
1447 });
1448 mem.writeInt(
1449 u32,
1450 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
1451 value,
1452 target_endian,
1453 );
1454 }
1455 } else {
1456 const atom = self.getAtom(.di_atom, reloc.atom_index);
1457 mem.writeInt(
1458 u32,
1459 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
1460 atom.off + reloc.offset + reloc.addend,
1461 target_endian,
1462 );
1463 }
1003 pub fn infoWriter(wip_nav: *WipNav) std.ArrayListUnmanaged(u8).Writer {
1004 return wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
14641005 }
14651006
1466 while (nav_state.exprloc_relocs.popOrNull()) |reloc| {
1467 if (self.bin_file.cast(.elf)) |elf_file| {
1468 _ = elf_file; // TODO
1469 } else if (self.bin_file.cast(.macho)) |macho_file| {
1470 if (macho_file.base.isRelocatable()) {
1471 // TODO
1472 } else {
1473 const d_sym = macho_file.getDebugSymbols().?;
1474 try d_sym.relocs.append(d_sym.allocator, .{
1475 .type = switch (reloc.type) {
1476 .direct_load => .direct_load,
1477 .got_load => .got_load,
1478 },
1479 .target = reloc.target,
1480 .offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off,
1481 .addend = 0,
1482 });
1483 }
1484 } else unreachable;
1007 pub const VarTag = enum { local_arg, local_var };
1008 pub fn genVarDebugInfo(
1009 wip_nav: *WipNav,
1010 tag: VarTag,
1011 name: []const u8,
1012 ty: Type,
1013 loc: Loc,
1014 ) UpdateError!void {
1015 wip_nav.any_children = true;
1016 assert(wip_nav.func != .none);
1017 const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
1018 try uleb128(diw, @intFromEnum(switch (tag) {
1019 inline else => |ct_tag| @field(AbbrevCode, @tagName(ct_tag)),
1020 }));
1021 try wip_nav.strp(name);
1022 try wip_nav.refType(ty);
1023 try wip_nav.exprloc(loc);
14851024 }
14861025
1487 try self.writeNavDebugInfo(di_atom_index, dbg_info_buffer.items);
1488}
1026 pub fn advancePCAndLine(
1027 wip_nav: *WipNav,
1028 delta_line: i33,
1029 delta_pc: u64,
1030 ) error{OutOfMemory}!void {
1031 const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
14891032
1490fn updateNavDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32) !void {
1491 const tracy = trace(@src());
1492 defer tracy.end();
1493
1494 // This logic is nearly identical to the logic above in `updateNav` for
1495 // `SrcFn` and the line number programs. If you are editing this logic, you
1496 // probably need to edit that logic too.
1497 const gpa = self.allocator;
1498
1499 const atom = self.getAtomPtr(.di_atom, atom_index);
1500 atom.len = len;
1501 if (self.di_atom_last_index) |last_index| blk: {
1502 if (atom_index == last_index) break :blk;
1503 if (atom.next_index) |next_index| {
1504 const next = self.getAtomPtr(.di_atom, next_index);
1505 // Update existing Nav - non-last item.
1506 if (atom.off + atom.len + min_nop_size > next.off) {
1507 // It grew too big, so we move it to a new location.
1508 if (atom.prev_index) |prev_index| {
1509 self.di_atom_free_list.put(gpa, prev_index, {}) catch {};
1510 self.getAtomPtr(.di_atom, prev_index).next_index = atom.next_index;
1511 }
1512 next.prev_index = atom.prev_index;
1513 atom.next_index = null;
1514 // Populate where it used to be with NOPs.
1515 if (self.bin_file.cast(.elf)) |elf_file| {
1516 const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?];
1517 const file_pos = debug_info_sect.sh_offset + atom.off;
1518 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
1519 } else if (self.bin_file.cast(.macho)) |macho_file| {
1520 if (macho_file.base.isRelocatable()) {
1521 const debug_info_sect = macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?];
1522 const file_pos = debug_info_sect.offset + atom.off;
1523 try pwriteDbgInfoNops(macho_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
1524 } else {
1525 const d_sym = macho_file.getDebugSymbols().?;
1526 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
1527 const file_pos = debug_info_sect.offset + atom.off;
1528 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false);
1529 }
1530 } else if (self.bin_file.cast(.wasm)) |wasm_file| {
1531 _ = wasm_file;
1532 // const debug_info_index = wasm_file.debug_info_atom.?;
1533 // const debug_info = &wasm_file.getAtomPtr(debug_info_index).code;
1534 // try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false);
1535 } else unreachable;
1536 // TODO Look at the free list before appending at the end.
1537 atom.prev_index = last_index;
1538 const last = self.getAtomPtr(.di_atom, last_index);
1539 last.next_index = atom_index;
1540 self.di_atom_last_index = atom_index;
1541
1542 atom.off = last.off + padToIdeal(last.len);
1543 }
1544 } else if (atom.prev_index == null) {
1545 // Append new Nav.
1546 // TODO Look at the free list before appending at the end.
1547 atom.prev_index = last_index;
1548 const last = self.getAtomPtr(.di_atom, last_index);
1549 last.next_index = atom_index;
1550 self.di_atom_last_index = atom_index;
1551
1552 atom.off = last.off + padToIdeal(last.len);
1553 }
1554 } else {
1555 // This is the first Nav of the .debug_info
1556 self.di_atom_first_index = atom_index;
1557 self.di_atom_last_index = atom_index;
1033 const header = wip_nav.dwarf.debug_line.header;
1034 assert(header.maximum_operations_per_instruction == 1);
1035 const delta_op: u64 = 0;
15581036
1559 atom.off = @intCast(padToIdeal(self.dbgInfoHeaderBytes()));
1037 const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or
1038 delta_line - header.line_base >= header.line_range)
1039 remaining: {
1040 assert(delta_line != 0);
1041 try dlw.writeByte(DW.LNS.advance_line);
1042 try sleb128(dlw, delta_line);
1043 break :remaining 0;
1044 } else delta_line);
1045
1046 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
1047 header.maximum_operations_per_instruction + delta_op;
1048 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
1049 const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: {
1050 try dlw.writeByte(DW.LNS.advance_pc);
1051 try uleb128(dlw, op_advance);
1052 break :remaining 0;
1053 } else if (op_advance >= max_op_advance) remaining: {
1054 try dlw.writeByte(DW.LNS.const_add_pc);
1055 break :remaining op_advance - max_op_advance;
1056 } else op_advance);
1057
1058 if (remaining_delta_line == 0 and remaining_op_advance == 0)
1059 try dlw.writeByte(DW.LNS.copy)
1060 else
1061 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +
1062 (header.line_range * remaining_op_advance) + header.opcode_base));
15601063 }
1561}
15621064
1563fn writeNavDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []const u8) !void {
1564 const tracy = trace(@src());
1565 defer tracy.end();
1566
1567 // This logic is nearly identical to the logic above in `updateNav` for
1568 // `SrcFn` and the line number programs. If you are editing this logic, you
1569 // probably need to edit that logic too.
1570
1571 const atom = self.getAtom(.di_atom, atom_index);
1572 const last_nav_index = self.di_atom_last_index.?;
1573 const last_nav = self.getAtom(.di_atom, last_nav_index);
1574 // +1 for a trailing zero to end the children of the nav tag.
1575 const needed_size = last_nav.off + last_nav.len + 1;
1576 const prev_padding_size: u32 = if (atom.prev_index) |prev_index| blk: {
1577 const prev = self.getAtom(.di_atom, prev_index);
1578 break :blk atom.off - (prev.off + prev.len);
1579 } else 0;
1580 const next_padding_size: u32 = if (atom.next_index) |next_index| blk: {
1581 const next = self.getAtom(.di_atom, next_index);
1582 break :blk next.off - (atom.off + atom.len);
1583 } else 0;
1584
1585 // To end the children of the nav tag.
1586 const trailing_zero = atom.next_index == null;
1587
1588 // We only have support for one compilation unit so far, so the offsets are directly
1589 // from the .debug_info section.
1590 if (self.bin_file.cast(.elf)) |elf_file| {
1591 const shdr_index = elf_file.debug_info_section_index.?;
1592 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
1593 const debug_info_sect = &elf_file.shdrs.items[shdr_index];
1594 const file_pos = debug_info_sect.sh_offset + atom.off;
1595 try pwriteDbgInfoNops(
1596 elf_file.base.file.?,
1597 file_pos,
1598 prev_padding_size,
1599 dbg_info_buf,
1600 next_padding_size,
1601 trailing_zero,
1602 );
1603 } else if (self.bin_file.cast(.macho)) |macho_file| {
1604 if (macho_file.base.isRelocatable()) {
1605 const sect_index = macho_file.debug_info_sect_index.?;
1606 try macho_file.growSection(sect_index, needed_size);
1607 const sect = macho_file.sections.items(.header)[sect_index];
1608 const file_pos = sect.offset + atom.off;
1609 try pwriteDbgInfoNops(
1610 macho_file.base.file.?,
1611 file_pos,
1612 prev_padding_size,
1613 dbg_info_buf,
1614 next_padding_size,
1615 trailing_zero,
1616 );
1617 } else {
1618 const d_sym = macho_file.getDebugSymbols().?;
1619 const sect_index = d_sym.debug_info_section_index.?;
1620 try d_sym.growSection(sect_index, needed_size, true, macho_file);
1621 const sect = d_sym.getSection(sect_index);
1622 const file_pos = sect.offset + atom.off;
1623 try pwriteDbgInfoNops(
1624 d_sym.file,
1625 file_pos,
1626 prev_padding_size,
1627 dbg_info_buf,
1628 next_padding_size,
1629 trailing_zero,
1630 );
1631 }
1632 } else if (self.bin_file.cast(.wasm)) |wasm_file| {
1633 _ = wasm_file;
1634 // const info_atom = wasm_file.debug_info_atom.?;
1635 // const debug_info = &wasm_file.getAtomPtr(info_atom).code;
1636 // const segment_size = debug_info.items.len;
1637 // if (needed_size != segment_size) {
1638 // log.debug(" needed size does not equal allocated size: {d}", .{needed_size});
1639 // if (needed_size > segment_size) {
1640 // log.debug(" allocating {d} bytes for 'debug info' information", .{needed_size - segment_size});
1641 // try debug_info.resize(self.allocator, needed_size);
1642 // @memset(debug_info.items[segment_size..], 0);
1643 // }
1644 // debug_info.items.len = needed_size;
1645 // }
1646 // log.debug(" writeDbgInfoNopsToArrayList debug_info_len={d} offset={d} content_len={d} next_padding_size={d}", .{
1647 // debug_info.items.len, atom.off, dbg_info_buf.len, next_padding_size,
1648 // });
1649 // try writeDbgInfoNopsToArrayList(
1650 // gpa,
1651 // debug_info,
1652 // atom.off,
1653 // prev_padding_size,
1654 // dbg_info_buf,
1655 // next_padding_size,
1656 // trailing_zero,
1657 // );
1658 } else unreachable;
1659}
1065 pub fn setColumn(wip_nav: *WipNav, column: u32) error{OutOfMemory}!void {
1066 const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
1067 try dlw.writeByte(DW.LNS.set_column);
1068 try uleb128(dlw, column + 1);
1069 }
16601070
1661pub fn updateNavLineNumber(self: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !void {
1662 const tracy = trace(@src());
1663 defer tracy.end();
1664
1665 const atom_index = try self.getOrCreateAtomForNav(.src_fn, nav_index);
1666 const atom = self.getAtom(.src_fn, atom_index);
1667 if (atom.len == 0) return;
1668
1669 const nav = zcu.intern_pool.getNav(nav_index);
1670 const nav_val = Value.fromInterned(nav.status.resolved.val);
1671 const func = nav_val.getFunction(zcu).?;
1672 log.debug("src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{
1673 zcu.navSrcLine(nav_index),
1674 func.lbrace_line,
1675 func.rbrace_line,
1676 });
1677 const line: u28 = @intCast(zcu.navSrcLine(nav_index) + func.lbrace_line);
1678 var data: [4]u8 = undefined;
1679 leb128.writeUnsignedFixed(4, &data, line);
1680
1681 switch (self.bin_file.tag) {
1682 .elf => {
1683 const elf_file = self.bin_file.cast(File.Elf).?;
1684 const shdr = elf_file.shdrs.items[elf_file.debug_line_section_index.?];
1685 const file_pos = shdr.sh_offset + atom.off + self.getRelocDbgLineOff();
1686 try elf_file.base.file.?.pwriteAll(&data, file_pos);
1687 },
1688 .macho => {
1689 const macho_file = self.bin_file.cast(File.MachO).?;
1690 if (macho_file.base.isRelocatable()) {
1691 const sect = macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?];
1692 const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff();
1693 try macho_file.base.file.?.pwriteAll(&data, file_pos);
1694 } else {
1695 const d_sym = macho_file.getDebugSymbols().?;
1696 const sect = d_sym.getSection(d_sym.debug_line_section_index.?);
1697 const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff();
1698 try d_sym.file.pwriteAll(&data, file_pos);
1699 }
1700 },
1701 .wasm => {
1702 // const wasm_file = self.bin_file.cast(File.Wasm).?;
1703 // const offset = atom.off + self.getRelocDbgLineOff();
1704 // const line_atom_index = wasm_file.debug_line_atom.?;
1705 // wasm_file.getAtomPtr(line_atom_index).code.items[offset..][0..data.len].* = data;
1706 },
1707 else => unreachable,
1071 pub fn setPrologueEnd(wip_nav: *WipNav) error{OutOfMemory}!void {
1072 const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
1073 try dlw.writeByte(DW.LNS.set_prologue_end);
17081074 }
1709}
17101075
1711pub fn freeNav(self: *Dwarf, nav_index: InternPool.Nav.Index) void {
1712 const gpa = self.allocator;
1713
1714 // Free SrcFn atom
1715 if (self.src_fn_navs.fetchRemove(nav_index)) |kv| {
1716 const src_fn_index = kv.value;
1717 const src_fn = self.getAtom(.src_fn, src_fn_index);
1718 _ = self.src_fn_free_list.remove(src_fn_index);
1719
1720 if (src_fn.prev_index) |prev_index| {
1721 self.src_fn_free_list.put(gpa, prev_index, {}) catch {};
1722 const prev = self.getAtomPtr(.src_fn, prev_index);
1723 prev.next_index = src_fn.next_index;
1724 if (src_fn.next_index) |next_index| {
1725 self.getAtomPtr(.src_fn, next_index).prev_index = prev_index;
1726 } else {
1727 self.src_fn_last_index = prev_index;
1728 }
1729 } else if (src_fn.next_index) |next_index| {
1730 self.src_fn_first_index = next_index;
1731 self.getAtomPtr(.src_fn, next_index).prev_index = null;
1732 }
1733 if (self.src_fn_first_index == src_fn_index) {
1734 self.src_fn_first_index = src_fn.next_index;
1735 }
1736 if (self.src_fn_last_index == src_fn_index) {
1737 self.src_fn_last_index = src_fn.prev_index;
1738 }
1076 pub fn setEpilogueBegin(wip_nav: *WipNav) error{OutOfMemory}!void {
1077 const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
1078 try dlw.writeByte(DW.LNS.set_epilogue_begin);
17391079 }
17401080
1741 // Free DI atom
1742 if (self.di_atom_navs.fetchRemove(nav_index)) |kv| {
1743 const di_atom_index = kv.value;
1744 const di_atom = self.getAtomPtr(.di_atom, di_atom_index);
1081 pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void {
1082 const zcu = wip_nav.pt.zcu;
1083 const dwarf = wip_nav.dwarf;
1084 if (wip_nav.func == func) return;
17451085
1746 if (self.di_atom_first_index == di_atom_index) {
1747 self.di_atom_first_index = di_atom.next_index;
1748 }
1749 if (self.di_atom_last_index == di_atom_index) {
1750 // TODO shrink the .debug_info section size here
1751 self.di_atom_last_index = di_atom.prev_index;
1086 const new_func_info = zcu.funcInfo(func);
1087 const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav);
1088 const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod);
1089
1090 const dlw = wip_nav.debug_line.writer(dwarf.gpa);
1091 if (dwarf.incremental()) {
1092 const new_nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, new_func_info.owner_nav);
1093 errdefer _ = dwarf.navs.pop();
1094 if (!new_nav_gop.found_existing) new_nav_gop.value_ptr.* = try dwarf.addCommonEntry(new_unit);
1095
1096 try dlw.writeByte(DW.LNS.extended_op);
1097 try uleb128(dlw, 1 + dwarf.sectionOffsetBytes());
1098 try dlw.writeByte(DW.LNE.ZIG_set_decl);
1099 try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{
1100 .source_entry = wip_nav.entry.toOptional(),
1101 .source_off = @intCast(wip_nav.debug_line.items.len),
1102 .target_sec = .debug_info,
1103 .target_unit = new_unit,
1104 .target_entry = new_nav_gop.value_ptr.toOptional(),
1105 });
1106 try dlw.writeByteNTimes(0, dwarf.sectionOffsetBytes());
1107 return;
17521108 }
17531109
1754 if (di_atom.prev_index) |prev_index| {
1755 self.getAtomPtr(.di_atom, prev_index).next_index = di_atom.next_index;
1756 // TODO the free list logic like we do for SrcFn above
1757 } else {
1758 di_atom.prev_index = null;
1110 const old_func_info = zcu.funcInfo(wip_nav.func);
1111 const old_file = zcu.navFileScopeIndex(old_func_info.owner_nav);
1112 if (old_file != new_file) {
1113 const mod_info = dwarf.getModInfo(wip_nav.unit);
1114 const mod_gop = try mod_info.dirs.getOrPut(dwarf.gpa, new_unit);
1115 errdefer _ = if (!mod_gop.found_existing) mod_info.dirs.pop();
1116 const file_gop = try mod_info.files.getOrPut(dwarf.gpa, new_file);
1117 errdefer _ = if (!file_gop.found_existing) mod_info.files.pop();
1118
1119 try dlw.writeByte(DW.LNS.set_file);
1120 try uleb128(dlw, file_gop.index);
17591121 }
17601122
1761 if (di_atom.next_index) |next_index| {
1762 self.getAtomPtr(.di_atom, next_index).prev_index = di_atom.prev_index;
1763 } else {
1764 di_atom.next_index = null;
1123 const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav);
1124 const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav);
1125 if (new_src_line != old_src_line) {
1126 try dlw.writeByte(DW.LNS.advance_line);
1127 try sleb128(dlw, new_src_line - old_src_line);
17651128 }
1129
1130 wip_nav.func = func;
17661131 }
1767}
17681132
1769pub fn writeDbgAbbrev(self: *Dwarf) !void {
1770 // These are LEB encoded but since the values are all less than 127
1771 // we can simply append these bytes.
1772 // zig fmt: off
1773 const abbrev_buf = [_]u8{
1774 @intFromEnum(AbbrevCode.padding),
1775 @as(u8, 0x80) | @as(u7, @truncate(DW.TAG.ZIG_padding >> 0)),
1776 @as(u8, 0x80) | @as(u7, @truncate(DW.TAG.ZIG_padding >> 7)),
1777 @as(u8, 0x00) | @as(u7, @intCast(DW.TAG.ZIG_padding >> 14)),
1778 DW.CHILDREN.no,
1779 0, 0,
1780
1781 @intFromEnum(AbbrevCode.compile_unit),
1782 DW.TAG.compile_unit,
1783 DW.CHILDREN.yes,
1784 DW.AT.stmt_list, DW.FORM.sec_offset,
1785 DW.AT.low_pc, DW.FORM.addr,
1786 DW.AT.high_pc, DW.FORM.addr,
1787 DW.AT.name, DW.FORM.strp,
1788 DW.AT.comp_dir, DW.FORM.strp,
1789 DW.AT.producer, DW.FORM.strp,
1790 DW.AT.language, DW.FORM.data2,
1791 0, 0,
1792
1793 @intFromEnum(AbbrevCode.subprogram),
1794 DW.TAG.subprogram,
1795 DW.CHILDREN.yes,
1796 DW.AT.low_pc, DW.FORM.addr,
1797 DW.AT.high_pc, DW.FORM.data4,
1798 DW.AT.type, DW.FORM.ref4,
1799 DW.AT.name, DW.FORM.string,
1800 DW.AT.linkage_name, DW.FORM.string,
1801 0, 0,
1802
1803 @intFromEnum(AbbrevCode.subprogram_retvoid),
1804 DW.TAG.subprogram,
1805 DW.CHILDREN.yes,
1806 DW.AT.low_pc, DW.FORM.addr,
1807 DW.AT.high_pc, DW.FORM.data4,
1808 DW.AT.name, DW.FORM.string,
1809 DW.AT.linkage_name, DW.FORM.string,
1810 0, 0,
1811
1812 @intFromEnum(AbbrevCode.base_type),
1813 DW.TAG.base_type, DW.CHILDREN.no,
1814 DW.AT.encoding, DW.FORM.data1,
1815 DW.AT.byte_size, DW.FORM.udata,
1816 DW.AT.name, DW.FORM.string,
1817 0, 0,
1818
1819 @intFromEnum(AbbrevCode.ptr_type),
1820 DW.TAG.pointer_type, DW.CHILDREN.no,
1821 DW.AT.type, DW.FORM.ref4,
1822 0, 0,
1823
1824 @intFromEnum(AbbrevCode.struct_type),
1825 DW.TAG.structure_type, DW.CHILDREN.yes,
1826 DW.AT.byte_size, DW.FORM.udata,
1827 DW.AT.name, DW.FORM.string,
1828 0, 0,
1829
1830 @intFromEnum(AbbrevCode.struct_member),
1831 DW.TAG.member,
1832 DW.CHILDREN.no,
1833 DW.AT.name, DW.FORM.string,
1834 DW.AT.type, DW.FORM.ref4,
1835 DW.AT.data_member_location, DW.FORM.udata,
1836 0, 0,
1837
1838 @intFromEnum(AbbrevCode.enum_type),
1839 DW.TAG.enumeration_type,
1840 DW.CHILDREN.yes,
1841 DW.AT.byte_size, DW.FORM.udata,
1842 DW.AT.name, DW.FORM.string,
1843 0, 0,
1844
1845 @intFromEnum(AbbrevCode.enum_variant),
1846 DW.TAG.enumerator, DW.CHILDREN.no,
1847 DW.AT.name, DW.FORM.string,
1848 DW.AT.const_value, DW.FORM.data8,
1849 0, 0,
1850
1851 @intFromEnum(AbbrevCode.union_type),
1852 DW.TAG.union_type, DW.CHILDREN.yes,
1853 DW.AT.byte_size, DW.FORM.udata,
1854 DW.AT.name, DW.FORM.string,
1855 0, 0,
1856
1857 @intFromEnum(AbbrevCode.zero_bit_type),
1858 DW.TAG.unspecified_type,
1859 DW.CHILDREN.no,
1860 0, 0,
1861
1862 @intFromEnum(AbbrevCode.parameter),
1863 DW.TAG.formal_parameter,
1864 DW.CHILDREN.no,
1865 DW.AT.location, DW.FORM.exprloc,
1866 DW.AT.type, DW.FORM.ref4,
1867 DW.AT.name, DW.FORM.string,
1868 0, 0,
1869
1870 @intFromEnum(AbbrevCode.variable),
1871 DW.TAG.variable,
1872 DW.CHILDREN.no,
1873 DW.AT.location, DW.FORM.exprloc,
1874 DW.AT.type, DW.FORM.ref4,
1875 DW.AT.name, DW.FORM.string,
1876 0, 0,
1877
1878 @intFromEnum(AbbrevCode.array_type),
1879 DW.TAG.array_type,
1880 DW.CHILDREN.yes,
1881 DW.AT.name, DW.FORM.string,
1882 DW.AT.type, DW.FORM.ref4,
1883 0, 0,
1884
1885 @intFromEnum(AbbrevCode.array_dim),
1886 DW.TAG.subrange_type,
1887 DW.CHILDREN.no,
1888 DW.AT.type, DW.FORM.ref4,
1889 DW.AT.count, DW.FORM.udata,
1890 0, 0,
1891
1892 0,
1893 };
1894 // zig fmt: on
1895 const abbrev_offset = 0;
1896 self.abbrev_table_offset = abbrev_offset;
1897
1898 const needed_size = abbrev_buf.len;
1899 if (self.bin_file.cast(.elf)) |elf_file| {
1900 const shdr_index = elf_file.debug_abbrev_section_index.?;
1901 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, false);
1902 const debug_abbrev_sect = &elf_file.shdrs.items[shdr_index];
1903 const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset;
1904 try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
1905 } else if (self.bin_file.cast(.macho)) |macho_file| {
1906 if (macho_file.base.isRelocatable()) {
1907 const sect_index = macho_file.debug_abbrev_sect_index.?;
1908 try macho_file.growSection(sect_index, needed_size);
1909 const sect = macho_file.sections.items(.header)[sect_index];
1910 const file_pos = sect.offset + abbrev_offset;
1911 try macho_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
1133 fn infoSectionOffset(wip_nav: *WipNav, sec: Section.Index, unit: Unit.Index, entry: Entry.Index, off: u32) UpdateError!void {
1134 const dwarf = wip_nav.dwarf;
1135 const gpa = dwarf.gpa;
1136 if (sec != .debug_info) {
1137 try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_section_relocs.append(gpa, .{
1138 .source_entry = wip_nav.entry.toOptional(),
1139 .source_off = @intCast(wip_nav.debug_info.items.len),
1140 .target_sec = sec,
1141 .target_unit = unit,
1142 .target_entry = entry.toOptional(),
1143 .target_off = off,
1144 });
1145 } else if (unit != wip_nav.unit) {
1146 try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_unit_relocs.append(gpa, .{
1147 .source_entry = wip_nav.entry.toOptional(),
1148 .source_off = @intCast(wip_nav.debug_info.items.len),
1149 .target_unit = unit,
1150 .target_entry = entry.toOptional(),
1151 .target_off = off,
1152 });
19121153 } else {
1913 const d_sym = macho_file.getDebugSymbols().?;
1914 const sect_index = d_sym.debug_abbrev_section_index.?;
1915 try d_sym.growSection(sect_index, needed_size, false, macho_file);
1916 const sect = d_sym.getSection(sect_index);
1917 const file_pos = sect.offset + abbrev_offset;
1918 try d_sym.file.pwriteAll(&abbrev_buf, file_pos);
1154 try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.append(gpa, .{
1155 .source_entry = wip_nav.entry.toOptional(),
1156 .source_off = @intCast(wip_nav.debug_info.items.len),
1157 .target_entry = entry,
1158 .target_off = off,
1159 });
19191160 }
1920 } else if (self.bin_file.cast(.wasm)) |wasm_file| {
1921 _ = wasm_file;
1922 // const debug_abbrev = &wasm_file.getAtomPtr(wasm_file.debug_abbrev_atom.?).code;
1923 // try debug_abbrev.resize(gpa, needed_size);
1924 // debug_abbrev.items[0..abbrev_buf.len].* = abbrev_buf;
1925 } else unreachable;
1926}
1927
1928fn dbgInfoHeaderBytes(self: *Dwarf) usize {
1929 _ = self;
1930 return 120;
1931}
1161 try wip_nav.debug_info.appendNTimes(gpa, 0, dwarf.sectionOffsetBytes());
1162 }
19321163
1933pub fn writeDbgInfoHeader(self: *Dwarf, zcu: *Zcu, low_pc: u64, high_pc: u64) !void {
1934 // If this value is null it means there is an error in the module;
1935 // leave debug_info_header_dirty=true.
1936 const first_dbg_info_off = self.getDebugInfoOff() orelse return;
1164 fn strp(wip_nav: *WipNav, str: []const u8) UpdateError!void {
1165 try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0);
1166 }
19371167
1938 // We have a function to compute the upper bound size, because it's needed
1939 // for determining where to put the offset of the first `LinkBlock`.
1940 const needed_bytes = self.dbgInfoHeaderBytes();
1941 var di_buf = try std.ArrayList(u8).initCapacity(self.allocator, needed_bytes);
1942 defer di_buf.deinit();
1168 fn addrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void {
1169 const dwarf = wip_nav.dwarf;
1170 try dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{
1171 .source_entry = wip_nav.entry,
1172 .source_off = @intCast(wip_nav.debug_info.items.len),
1173 .target_sym = sym_index,
1174 });
1175 try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, @intFromEnum(dwarf.address_size));
1176 }
19431177
1944 const comp = self.bin_file.comp;
1945 const target = comp.root_mod.resolved_target.result;
1946 const target_endian = target.cpu.arch.endian();
1947 const init_len_size: usize = switch (self.format) {
1948 .dwarf32 => 4,
1949 .dwarf64 => 12,
1950 };
1178 fn exprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
1179 if (loc == .empty) return;
1180 var wip: struct {
1181 const Info = std.io.CountingWriter(std.io.NullWriter);
1182 dwarf: *Dwarf,
1183 debug_info: Info,
1184 fn infoWriter(wip: *@This()) Info.Writer {
1185 return wip.debug_info.writer();
1186 }
1187 fn addrSym(wip: *@This(), _: u32) error{}!void {
1188 wip.debug_info.bytes_written += @intFromEnum(wip.dwarf.address_size);
1189 }
1190 } = .{
1191 .dwarf = wip_nav.dwarf,
1192 .debug_info = std.io.countingWriter(std.io.null_writer),
1193 };
1194 try loc.write(&wip);
1195 try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), wip.debug_info.bytes_written);
1196 try loc.write(wip_nav);
1197 }
19511198
1952 // initial length - length of the .debug_info contribution for this compilation unit,
1953 // not including the initial length itself.
1954 // We have to come back and write it later after we know the size.
1955 const after_init_len = di_buf.items.len + init_len_size;
1956 const dbg_info_end = self.getDebugInfoEnd().?;
1957 const init_len = dbg_info_end - after_init_len + 1;
1958
1959 if (self.format == .dwarf64) di_buf.appendNTimesAssumeCapacity(0xff, 4);
1960 self.writeOffsetAssumeCapacity(&di_buf, init_len);
1961
1962 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version
1963 const abbrev_offset = self.abbrev_table_offset.?;
1964
1965 self.writeOffsetAssumeCapacity(&di_buf, abbrev_offset);
1966 di_buf.appendAssumeCapacity(self.ptrWidthBytes()); // address size
1967
1968 // Write the form for the compile unit, which must match the abbrev table above.
1969 const name_strp = try self.strtab.insert(self.allocator, zcu.root_mod.root_src_path);
1970 var compile_unit_dir_buffer: [std.fs.max_path_bytes]u8 = undefined;
1971 const compile_unit_dir = resolveCompilationDir(zcu, &compile_unit_dir_buffer);
1972 const comp_dir_strp = try self.strtab.insert(self.allocator, compile_unit_dir);
1973 const producer_strp = try self.strtab.insert(self.allocator, link.producer_string);
1974
1975 di_buf.appendAssumeCapacity(@intFromEnum(AbbrevCode.compile_unit));
1976 self.writeOffsetAssumeCapacity(&di_buf, 0); // DW.AT.stmt_list, DW.FORM.sec_offset
1977 self.writeAddrAssumeCapacity(&di_buf, low_pc);
1978 self.writeAddrAssumeCapacity(&di_buf, high_pc);
1979 self.writeOffsetAssumeCapacity(&di_buf, name_strp);
1980 self.writeOffsetAssumeCapacity(&di_buf, comp_dir_strp);
1981 self.writeOffsetAssumeCapacity(&di_buf, producer_strp);
1982
1983 // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number:
1984 // http://dwarfstd.org/ShowIssue.php?issue=171115.1
1985 // Until then we say it is C99.
1986 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG.C99, target_endian);
1987
1988 if (di_buf.items.len > first_dbg_info_off) {
1989 // Move the first N navs to the end to make more padding for the header.
1990 @panic("TODO: handle .debug_info header exceeding its padding");
1991 }
1992 const jmp_amt = first_dbg_info_off - di_buf.items.len;
1993 if (self.bin_file.cast(.elf)) |elf_file| {
1994 const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?];
1995 const file_pos = debug_info_sect.sh_offset;
1996 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
1997 } else if (self.bin_file.cast(.macho)) |macho_file| {
1998 if (macho_file.base.isRelocatable()) {
1999 const debug_info_sect = macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?];
2000 const file_pos = debug_info_sect.offset;
2001 try pwriteDbgInfoNops(macho_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
2002 } else {
2003 const d_sym = macho_file.getDebugSymbols().?;
2004 const debug_info_sect = d_sym.getSection(d_sym.debug_info_section_index.?);
2005 const file_pos = debug_info_sect.offset;
2006 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false);
2007 }
2008 } else if (self.bin_file.cast(.wasm)) |wasm_file| {
2009 _ = wasm_file;
2010 // const debug_info = &wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;
2011 // try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);
2012 } else unreachable;
2013}
1199 fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } {
1200 const zcu = wip_nav.pt.zcu;
1201 const ip = &zcu.intern_pool;
1202 const maybe_inst_index = ty.typeDeclInst(zcu);
1203 const unit = if (maybe_inst_index) |inst_index|
1204 try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFull(ip).file).mod)
1205 else
1206 .main;
1207 const gop = try wip_nav.dwarf.types.getOrPut(wip_nav.dwarf.gpa, ty.toIntern());
1208 if (gop.found_existing) return .{ unit, gop.value_ptr.* };
1209 const entry = try wip_nav.dwarf.addCommonEntry(unit);
1210 gop.value_ptr.* = entry;
1211 if (maybe_inst_index == null) try wip_nav.pending_types.append(wip_nav.dwarf.gpa, ty.toIntern());
1212 return .{ unit, entry };
1213 }
20141214
2015fn resolveCompilationDir(zcu: *Zcu, buffer: *[std.fs.max_path_bytes]u8) []const u8 {
2016 // We fully resolve all paths at this point to avoid lack of source line info in stack
2017 // traces or lack of debugging information which, if relative paths were used, would
2018 // be very location dependent.
2019 // TODO: the only concern I have with this is WASI as either host or target, should
2020 // we leave the paths as relative then?
2021 const root_dir_path = zcu.root_mod.root.root_dir.path orelse ".";
2022 const sub_path = zcu.root_mod.root.sub_path;
2023 const realpath = if (std.fs.path.isAbsolute(root_dir_path)) r: {
2024 @memcpy(buffer[0..root_dir_path.len], root_dir_path);
2025 break :r root_dir_path;
2026 } else std.fs.realpath(root_dir_path, buffer) catch return root_dir_path;
2027 const len = realpath.len + 1 + sub_path.len;
2028 if (buffer.len < len) return root_dir_path;
2029 buffer[realpath.len] = '/';
2030 @memcpy(buffer[realpath.len + 1 ..][0..sub_path.len], sub_path);
2031 return buffer[0..len];
2032}
1215 fn refType(wip_nav: *WipNav, ty: Type) UpdateError!void {
1216 const unit, const entry = try wip_nav.getTypeEntry(ty);
1217 try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
1218 }
20331219
2034fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) void {
2035 const comp = self.bin_file.comp;
2036 const target = comp.root_mod.resolved_target.result;
2037 const target_endian = target.cpu.arch.endian();
2038 switch (self.ptr_width) {
2039 .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(addr), target_endian),
2040 .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian),
1220 fn refForward(wip_nav: *WipNav) std.mem.Allocator.Error!u32 {
1221 const dwarf = wip_nav.dwarf;
1222 const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs;
1223 const reloc_index: u32 = @intCast(cross_entry_relocs.items.len);
1224 try cross_entry_relocs.append(dwarf.gpa, .{
1225 .source_entry = wip_nav.entry.toOptional(),
1226 .source_off = @intCast(wip_nav.debug_info.items.len),
1227 .target_entry = undefined,
1228 .target_off = undefined,
1229 });
1230 try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, dwarf.sectionOffsetBytes());
1231 return reloc_index;
20411232 }
2042}
20431233
2044fn writeOffsetAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), off: u64) void {
2045 const comp = self.bin_file.comp;
2046 const target = comp.root_mod.resolved_target.result;
2047 const target_endian = target.cpu.arch.endian();
2048 switch (self.format) {
2049 .dwarf32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(off), target_endian),
2050 .dwarf64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), off, target_endian),
1234 fn finishForward(wip_nav: *WipNav, reloc_index: u32) void {
1235 const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.items[reloc_index];
1236 reloc.target_entry = wip_nav.entry;
1237 reloc.target_off = @intCast(wip_nav.debug_info.items.len);
20511238 }
2052}
20531239
2054/// Writes to the file a buffer, prefixed and suffixed by the specified number of
2055/// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes
2056/// are less than 1044480 bytes (if this limit is ever reached, this function can be
2057/// improved to make more than one pwritev call, or the limit can be raised by a fixed
2058/// amount by increasing the length of `vecs`).
2059fn pwriteDbgLineNops(
2060 file: fs.File,
2061 offset: u64,
2062 prev_padding_size: usize,
2063 buf: []const u8,
2064 next_padding_size: usize,
2065) !void {
2066 const tracy = trace(@src());
2067 defer tracy.end();
2068
2069 const page_of_nops = [1]u8{DW.LNS.negate_stmt} ** 4096;
2070 const three_byte_nop = [3]u8{ DW.LNS.advance_pc, 0b1000_0000, 0 };
2071 var vecs: [512]std.posix.iovec_const = undefined;
2072 var vec_index: usize = 0;
2073 {
2074 var padding_left = prev_padding_size;
2075 if (padding_left % 2 != 0) {
2076 vecs[vec_index] = .{
2077 .base = &three_byte_nop,
2078 .len = three_byte_nop.len,
2079 };
2080 vec_index += 1;
2081 padding_left -= three_byte_nop.len;
2082 }
2083 while (padding_left > page_of_nops.len) {
2084 vecs[vec_index] = .{
2085 .base = &page_of_nops,
2086 .len = page_of_nops.len,
2087 };
2088 vec_index += 1;
2089 padding_left -= page_of_nops.len;
2090 }
2091 if (padding_left > 0) {
2092 vecs[vec_index] = .{
2093 .base = &page_of_nops,
2094 .len = padding_left,
2095 };
2096 vec_index += 1;
1240 fn enumConstValue(
1241 wip_nav: *WipNav,
1242 loaded_enum: InternPool.LoadedEnumType,
1243 abbrev_code: std.enums.EnumFieldStruct(std.builtin.Signedness, AbbrevCode, null),
1244 field_index: usize,
1245 ) std.mem.Allocator.Error!void {
1246 const zcu = wip_nav.pt.zcu;
1247 const ip = &zcu.intern_pool;
1248 const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
1249 const signedness = switch (loaded_enum.tag_ty) {
1250 .comptime_int_type => .signed,
1251 else => Type.fromInterned(loaded_enum.tag_ty).intInfo(zcu).signedness,
1252 };
1253 try uleb128(diw, @intFromEnum(switch (signedness) {
1254 inline .signed, .unsigned => |ct_signedness| @field(abbrev_code, @tagName(ct_signedness)),
1255 }));
1256 if (loaded_enum.values.len > 0) switch (ip.indexToKey(loaded_enum.values.get(ip)[field_index]).int.storage) {
1257 .u64 => |value| switch (signedness) {
1258 .signed => try sleb128(diw, value),
1259 .unsigned => try uleb128(diw, value),
1260 },
1261 .i64 => |value| switch (signedness) {
1262 .signed => try sleb128(diw, value),
1263 .unsigned => unreachable,
1264 },
1265 .big_int => |big_int| {
1266 const bits = big_int.bitCountTwosCompForSignedness(signedness);
1267 try wip_nav.debug_info.ensureUnusedCapacity(wip_nav.dwarf.gpa, std.math.divCeil(usize, bits, 7) catch unreachable);
1268 var bit: usize = 0;
1269 var carry: u1 = 1;
1270 while (bit < bits) : (bit += 7) {
1271 const limb_bits = @typeInfo(std.math.big.Limb).Int.bits;
1272 const limb_index = bit / limb_bits;
1273 const limb_shift: std.math.Log2Int(std.math.big.Limb) = @intCast(bit % limb_bits);
1274 const low_abs_part: u7 = @truncate(big_int.limbs[limb_index] >> limb_shift);
1275 const abs_part = if (limb_shift > limb_bits - 7) abs_part: {
1276 const next_limb: std.math.big.Limb = if (limb_index + 1 < big_int.limbs.len)
1277 big_int.limbs[limb_index + 1]
1278 else if (big_int.positive) 0 else std.math.maxInt(std.math.big.Limb);
1279 const high_abs_part: u7 = @truncate(next_limb << -%limb_shift);
1280 break :abs_part high_abs_part | low_abs_part;
1281 } else low_abs_part;
1282 const twos_comp_part = if (big_int.positive) abs_part else twos_comp_part: {
1283 const twos_comp_part, carry = @addWithOverflow(~abs_part, carry);
1284 break :twos_comp_part twos_comp_part;
1285 };
1286 wip_nav.debug_info.appendAssumeCapacity(@as(u8, if (bit + 7 < bits) 0x80 else 0x00) | twos_comp_part);
1287 }
1288 },
1289 .lazy_align, .lazy_size => unreachable,
1290 } else switch (signedness) {
1291 .signed => try sleb128(diw, field_index),
1292 .unsigned => try uleb128(diw, field_index),
20971293 }
20981294 }
20991295
2100 vecs[vec_index] = .{
2101 .base = buf.ptr,
2102 .len = buf.len,
1296 fn flush(wip_nav: *WipNav) UpdateError!void {
1297 while (wip_nav.pending_types.popOrNull()) |ty| try wip_nav.dwarf.updateType(wip_nav.pt, ty, &wip_nav.pending_types);
1298 }
1299};
1300
1301/// When allocating, the ideal_capacity is calculated by
1302/// actual_capacity + (actual_capacity / ideal_factor)
1303const ideal_factor = 3;
1304
1305fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
1306 return actual_size +| (actual_size / ideal_factor);
1307}
1308
1309pub fn init(lf: *link.File, format: DW.Format) Dwarf {
1310 const comp = lf.comp;
1311 const gpa = comp.gpa;
1312 const target = comp.root_mod.resolved_target.result;
1313 return .{
1314 .gpa = gpa,
1315 .bin_file = lf,
1316 .format = format,
1317 .address_size = switch (target.ptrBitWidth()) {
1318 0...32 => .@"32",
1319 33...64 => .@"64",
1320 else => unreachable,
1321 },
1322 .endian = target.cpu.arch.endian(),
1323
1324 .mods = .{},
1325 .types = .{},
1326 .navs = .{},
1327
1328 .debug_abbrev = .{ .section = Section.init },
1329 .debug_aranges = .{ .section = Section.init },
1330 .debug_info = .{ .section = Section.init },
1331 .debug_line = .{
1332 .header = switch (target.cpu.arch) {
1333 .x86_64, .aarch64 => .{
1334 .minimum_instruction_length = 1,
1335 .maximum_operations_per_instruction = 1,
1336 .default_is_stmt = true,
1337 .line_base = -5,
1338 .line_range = 14,
1339 .opcode_base = DW.LNS.set_isa + 1,
1340 },
1341 else => .{
1342 .minimum_instruction_length = 1,
1343 .maximum_operations_per_instruction = 1,
1344 .default_is_stmt = true,
1345 .line_base = 0,
1346 .line_range = 1,
1347 .opcode_base = DW.LNS.set_isa + 1,
1348 },
1349 },
1350 .section = Section.init,
1351 },
1352 .debug_line_str = StringSection.init,
1353 .debug_loclists = .{ .section = Section.init },
1354 .debug_rnglists = .{ .section = Section.init },
1355 .debug_str = StringSection.init,
21031356 };
2104 if (buf.len > 0) vec_index += 1;
1357}
21051358
2106 {
2107 var padding_left = next_padding_size;
2108 if (padding_left % 2 != 0) {
2109 vecs[vec_index] = .{
2110 .base = &three_byte_nop,
2111 .len = three_byte_nop.len,
2112 };
2113 vec_index += 1;
2114 padding_left -= three_byte_nop.len;
2115 }
2116 while (padding_left > page_of_nops.len) {
2117 vecs[vec_index] = .{
2118 .base = &page_of_nops,
2119 .len = page_of_nops.len,
2120 };
2121 vec_index += 1;
2122 padding_left -= page_of_nops.len;
1359pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
1360 if (dwarf.bin_file.cast(.elf)) |elf_file| {
1361 for ([_]*Section{
1362 &dwarf.debug_abbrev.section,
1363 &dwarf.debug_aranges.section,
1364 &dwarf.debug_info.section,
1365 &dwarf.debug_line.section,
1366 &dwarf.debug_line_str.section,
1367 &dwarf.debug_loclists.section,
1368 &dwarf.debug_rnglists.section,
1369 &dwarf.debug_str.section,
1370 }, [_]u32{
1371 elf_file.debug_abbrev_section_index.?,
1372 elf_file.debug_aranges_section_index.?,
1373 elf_file.debug_info_section_index.?,
1374 elf_file.debug_line_section_index.?,
1375 elf_file.debug_line_str_section_index.?,
1376 elf_file.debug_loclists_section_index.?,
1377 elf_file.debug_rnglists_section_index.?,
1378 elf_file.debug_str_section_index.?,
1379 }) |sec, section_index| {
1380 const shdr = &elf_file.shdrs.items[section_index];
1381 sec.index = section_index;
1382 sec.off = shdr.sh_offset;
1383 sec.len = shdr.sh_size;
21231384 }
2124 if (padding_left > 0) {
2125 vecs[vec_index] = .{
2126 .base = &page_of_nops,
2127 .len = padding_left,
2128 };
2129 vec_index += 1;
1385 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
1386 if (macho_file.d_sym) |*d_sym| {
1387 for ([_]*Section{
1388 &dwarf.debug_abbrev.section,
1389 &dwarf.debug_aranges.section,
1390 &dwarf.debug_info.section,
1391 &dwarf.debug_line.section,
1392 &dwarf.debug_line_str.section,
1393 &dwarf.debug_loclists.section,
1394 &dwarf.debug_rnglists.section,
1395 &dwarf.debug_str.section,
1396 }, [_]u8{
1397 d_sym.debug_abbrev_section_index.?,
1398 d_sym.debug_aranges_section_index.?,
1399 d_sym.debug_info_section_index.?,
1400 d_sym.debug_line_section_index.?,
1401 d_sym.debug_line_str_section_index.?,
1402 d_sym.debug_loclists_section_index.?,
1403 d_sym.debug_rnglists_section_index.?,
1404 d_sym.debug_str_section_index.?,
1405 }) |sec, sect_index| {
1406 const header = &d_sym.sections.items[sect_index];
1407 sec.index = sect_index;
1408 sec.off = header.offset;
1409 sec.len = header.size;
1410 }
1411 } else {
1412 for ([_]*Section{
1413 &dwarf.debug_abbrev.section,
1414 &dwarf.debug_aranges.section,
1415 &dwarf.debug_info.section,
1416 &dwarf.debug_line.section,
1417 &dwarf.debug_line_str.section,
1418 &dwarf.debug_loclists.section,
1419 &dwarf.debug_rnglists.section,
1420 &dwarf.debug_str.section,
1421 }, [_]u8{
1422 macho_file.debug_abbrev_sect_index.?,
1423 macho_file.debug_aranges_sect_index.?,
1424 macho_file.debug_info_sect_index.?,
1425 macho_file.debug_line_sect_index.?,
1426 macho_file.debug_line_str_sect_index.?,
1427 macho_file.debug_loclists_sect_index.?,
1428 macho_file.debug_rnglists_sect_index.?,
1429 macho_file.debug_str_sect_index.?,
1430 }) |sec, sect_index| {
1431 const header = &macho_file.sections.items(.header)[sect_index];
1432 sec.index = sect_index;
1433 sec.off = header.offset;
1434 sec.len = header.size;
1435 }
21301436 }
21311437 }
2132 try file.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
21331438}
21341439
2135fn writeDbgLineNopsBuffered(
2136 buf: []u8,
2137 offset: u32,
2138 prev_padding_size: usize,
2139 content: []const u8,
2140 next_padding_size: usize,
2141) void {
2142 assert(buf.len >= content.len + prev_padding_size + next_padding_size);
2143 const tracy = trace(@src());
2144 defer tracy.end();
2145
2146 const three_byte_nop = [3]u8{ DW.LNS.advance_pc, 0b1000_0000, 0 };
2147 {
2148 var padding_left = prev_padding_size;
2149 if (padding_left % 2 != 0) {
2150 buf[offset - padding_left ..][0..3].* = three_byte_nop;
2151 padding_left -= 3;
2152 }
1440pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
1441 dwarf.reloadSectionMetadata();
21531442
2154 while (padding_left > 0) : (padding_left -= 1) {
2155 buf[offset - padding_left] = DW.LNS.negate_stmt;
2156 }
2157 }
1443 dwarf.debug_abbrev.section.pad_to_ideal = false;
1444 assert(try dwarf.debug_abbrev.section.addUnit(0, 0, dwarf) == DebugAbbrev.unit);
1445 errdefer dwarf.debug_abbrev.section.popUnit();
1446 assert(try dwarf.debug_abbrev.section.addEntry(DebugAbbrev.unit, dwarf) == DebugAbbrev.entry);
21581447
2159 @memcpy(buf[offset..][0..content.len], content);
1448 dwarf.debug_aranges.section.pad_to_ideal = false;
1449 dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size) * 2);
21601450
2161 {
2162 var padding_left = next_padding_size;
2163 if (padding_left % 2 != 0) {
2164 buf[offset + content.len + padding_left ..][0..3].* = three_byte_nop;
2165 padding_left -= 3;
2166 }
1451 dwarf.debug_line_str.section.pad_to_ideal = false;
1452 assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
1453 errdefer dwarf.debug_line_str.section.popUnit();
21671454
2168 while (padding_left > 0) : (padding_left -= 1) {
2169 buf[offset + content.len + padding_left] = DW.LNS.negate_stmt;
2170 }
2171 }
2172}
1455 dwarf.debug_str.section.pad_to_ideal = false;
1456 assert(try dwarf.debug_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
1457 errdefer dwarf.debug_str.section.popUnit();
21731458
2174/// Writes to the file a buffer, prefixed and suffixed by the specified number of
2175/// bytes of padding.
2176fn pwriteDbgInfoNops(
2177 file: fs.File,
2178 offset: u64,
2179 prev_padding_size: usize,
2180 buf: []const u8,
2181 next_padding_size: usize,
2182 trailing_zero: bool,
2183) !void {
2184 const tracy = trace(@src());
2185 defer tracy.end();
2186
2187 const page_of_nops = [1]u8{@intFromEnum(AbbrevCode.padding)} ** 4096;
2188 var vecs: [32]std.posix.iovec_const = undefined;
2189 var vec_index: usize = 0;
2190 {
2191 var padding_left = prev_padding_size;
2192 while (padding_left > page_of_nops.len) {
2193 vecs[vec_index] = .{
2194 .base = &page_of_nops,
2195 .len = page_of_nops.len,
2196 };
2197 vec_index += 1;
2198 padding_left -= page_of_nops.len;
2199 }
2200 if (padding_left > 0) {
2201 vecs[vec_index] = .{
2202 .base = &page_of_nops,
2203 .len = padding_left,
2204 };
2205 vec_index += 1;
2206 }
2207 }
1459 dwarf.debug_loclists.section.pad_to_ideal = false;
22081460
2209 vecs[vec_index] = .{
2210 .base = buf.ptr,
2211 .len = buf.len,
2212 };
2213 if (buf.len > 0) vec_index += 1;
1461 dwarf.debug_rnglists.section.pad_to_ideal = false;
1462}
22141463
2215 {
2216 var padding_left = next_padding_size;
2217 while (padding_left > page_of_nops.len) {
2218 vecs[vec_index] = .{
2219 .base = &page_of_nops,
2220 .len = page_of_nops.len,
2221 };
2222 vec_index += 1;
2223 padding_left -= page_of_nops.len;
2224 }
2225 if (padding_left > 0) {
2226 vecs[vec_index] = .{
2227 .base = &page_of_nops,
2228 .len = padding_left,
2229 };
2230 vec_index += 1;
2231 }
2232 }
1464pub fn deinit(dwarf: *Dwarf) void {
1465 const gpa = dwarf.gpa;
1466 for (dwarf.mods.values()) |*mod_info| mod_info.deinit(gpa);
1467 dwarf.mods.deinit(gpa);
1468 dwarf.types.deinit(gpa);
1469 dwarf.navs.deinit(gpa);
1470 dwarf.debug_abbrev.section.deinit(gpa);
1471 dwarf.debug_aranges.section.deinit(gpa);
1472 dwarf.debug_info.section.deinit(gpa);
1473 dwarf.debug_line.section.deinit(gpa);
1474 dwarf.debug_line_str.deinit(gpa);
1475 dwarf.debug_loclists.section.deinit(gpa);
1476 dwarf.debug_rnglists.section.deinit(gpa);
1477 dwarf.debug_str.deinit(gpa);
1478 dwarf.* = undefined;
1479}
22331480
2234 if (trailing_zero) {
2235 var zbuf = [1]u8{0};
2236 vecs[vec_index] = .{
2237 .base = &zbuf,
2238 .len = zbuf.len,
1481fn getUnit(dwarf: *Dwarf, mod: *Module) UpdateError!Unit.Index {
1482 const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod);
1483 const unit: Unit.Index = @enumFromInt(mod_gop.index);
1484 if (!mod_gop.found_existing) {
1485 errdefer _ = dwarf.mods.pop();
1486 mod_gop.value_ptr.* = .{
1487 .root_dir_path = undefined,
1488 .dirs = .{},
1489 .files = .{},
22391490 };
2240 vec_index += 1;
1491 errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa);
1492 try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {});
1493 assert(try dwarf.debug_aranges.section.addUnit(
1494 DebugAranges.headerBytes(dwarf),
1495 DebugAranges.trailerBytes(dwarf),
1496 dwarf,
1497 ) == unit);
1498 errdefer dwarf.debug_aranges.section.popUnit();
1499 assert(try dwarf.debug_info.section.addUnit(
1500 DebugInfo.headerBytes(dwarf),
1501 DebugInfo.trailer_bytes,
1502 dwarf,
1503 ) == unit);
1504 errdefer dwarf.debug_info.section.popUnit();
1505 assert(try dwarf.debug_line.section.addUnit(
1506 DebugLine.headerBytes(dwarf, 5, 25),
1507 DebugLine.trailer_bytes,
1508 dwarf,
1509 ) == unit);
1510 errdefer dwarf.debug_line.section.popUnit();
1511 assert(try dwarf.debug_loclists.section.addUnit(
1512 DebugLocLists.headerBytes(dwarf),
1513 DebugLocLists.trailer_bytes,
1514 dwarf,
1515 ) == unit);
1516 errdefer dwarf.debug_loclists.section.popUnit();
1517 assert(try dwarf.debug_rnglists.section.addUnit(
1518 DebugRngLists.headerBytes(dwarf),
1519 DebugRngLists.trailer_bytes,
1520 dwarf,
1521 ) == unit);
1522 errdefer dwarf.debug_rnglists.section.popUnit();
22411523 }
2242
2243 try file.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
1524 return unit;
22441525}
22451526
2246fn writeDbgInfoNopsToArrayList(
2247 gpa: Allocator,
2248 buffer: *std.ArrayListUnmanaged(u8),
2249 offset: u32,
2250 prev_padding_size: usize,
2251 content: []const u8,
2252 next_padding_size: usize,
2253 trailing_zero: bool,
2254) Allocator.Error!void {
2255 try buffer.resize(gpa, @max(
2256 buffer.items.len,
2257 offset + content.len + next_padding_size + 1,
2258 ));
2259 @memset(buffer.items[offset - prev_padding_size .. offset], @intFromEnum(AbbrevCode.padding));
2260 @memcpy(buffer.items[offset..][0..content.len], content);
2261 @memset(buffer.items[offset + content.len ..][0..next_padding_size], @intFromEnum(AbbrevCode.padding));
2262
2263 if (trailing_zero) {
2264 buffer.items[offset + content.len + next_padding_size] = 0;
2265 }
1527fn getUnitIfExists(dwarf: *const Dwarf, mod: *Module) ?Unit.Index {
1528 return @enumFromInt(dwarf.mods.getIndex(mod) orelse return null);
22661529}
22671530
2268pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
2269 const comp = self.bin_file.comp;
2270 const target = comp.root_mod.resolved_target.result;
2271 const target_endian = target.cpu.arch.endian();
2272 const ptr_width_bytes = self.ptrWidthBytes();
2273
2274 // Enough for all the data without resizing. When support for more compilation units
2275 // is added, the size of this section will become more variable.
2276 var di_buf = try std.ArrayList(u8).initCapacity(self.allocator, 100);
2277 defer di_buf.deinit();
2278
2279 // initial length - length of the .debug_aranges contribution for this compilation unit,
2280 // not including the initial length itself.
2281 // We have to come back and write it later after we know the size.
2282 if (self.format == .dwarf64) di_buf.appendNTimesAssumeCapacity(0xff, 4);
2283 const init_len_index = di_buf.items.len;
2284 self.writeOffsetAssumeCapacity(&di_buf, 0);
2285 const after_init_len = di_buf.items.len;
2286 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version
2287
2288 // When more than one compilation unit is supported, this will be the offset to it.
2289 // For now it is always at offset 0 in .debug_info.
2290 self.writeOffsetAssumeCapacity(&di_buf, 0); // .debug_info offset
2291 di_buf.appendAssumeCapacity(ptr_width_bytes); // address_size
2292 di_buf.appendAssumeCapacity(0); // segment_selector_size
2293
2294 const end_header_offset = di_buf.items.len;
2295 const begin_entries_offset = mem.alignForward(usize, end_header_offset, ptr_width_bytes * 2);
2296 di_buf.appendNTimesAssumeCapacity(0, begin_entries_offset - end_header_offset);
2297
2298 // Currently only one compilation unit is supported, so the address range is simply
2299 // identical to the main program header virtual address and memory size.
2300 self.writeAddrAssumeCapacity(&di_buf, addr);
2301 self.writeAddrAssumeCapacity(&di_buf, size);
2302
2303 // Sentinel.
2304 self.writeAddrAssumeCapacity(&di_buf, 0);
2305 self.writeAddrAssumeCapacity(&di_buf, 0);
2306
2307 // Go back and populate the initial length.
2308 const init_len = di_buf.items.len - after_init_len;
2309 switch (self.format) {
2310 .dwarf32 => mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @intCast(init_len), target_endian),
2311 .dwarf64 => mem.writeInt(u64, di_buf.items[init_len_index..][0..8], init_len, target_endian),
2312 }
2313
2314 const needed_size: u32 = @intCast(di_buf.items.len);
2315 if (self.bin_file.cast(.elf)) |elf_file| {
2316 const shdr_index = elf_file.debug_aranges_section_index.?;
2317 try elf_file.growNonAllocSection(shdr_index, needed_size, 16, false);
2318 const debug_aranges_sect = &elf_file.shdrs.items[shdr_index];
2319 const file_pos = debug_aranges_sect.sh_offset;
2320 try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);
2321 } else if (self.bin_file.cast(.macho)) |macho_file| {
2322 if (macho_file.base.isRelocatable()) {
2323 const sect_index = macho_file.debug_aranges_sect_index.?;
2324 try macho_file.growSection(sect_index, needed_size);
2325 const sect = macho_file.sections.items(.header)[sect_index];
2326 const file_pos = sect.offset;
2327 try macho_file.base.file.?.pwriteAll(di_buf.items, file_pos);
2328 } else {
2329 const d_sym = macho_file.getDebugSymbols().?;
2330 const sect_index = d_sym.debug_aranges_section_index.?;
2331 try d_sym.growSection(sect_index, needed_size, false, macho_file);
2332 const sect = d_sym.getSection(sect_index);
2333 const file_pos = sect.offset;
2334 try d_sym.file.pwriteAll(di_buf.items, file_pos);
2335 }
2336 } else if (self.bin_file.cast(.wasm)) |wasm_file| {
2337 _ = wasm_file;
2338 // const debug_ranges = &wasm_file.getAtomPtr(wasm_file.debug_ranges_atom.?).code;
2339 // try debug_ranges.resize(gpa, needed_size);
2340 // @memcpy(debug_ranges.items[0..di_buf.items.len], di_buf.items);
2341 } else unreachable;
1531fn getModInfo(dwarf: *Dwarf, unit: Unit.Index) *ModInfo {
1532 return &dwarf.mods.values()[@intFromEnum(unit)];
23421533}
23431534
2344pub fn writeDbgLineHeader(self: *Dwarf) !void {
2345 const comp = self.bin_file.comp;
2346 const gpa = self.allocator;
2347 const target = comp.root_mod.resolved_target.result;
2348 const target_endian = target.cpu.arch.endian();
2349 const init_len_size: usize = switch (self.format) {
2350 .dwarf32 => 4,
2351 .dwarf64 => 12,
1535pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, sym_index: u32) UpdateError!?WipNav {
1536 const zcu = pt.zcu;
1537 const ip = &zcu.intern_pool;
1538
1539 const nav = ip.getNav(nav_index);
1540 log.debug("initWipNav({})", .{nav.fqn.fmt(ip)});
1541
1542 const inst_info = nav.srcInst(ip).resolveFull(ip);
1543 const file = zcu.fileByIndex(inst_info.file);
1544
1545 const unit = try dwarf.getUnit(file.mod);
1546 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
1547 errdefer _ = dwarf.navs.pop();
1548 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
1549 const nav_val = zcu.navValue(nav_index);
1550 var wip_nav: WipNav = .{
1551 .dwarf = dwarf,
1552 .pt = pt,
1553 .unit = unit,
1554 .entry = nav_gop.value_ptr.*,
1555 .any_children = false,
1556 .func = .none,
1557 .func_high_reloc = undefined,
1558 .debug_info = .{},
1559 .debug_line = .{},
1560 .debug_loclists = .{},
1561 .pending_types = .{},
23521562 };
1563 errdefer wip_nav.deinit();
23531564
2354 const dbg_line_prg_off = self.getDebugLineProgramOff() orelse return;
2355 assert(self.getDebugLineProgramEnd().? != 0);
2356
2357 // Convert all input DI files into a set of include dirs and file names.
2358 var arena = std.heap.ArenaAllocator.init(gpa);
2359 defer arena.deinit();
2360 const paths = try self.genIncludeDirsAndFileNames(arena.allocator());
2361
2362 // The size of this header is variable, depending on the number of directories,
2363 // files, and padding. We have a function to compute the upper bound size, however,
2364 // because it's needed for determining where to put the offset of the first `SrcFn`.
2365 const needed_bytes = self.dbgLineNeededHeaderBytes(paths.dirs, paths.files);
2366 var di_buf = try std.ArrayList(u8).initCapacity(gpa, needed_bytes);
2367 defer di_buf.deinit();
2368
2369 if (self.format == .dwarf64) di_buf.appendNTimesAssumeCapacity(0xff, 4);
2370 self.writeOffsetAssumeCapacity(&di_buf, 0);
2371
2372 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version
2373
2374 // Empirically, debug info consumers do not respect this field, or otherwise
2375 // consider it to be an error when it does not point exactly to the end of the header.
2376 // Therefore we rely on the NOP jump at the beginning of the Line Number Program for
2377 // padding rather than this field.
2378 const before_header_len = di_buf.items.len;
2379 self.writeOffsetAssumeCapacity(&di_buf, 0); // We will come back and write this.
2380 const after_header_len = di_buf.items.len;
2381
2382 assert(self.dbg_line_header.opcode_base == DW.LNS.set_isa + 1);
2383 di_buf.appendSliceAssumeCapacity(&[_]u8{
2384 self.dbg_line_header.minimum_instruction_length,
2385 self.dbg_line_header.maximum_operations_per_instruction,
2386 @intFromBool(self.dbg_line_header.default_is_stmt),
2387 @bitCast(self.dbg_line_header.line_base),
2388 self.dbg_line_header.line_range,
2389 self.dbg_line_header.opcode_base,
2390
2391 // Standard opcode lengths. The number of items here is based on `opcode_base`.
2392 // The value is the number of LEB128 operands the instruction takes.
2393 0, // `DW.LNS.copy`
2394 1, // `DW.LNS.advance_pc`
2395 1, // `DW.LNS.advance_line`
2396 1, // `DW.LNS.set_file`
2397 1, // `DW.LNS.set_column`
2398 0, // `DW.LNS.negate_stmt`
2399 0, // `DW.LNS.set_basic_block`
2400 0, // `DW.LNS.const_add_pc`
2401 1, // `DW.LNS.fixed_advance_pc`
2402 0, // `DW.LNS.set_prologue_end`
2403 0, // `DW.LNS.set_epilogue_begin`
2404 1, // `DW.LNS.set_isa`
2405 });
2406
2407 for (paths.dirs, 0..) |dir, i| {
2408 log.debug("adding new include dir at {d} of '{s}'", .{ i + 1, dir });
2409 di_buf.appendSliceAssumeCapacity(dir);
2410 di_buf.appendAssumeCapacity(0);
2411 }
2412 di_buf.appendAssumeCapacity(0); // include directories sentinel
2413
2414 for (paths.files, 0..) |file, i| {
2415 const dir_index = paths.files_dirs_indexes[i];
2416 log.debug("adding new file name at {d} of '{s}' referencing directory {d}", .{
2417 i + 1,
2418 file,
2419 dir_index + 1,
2420 });
2421 di_buf.appendSliceAssumeCapacity(file);
2422 di_buf.appendSliceAssumeCapacity(&[_]u8{
2423 0, // null byte for the relative path name
2424 @intCast(dir_index), // directory_index
2425 0, // mtime (TODO supply this)
2426 0, // file size bytes (TODO supply this)
2427 });
2428 }
2429 di_buf.appendAssumeCapacity(0); // file names sentinel
1565 switch (ip.indexToKey(nav_val.toIntern())) {
1566 else => {
1567 assert(file.zir_loaded);
1568 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
1569 assert(decl_inst.tag == .declaration);
1570 const tree = try file.getTree(dwarf.gpa);
1571 const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
1572 assert(loc.line == zcu.navSrcLine(nav_index));
1573
1574 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
1575 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index).data;
1576 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
1577 break :parent .{
1578 parent_namespace_ptr.owner_type,
1579 switch (decl_extra.name) {
1580 .@"comptime",
1581 .@"usingnamespace",
1582 .unnamed_test,
1583 .decltest,
1584 => DW.ACCESS.private,
1585 _ => if (decl_extra.name.isNamedTest(file.zir))
1586 DW.ACCESS.private
1587 else if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
1588 DW.ACCESS.public
1589 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
1590 DW.ACCESS.private
1591 else
1592 unreachable,
1593 },
1594 };
1595 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
1596
1597 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1598 try uleb128(diw, @intFromEnum(AbbrevCode.decl_var));
1599 try wip_nav.refType(Type.fromInterned(parent_type));
1600 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1601 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1602 try uleb128(diw, loc.column + 1);
1603 try diw.writeByte(accessibility);
1604 try wip_nav.strp(nav.name.toSlice(ip));
1605 try wip_nav.strp(nav.fqn.toSlice(ip));
1606 const ty = nav_val.typeOf(zcu);
1607 const ty_reloc_index = try wip_nav.refForward();
1608 try wip_nav.exprloc(.{ .addr = .{ .sym = sym_index } });
1609 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
1610 ty.abiAlignment(pt).toByteUnits().?);
1611 const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() });
1612 try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index|
1613 zcu.all_exports.items[export_index..][0..1]
1614 else if (zcu.multi_exports.get(func_unit)) |export_range|
1615 zcu.all_exports.items[export_range.index..][0..export_range.len]
1616 else
1617 &.{}) |@"export"|
1618 {
1619 if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true;
1620 } else false));
1621 wip_nav.finishForward(ty_reloc_index);
1622 try uleb128(diw, @intFromEnum(AbbrevCode.is_const));
1623 try wip_nav.refType(ty);
1624 },
1625 .variable => |variable| {
1626 assert(file.zir_loaded);
1627 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
1628 assert(decl_inst.tag == .declaration);
1629 const tree = try file.getTree(dwarf.gpa);
1630 const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
1631 assert(loc.line == zcu.navSrcLine(nav_index));
1632
1633 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
1634 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index).data;
1635 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
1636 break :parent .{
1637 parent_namespace_ptr.owner_type,
1638 switch (decl_extra.name) {
1639 .@"comptime",
1640 .@"usingnamespace",
1641 .unnamed_test,
1642 .decltest,
1643 => DW.ACCESS.private,
1644 _ => if (decl_extra.name.isNamedTest(file.zir))
1645 DW.ACCESS.private
1646 else if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
1647 DW.ACCESS.public
1648 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
1649 DW.ACCESS.private
1650 else
1651 unreachable,
1652 },
1653 };
1654 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
1655
1656 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1657 try uleb128(diw, @intFromEnum(AbbrevCode.decl_var));
1658 try wip_nav.refType(Type.fromInterned(parent_type));
1659 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1660 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1661 try uleb128(diw, loc.column + 1);
1662 try diw.writeByte(accessibility);
1663 try wip_nav.strp(nav.name.toSlice(ip));
1664 try wip_nav.strp(nav.fqn.toSlice(ip));
1665 const ty = Type.fromInterned(variable.ty);
1666 try wip_nav.refType(ty);
1667 const addr: Loc = .{ .addr = .{ .sym = sym_index } };
1668 try wip_nav.exprloc(if (variable.is_threadlocal) .{ .form_tls_address = &addr } else addr);
1669 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
1670 ty.abiAlignment(pt).toByteUnits().?);
1671 const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() });
1672 try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index|
1673 zcu.all_exports.items[export_index..][0..1]
1674 else if (zcu.multi_exports.get(func_unit)) |export_range|
1675 zcu.all_exports.items[export_range.index..][0..export_range.len]
1676 else
1677 &.{}) |@"export"|
1678 {
1679 if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true;
1680 } else false));
1681 },
1682 .func => |func| {
1683 assert(file.zir_loaded);
1684 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
1685 assert(decl_inst.tag == .declaration);
1686 const tree = try file.getTree(dwarf.gpa);
1687 const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
1688 assert(loc.line == zcu.navSrcLine(nav_index));
1689
1690 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
1691 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index).data;
1692 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
1693 break :parent .{
1694 parent_namespace_ptr.owner_type,
1695 switch (decl_extra.name) {
1696 .@"comptime",
1697 .@"usingnamespace",
1698 .unnamed_test,
1699 .decltest,
1700 => DW.ACCESS.private,
1701 _ => if (decl_extra.name.isNamedTest(file.zir))
1702 DW.ACCESS.private
1703 else if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
1704 DW.ACCESS.public
1705 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
1706 DW.ACCESS.private
1707 else
1708 unreachable,
1709 },
1710 };
1711 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
1712
1713 const func_type = ip.indexToKey(func.ty).func_type;
1714 wip_nav.func = nav_val.toIntern();
1715
1716 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1717 try uleb128(diw, @intFromEnum(AbbrevCode.decl_func));
1718 try wip_nav.refType(Type.fromInterned(parent_type));
1719 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1720 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1721 try uleb128(diw, loc.column + 1);
1722 try diw.writeByte(accessibility);
1723 try wip_nav.strp(nav.name.toSlice(ip));
1724 try wip_nav.strp(nav.fqn.toSlice(ip));
1725 try wip_nav.refType(Type.fromInterned(func_type.return_type));
1726 const external_relocs = &dwarf.debug_info.section.getUnit(unit).external_relocs;
1727 try external_relocs.append(dwarf.gpa, .{
1728 .source_entry = wip_nav.entry,
1729 .source_off = @intCast(wip_nav.debug_info.items.len),
1730 .target_sym = sym_index,
1731 });
1732 try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
1733 wip_nav.func_high_reloc = @intCast(external_relocs.items.len);
1734 try external_relocs.append(dwarf.gpa, .{
1735 .source_entry = wip_nav.entry,
1736 .source_off = @intCast(wip_nav.debug_info.items.len),
1737 .target_sym = sym_index,
1738 });
1739 try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
1740 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
1741 target_info.defaultFunctionAlignment(file.mod.resolved_target.result).toByteUnits().?);
1742 const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() });
1743 try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index|
1744 zcu.all_exports.items[export_index..][0..1]
1745 else if (zcu.multi_exports.get(func_unit)) |export_range|
1746 zcu.all_exports.items[export_range.index..][0..export_range.len]
1747 else
1748 &.{}) |@"export"|
1749 {
1750 if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true;
1751 } else false));
1752 try diw.writeByte(@intFromBool(func_type.return_type == .noreturn_type));
1753
1754 const dlw = wip_nav.debug_line.writer(dwarf.gpa);
1755 try dlw.writeByte(DW.LNS.extended_op);
1756 if (dwarf.incremental()) {
1757 try uleb128(dlw, 1 + dwarf.sectionOffsetBytes());
1758 try dlw.writeByte(DW.LNE.ZIG_set_decl);
1759 try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{
1760 .source_entry = wip_nav.entry.toOptional(),
1761 .source_off = @intCast(wip_nav.debug_line.items.len),
1762 .target_sec = .debug_info,
1763 .target_unit = wip_nav.unit,
1764 .target_entry = wip_nav.entry.toOptional(),
1765 });
1766 try dlw.writeByteNTimes(0, dwarf.sectionOffsetBytes());
24301767
2431 const header_len = di_buf.items.len - after_header_len;
2432 switch (self.format) {
2433 .dwarf32 => mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(header_len), target_endian),
2434 .dwarf64 => mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian),
2435 }
1768 try dlw.writeByte(DW.LNS.set_column);
1769 try uleb128(dlw, func.lbrace_column + 1);
24361770
2437 assert(needed_bytes == di_buf.items.len);
1771 try wip_nav.advancePCAndLine(func.lbrace_line, 0);
1772 } else {
1773 try uleb128(dlw, 1 + @intFromEnum(dwarf.address_size));
1774 try dlw.writeByte(DW.LNE.set_address);
1775 try dwarf.debug_line.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{
1776 .source_entry = wip_nav.entry,
1777 .source_off = @intCast(wip_nav.debug_line.items.len),
1778 .target_sym = sym_index,
1779 });
1780 try dlw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
24381781
2439 if (di_buf.items.len > dbg_line_prg_off) {
2440 const needed_with_padding = padToIdeal(needed_bytes);
2441 const delta = needed_with_padding - dbg_line_prg_off;
1782 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
1783 try dlw.writeByte(DW.LNS.set_file);
1784 try uleb128(dlw, file_gop.index);
24421785
2443 const first_fn_index = self.src_fn_first_index.?;
2444 const first_fn = self.getAtom(.src_fn, first_fn_index);
2445 const last_fn_index = self.src_fn_last_index.?;
2446 const last_fn = self.getAtom(.src_fn, last_fn_index);
1786 try dlw.writeByte(DW.LNS.set_column);
1787 try uleb128(dlw, func.lbrace_column + 1);
24471788
2448 var src_fn_index = first_fn_index;
1789 try wip_nav.advancePCAndLine(@intCast(loc.line + func.lbrace_line), 0);
1790 }
1791 },
1792 }
1793 return wip_nav;
1794}
24491795
2450 const buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - first_fn.off);
2451 defer gpa.free(buffer);
1796pub fn finishWipNav(
1797 dwarf: *Dwarf,
1798 pt: Zcu.PerThread,
1799 nav_index: InternPool.Nav.Index,
1800 sym: struct { index: u32, addr: u64, size: u64 },
1801 wip_nav: *WipNav,
1802) UpdateError!void {
1803 const zcu = pt.zcu;
1804 const ip = &zcu.intern_pool;
1805 const nav = ip.getNav(nav_index);
1806 log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)});
1807
1808 if (wip_nav.func != .none) {
1809 dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size;
1810 if (wip_nav.any_children) {
1811 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1812 try uleb128(diw, @intFromEnum(AbbrevCode.null));
1813 } else std.leb.writeUnsignedFixed(
1814 AbbrevCode.decl_bytes,
1815 wip_nav.debug_info.items[0..AbbrevCode.decl_bytes],
1816 @intFromEnum(AbbrevCode.decl_func_empty),
1817 );
24521818
2453 if (self.bin_file.cast(.elf)) |elf_file| {
2454 const shdr_index = elf_file.debug_line_section_index.?;
2455 const needed_size = elf_file.shdrs.items[shdr_index].sh_size + delta;
2456 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
2457 const file_pos = elf_file.shdrs.items[shdr_index].sh_offset + first_fn.off;
1819 var aranges_entry = [1]u8{0} ** (8 + 8);
1820 try dwarf.debug_aranges.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{
1821 .source_entry = wip_nav.entry,
1822 .target_sym = sym.index,
1823 });
1824 dwarf.writeInt(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0);
1825 dwarf.writeInt(aranges_entry[@intFromEnum(dwarf.address_size)..][0..@intFromEnum(dwarf.address_size)], sym.size);
1826
1827 @memset(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0);
1828 try dwarf.debug_aranges.section.replaceEntry(
1829 wip_nav.unit,
1830 wip_nav.entry,
1831 dwarf,
1832 aranges_entry[0 .. @intFromEnum(dwarf.address_size) * 2],
1833 );
24581834
2459 const amt = try elf_file.base.file.?.preadAll(buffer, file_pos);
2460 if (amt != buffer.len) return error.InputOutput;
1835 try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).external_relocs.appendSlice(dwarf.gpa, &.{
1836 .{
1837 .source_entry = wip_nav.entry,
1838 .source_off = 1,
1839 .target_sym = sym.index,
1840 },
1841 .{
1842 .source_entry = wip_nav.entry,
1843 .source_off = 1 + @intFromEnum(dwarf.address_size),
1844 .target_sym = sym.index,
1845 .target_off = sym.size,
1846 },
1847 });
1848 try dwarf.debug_rnglists.section.replaceEntry(
1849 wip_nav.unit,
1850 wip_nav.entry,
1851 dwarf,
1852 ([1]u8{DW.RLE.start_end} ++ [1]u8{0} ** (8 + 8))[0 .. 1 + @intFromEnum(dwarf.address_size) + @intFromEnum(dwarf.address_size)],
1853 );
1854 }
24611855
2462 try elf_file.base.file.?.pwriteAll(buffer, file_pos + delta);
2463 } else if (self.bin_file.cast(.macho)) |macho_file| {
2464 if (macho_file.base.isRelocatable()) {
2465 const sect_index = macho_file.debug_line_sect_index.?;
2466 const needed_size: u32 = @intCast(macho_file.sections.items(.header)[sect_index].size + delta);
2467 try macho_file.growSection(sect_index, needed_size);
2468 const file_pos = macho_file.sections.items(.header)[sect_index].offset + first_fn.off;
1856 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
1857 if (wip_nav.debug_line.items.len > 0) {
1858 const dlw = wip_nav.debug_line.writer(dwarf.gpa);
1859 try dlw.writeByte(DW.LNS.extended_op);
1860 try uleb128(dlw, 1);
1861 try dlw.writeByte(DW.LNE.end_sequence);
1862 try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.items);
1863 }
1864 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items);
24691865
2470 const amt = try macho_file.base.file.?.preadAll(buffer, file_pos);
2471 if (amt != buffer.len) return error.InputOutput;
1866 try wip_nav.flush();
1867}
24721868
2473 try macho_file.base.file.?.pwriteAll(buffer, file_pos + delta);
2474 } else {
2475 const d_sym = macho_file.getDebugSymbols().?;
2476 const sect_index = d_sym.debug_line_section_index.?;
2477 const needed_size: u32 = @intCast(d_sym.getSection(sect_index).size + delta);
2478 try d_sym.growSection(sect_index, needed_size, true, macho_file);
2479 const file_pos = d_sym.getSection(sect_index).offset + first_fn.off;
1869pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateError!void {
1870 const zcu = pt.zcu;
1871 const ip = &zcu.intern_pool;
1872 const nav_val = zcu.navValue(nav_index);
24801873
2481 const amt = try d_sym.file.preadAll(buffer, file_pos);
2482 if (amt != buffer.len) return error.InputOutput;
1874 const nav = ip.getNav(nav_index);
1875 log.debug("updateComptimeNav({})", .{nav.fqn.fmt(ip)});
1876
1877 const inst_info = nav.srcInst(ip).resolveFull(ip);
1878 const file = zcu.fileByIndex(inst_info.file);
1879 assert(file.zir_loaded);
1880 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
1881 assert(decl_inst.tag == .declaration);
1882 const tree = try file.getTree(dwarf.gpa);
1883 const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
1884 assert(loc.line == zcu.navSrcLine(nav_index));
1885
1886 const unit = try dwarf.getUnit(file.mod);
1887 var wip_nav: WipNav = .{
1888 .dwarf = dwarf,
1889 .pt = pt,
1890 .unit = unit,
1891 .entry = undefined,
1892 .any_children = false,
1893 .func = .none,
1894 .func_high_reloc = undefined,
1895 .debug_info = .{},
1896 .debug_line = .{},
1897 .debug_loclists = .{},
1898 .pending_types = .{},
1899 };
1900 defer wip_nav.deinit();
1901
1902 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
1903 errdefer _ = dwarf.navs.pop();
1904 switch (ip.indexToKey(nav_val.toIntern())) {
1905 .struct_type => done: {
1906 const loaded_struct = ip.loadStructType(nav_val.toIntern());
1907
1908 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
1909 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
1910 break :parent .{
1911 parent_namespace_ptr.owner_type,
1912 if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
1913 DW.ACCESS.public
1914 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
1915 DW.ACCESS.private
1916 else
1917 unreachable,
1918 };
1919 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
1920
1921 decl_struct: {
1922 if (loaded_struct.zir_index == .none) break :decl_struct;
1923
1924 const value_inst = value_inst: {
1925 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index);
1926 const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
1927 const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
1928 if (break_inst.tag != .break_inline) break :value_inst null;
1929 assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
1930 var value_inst = break_inst.data.@"break".operand.toIndex();
1931 while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
1932 else => break,
1933 .as_node => value_inst = file.zir.extraData(
1934 Zir.Inst.As,
1935 file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
1936 ).data.operand.toIndex(),
1937 };
1938 break :value_inst value_inst;
1939 };
1940 const type_inst_info = loaded_struct.zir_index.unwrap().?.resolveFull(ip);
1941 if (type_inst_info.inst != value_inst) break :decl_struct;
24831942
2484 try d_sym.file.pwriteAll(buffer, file_pos + delta);
1943 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
1944 if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
1945 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
1946 type_gop.value_ptr.* = nav_gop.value_ptr.*;
1947 }
1948 wip_nav.entry = nav_gop.value_ptr.*;
1949 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1950
1951 switch (loaded_struct.layout) {
1952 .auto, .@"extern" => {
1953 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0)
1954 .decl_namespace_struct
1955 else
1956 .decl_struct)));
1957 try wip_nav.refType(Type.fromInterned(parent_type));
1958 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1959 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1960 try uleb128(diw, loc.column + 1);
1961 try diw.writeByte(accessibility);
1962 try wip_nav.strp(nav.name.toSlice(ip));
1963 if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
1964 try uleb128(diw, nav_val.toType().abiSize(pt));
1965 try uleb128(diw, nav_val.toType().abiAlignment(pt).toByteUnits().?);
1966 for (0..loaded_struct.field_types.len) |field_index| {
1967 const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
1968 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
1969 if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
1970 const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
1971 defer dwarf.gpa.free(field_name);
1972 try wip_nav.strp(field_name);
1973 }
1974 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1975 try wip_nav.refType(field_type);
1976 if (!is_comptime) {
1977 try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
1978 try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
1979 field_type.abiAlignment(pt).toByteUnits().?);
1980 }
1981 }
1982 try uleb128(diw, @intFromEnum(AbbrevCode.null));
1983 }
1984 },
1985 .@"packed" => {
1986 try uleb128(diw, @intFromEnum(AbbrevCode.decl_packed_struct));
1987 try wip_nav.refType(Type.fromInterned(parent_type));
1988 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1989 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1990 try uleb128(diw, loc.column + 1);
1991 try diw.writeByte(accessibility);
1992 try wip_nav.strp(nav.name.toSlice(ip));
1993 try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
1994 var field_bit_offset: u16 = 0;
1995 for (0..loaded_struct.field_types.len) |field_index| {
1996 try uleb128(diw, @intFromEnum(@as(AbbrevCode, .packed_struct_field)));
1997 try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip));
1998 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1999 try wip_nav.refType(field_type);
2000 try uleb128(diw, field_bit_offset);
2001 field_bit_offset += @intCast(field_type.bitSize(pt));
2002 }
2003 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2004 },
2005 }
2006 break :done;
24852007 }
2486 } else if (self.bin_file.cast(.wasm)) |wasm_file| {
2487 _ = wasm_file;
2488 // const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
2489 // {
2490 // const src = debug_line.items[first_fn.off..];
2491 // @memcpy(buffer[0..src.len], src);
2492 // }
2493 // try debug_line.resize(self.allocator, debug_line.items.len + delta);
2494 // @memcpy(debug_line.items[first_fn.off + delta ..][0..buffer.len], buffer);
2495 } else unreachable;
2496
2497 while (true) {
2498 const src_fn = self.getAtomPtr(.src_fn, src_fn_index);
2499 src_fn.off += delta;
2500
2501 if (src_fn.next_index) |next_index| {
2502 src_fn_index = next_index;
2503 } else break;
2504 }
2505 }
25062008
2507 // Backpatch actual length of the debug line program
2508 const init_len = self.getDebugLineProgramEnd().? - init_len_size;
2509 switch (self.format) {
2510 .dwarf32 => {
2511 mem.writeInt(u32, di_buf.items[0..4], @intCast(init_len), target_endian);
2512 },
2513 .dwarf64 => {
2514 mem.writeInt(u64, di_buf.items[4..][0..8], init_len, target_endian);
2009 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2010 wip_nav.entry = nav_gop.value_ptr.*;
2011 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2012 try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
2013 try wip_nav.refType(Type.fromInterned(parent_type));
2014 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2015 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2016 try uleb128(diw, loc.column + 1);
2017 try diw.writeByte(accessibility);
2018 try wip_nav.strp(nav.name.toSlice(ip));
2019 try wip_nav.refType(nav_val.toType());
25152020 },
2516 }
2021 .enum_type => done: {
2022 const loaded_enum = ip.loadEnumType(nav_val.toIntern());
2023
2024 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2025 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2026 break :parent .{
2027 parent_namespace_ptr.owner_type,
2028 if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
2029 DW.ACCESS.public
2030 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
2031 DW.ACCESS.private
2032 else
2033 unreachable,
2034 };
2035 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
2036
2037 decl_enum: {
2038 if (loaded_enum.zir_index == .none) break :decl_enum;
2039
2040 const value_inst = value_inst: {
2041 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index);
2042 const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
2043 const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
2044 if (break_inst.tag != .break_inline) break :value_inst null;
2045 assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
2046 var value_inst = break_inst.data.@"break".operand.toIndex();
2047 while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
2048 else => break,
2049 .as_node => value_inst = file.zir.extraData(
2050 Zir.Inst.As,
2051 file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
2052 ).data.operand.toIndex(),
2053 };
2054 break :value_inst value_inst;
2055 };
2056 const type_inst_info = loaded_enum.zir_index.unwrap().?.resolveFull(ip);
2057 if (type_inst_info.inst != value_inst) break :decl_enum;
25172058
2518 // We use NOPs because consumers empirically do not respect the header length field.
2519 const jmp_amt = self.getDebugLineProgramOff().? - di_buf.items.len;
2520 if (self.bin_file.cast(.elf)) |elf_file| {
2521 const debug_line_sect = &elf_file.shdrs.items[elf_file.debug_line_section_index.?];
2522 const file_pos = debug_line_sect.sh_offset;
2523 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
2524 } else if (self.bin_file.cast(.macho)) |macho_file| {
2525 if (macho_file.base.isRelocatable()) {
2526 const debug_line_sect = macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?];
2527 const file_pos = debug_line_sect.offset;
2528 try pwriteDbgLineNops(macho_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
2529 } else {
2530 const d_sym = macho_file.getDebugSymbols().?;
2531 const debug_line_sect = d_sym.getSection(d_sym.debug_line_section_index.?);
2532 const file_pos = debug_line_sect.offset;
2533 try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt);
2534 }
2535 } else if (self.bin_file.cast(.wasm)) |wasm_file| {
2536 _ = wasm_file;
2537 // const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
2538 // writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);
2539 } else unreachable;
2540}
2059 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
2060 if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
2061 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2062 type_gop.value_ptr.* = nav_gop.value_ptr.*;
2063 }
2064 wip_nav.entry = nav_gop.value_ptr.*;
2065 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2066 try uleb128(diw, @intFromEnum(AbbrevCode.decl_enum));
2067 try wip_nav.refType(Type.fromInterned(parent_type));
2068 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2069 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2070 try uleb128(diw, loc.column + 1);
2071 try diw.writeByte(accessibility);
2072 try wip_nav.strp(nav.name.toSlice(ip));
2073 try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
2074 for (0..loaded_enum.names.len) |field_index| {
2075 try wip_nav.enumConstValue(loaded_enum, .{
2076 .signed = .signed_enum_field,
2077 .unsigned = .unsigned_enum_field,
2078 }, field_index);
2079 try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
2080 }
2081 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2082 break :done;
2083 }
25412084
2542fn getDebugInfoOff(self: Dwarf) ?u32 {
2543 const first_index = self.di_atom_first_index orelse return null;
2544 const first = self.getAtom(.di_atom, first_index);
2545 return first.off;
2546}
2085 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2086 wip_nav.entry = nav_gop.value_ptr.*;
2087 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2088 try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
2089 try wip_nav.refType(Type.fromInterned(parent_type));
2090 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2091 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2092 try uleb128(diw, loc.column + 1);
2093 try diw.writeByte(accessibility);
2094 try wip_nav.strp(nav.name.toSlice(ip));
2095 try wip_nav.refType(nav_val.toType());
2096 },
2097 .union_type => done: {
2098 const loaded_union = ip.loadUnionType(nav_val.toIntern());
2099
2100 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2101 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2102 break :parent .{
2103 parent_namespace_ptr.owner_type,
2104 if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
2105 DW.ACCESS.public
2106 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
2107 DW.ACCESS.private
2108 else
2109 unreachable,
2110 };
2111 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
2112
2113 decl_union: {
2114 const value_inst = value_inst: {
2115 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index);
2116 const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
2117 const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
2118 if (break_inst.tag != .break_inline) break :value_inst null;
2119 assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
2120 var value_inst = break_inst.data.@"break".operand.toIndex();
2121 while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
2122 else => break,
2123 .as_node => value_inst = file.zir.extraData(
2124 Zir.Inst.As,
2125 file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
2126 ).data.operand.toIndex(),
2127 };
2128 break :value_inst value_inst;
2129 };
2130 const type_inst_info = loaded_union.zir_index.resolveFull(ip);
2131 if (type_inst_info.inst != value_inst) break :decl_union;
25472132
2548fn getDebugInfoEnd(self: Dwarf) ?u32 {
2549 const last_index = self.di_atom_last_index orelse return null;
2550 const last = self.getAtom(.di_atom, last_index);
2551 return last.off + last.len;
2552}
2133 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
2134 if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
2135 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2136 type_gop.value_ptr.* = nav_gop.value_ptr.*;
2137 }
2138 wip_nav.entry = nav_gop.value_ptr.*;
2139 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2140 try uleb128(diw, @intFromEnum(AbbrevCode.decl_union));
2141 try wip_nav.refType(Type.fromInterned(parent_type));
2142 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2143 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2144 try uleb128(diw, loc.column + 1);
2145 try diw.writeByte(accessibility);
2146 try wip_nav.strp(nav.name.toSlice(ip));
2147 const union_layout = pt.getUnionLayout(loaded_union);
2148 try uleb128(diw, union_layout.abi_size);
2149 try uleb128(diw, union_layout.abi_align.toByteUnits().?);
2150 const loaded_tag = loaded_union.loadTagType(ip);
2151 if (loaded_union.hasTag(ip)) {
2152 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
2153 try wip_nav.infoSectionOffset(
2154 .debug_info,
2155 wip_nav.unit,
2156 wip_nav.entry,
2157 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2158 );
2159 {
2160 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2161 try wip_nav.strp("tag");
2162 try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty));
2163 try uleb128(diw, union_layout.tagOffset());
2164
2165 for (0..loaded_union.field_types.len) |field_index| {
2166 try wip_nav.enumConstValue(loaded_tag, .{
2167 .signed = .signed_tagged_union_field,
2168 .unsigned = .unsigned_tagged_union_field,
2169 }, field_index);
2170 {
2171 try uleb128(diw, @intFromEnum(AbbrevCode.struct_field));
2172 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
2173 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
2174 try wip_nav.refType(field_type);
2175 try uleb128(diw, union_layout.payloadOffset());
2176 try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
2177 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(pt).toByteUnits().?);
2178 }
2179 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2180 }
2181 }
2182 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2183
2184 if (ip.indexToKey(loaded_union.enum_tag_ty).enum_type == .generated_tag)
2185 try wip_nav.pending_types.append(dwarf.gpa, loaded_union.enum_tag_ty);
2186 } else for (0..loaded_union.field_types.len) |field_index| {
2187 try uleb128(diw, @intFromEnum(AbbrevCode.untagged_union_field));
2188 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
2189 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
2190 try wip_nav.refType(field_type);
2191 try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
2192 field_type.abiAlignment(pt).toByteUnits().?);
2193 }
2194 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2195 break :done;
2196 }
25532197
2554fn getDebugLineProgramOff(self: Dwarf) ?u32 {
2555 const first_index = self.src_fn_first_index orelse return null;
2556 const first = self.getAtom(.src_fn, first_index);
2557 return first.off;
2558}
2198 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2199 wip_nav.entry = nav_gop.value_ptr.*;
2200 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2201 try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
2202 try wip_nav.refType(Type.fromInterned(parent_type));
2203 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2204 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2205 try uleb128(diw, loc.column + 1);
2206 try diw.writeByte(accessibility);
2207 try wip_nav.strp(nav.name.toSlice(ip));
2208 try wip_nav.refType(nav_val.toType());
2209 },
2210 .opaque_type => done: {
2211 const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
2212
2213 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2214 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2215 break :parent .{
2216 parent_namespace_ptr.owner_type,
2217 if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
2218 DW.ACCESS.public
2219 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
2220 DW.ACCESS.private
2221 else
2222 unreachable,
2223 };
2224 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
2225
2226 decl_opaque: {
2227 const value_inst = value_inst: {
2228 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index);
2229 const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
2230 const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
2231 if (break_inst.tag != .break_inline) break :value_inst null;
2232 assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
2233 var value_inst = break_inst.data.@"break".operand.toIndex();
2234 while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
2235 else => break,
2236 .as_node => value_inst = file.zir.extraData(
2237 Zir.Inst.As,
2238 file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
2239 ).data.operand.toIndex(),
2240 };
2241 break :value_inst value_inst;
2242 };
2243 const type_inst_info = loaded_opaque.zir_index.resolveFull(ip);
2244 if (type_inst_info.inst != value_inst) break :decl_opaque;
25592245
2560fn getDebugLineProgramEnd(self: Dwarf) ?u32 {
2561 const last_index = self.src_fn_last_index orelse return null;
2562 const last = self.getAtom(.src_fn, last_index);
2563 return last.off + last.len;
2564}
2246 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
2247 if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
2248 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2249 type_gop.value_ptr.* = nav_gop.value_ptr.*;
2250 }
2251 wip_nav.entry = nav_gop.value_ptr.*;
2252 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2253 try uleb128(diw, @intFromEnum(AbbrevCode.decl_namespace_struct));
2254 try wip_nav.refType(Type.fromInterned(parent_type));
2255 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2256 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2257 try uleb128(diw, loc.column + 1);
2258 try diw.writeByte(accessibility);
2259 try wip_nav.strp(nav.name.toSlice(ip));
2260 try diw.writeByte(@intFromBool(false));
2261 break :done;
2262 }
25652263
2566/// Always 4 or 8 depending on whether this is 32-bit or 64-bit format.
2567fn ptrWidthBytes(self: Dwarf) u8 {
2568 return switch (self.ptr_width) {
2569 .p32 => 4,
2570 .p64 => 8,
2571 };
2264 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2265 wip_nav.entry = nav_gop.value_ptr.*;
2266 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2267 try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
2268 try wip_nav.refType(Type.fromInterned(parent_type));
2269 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2270 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2271 try uleb128(diw, loc.column + 1);
2272 try diw.writeByte(accessibility);
2273 try wip_nav.strp(nav.name.toSlice(ip));
2274 try wip_nav.refType(nav_val.toType());
2275 },
2276 else => {
2277 _ = dwarf.navs.pop();
2278 return;
2279 },
2280 }
2281 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2282 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items);
2283 try wip_nav.flush();
25722284}
25732285
2574fn dbgLineNeededHeaderBytes(self: Dwarf, dirs: []const []const u8, files: []const []const u8) u32 {
2575 var size: usize = switch (self.format) { // length field
2576 .dwarf32 => 4,
2577 .dwarf64 => 12,
2578 };
2579 size += @sizeOf(u16); // version field
2580 size += switch (self.format) { // offset to end-of-header
2581 .dwarf32 => 4,
2582 .dwarf64 => 8,
2583 };
2584 size += 18; // opcodes
2585
2586 for (dirs) |dir| { // include dirs
2587 size += dir.len + 1;
2286fn updateType(
2287 dwarf: *Dwarf,
2288 pt: Zcu.PerThread,
2289 type_index: InternPool.Index,
2290 pending_types: *std.ArrayListUnmanaged(InternPool.Index),
2291) UpdateError!void {
2292 const zcu = pt.zcu;
2293 const ip = &zcu.intern_pool;
2294 const ty = Type.fromInterned(type_index);
2295 switch (type_index) {
2296 .generic_poison_type => log.debug("updateType({s})", .{"anytype"}),
2297 else => log.debug("updateType({})", .{ty.fmt(pt)}),
25882298 }
2589 size += 1; // include dirs sentinel
25902299
2591 for (files) |file| { // file names
2592 size += file.len + 1 + 1 + 1 + 1;
2300 var wip_nav: WipNav = .{
2301 .dwarf = dwarf,
2302 .pt = pt,
2303 .unit = .main,
2304 .entry = dwarf.types.get(type_index).?,
2305 .any_children = false,
2306 .func = .none,
2307 .func_high_reloc = undefined,
2308 .debug_info = .{},
2309 .debug_line = .{},
2310 .debug_loclists = .{},
2311 .pending_types = pending_types.*,
2312 };
2313 defer {
2314 pending_types.* = wip_nav.pending_types;
2315 wip_nav.pending_types = .{};
2316 wip_nav.deinit();
25932317 }
2594 size += 1; // file names sentinel
2595
2596 return @intCast(size);
2597}
2318 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2319 const name = switch (type_index) {
2320 .generic_poison_type => "",
2321 else => try std.fmt.allocPrint(dwarf.gpa, "{}", .{ty.fmt(pt)}),
2322 };
2323 defer dwarf.gpa.free(name);
2324
2325 switch (ip.indexToKey(type_index)) {
2326 .int_type => |int_type| {
2327 try uleb128(diw, @intFromEnum(AbbrevCode.numeric_type));
2328 try wip_nav.strp(name);
2329 try diw.writeByte(switch (int_type.signedness) {
2330 inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)),
2331 });
2332 try uleb128(diw, int_type.bits);
2333 try uleb128(diw, ty.abiSize(pt));
2334 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2335 },
2336 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
2337 .One, .Many, .C => {
2338 const ptr_child_type = Type.fromInterned(ptr_type.child);
2339 try uleb128(diw, @intFromEnum(AbbrevCode.ptr_type));
2340 try wip_nav.strp(name);
2341 try diw.writeByte(@intFromBool(ptr_type.flags.is_allowzero));
2342 try uleb128(diw, ptr_type.flags.alignment.toByteUnits() orelse
2343 ptr_child_type.abiAlignment(pt).toByteUnits().?);
2344 try diw.writeByte(@intFromEnum(ptr_type.flags.address_space));
2345 if (ptr_type.flags.is_const or ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
2346 .debug_info,
2347 wip_nav.unit,
2348 wip_nav.entry,
2349 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2350 ) else try wip_nav.refType(ptr_child_type);
2351 if (ptr_type.flags.is_const) {
2352 try uleb128(diw, @intFromEnum(AbbrevCode.is_const));
2353 if (ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
2354 .debug_info,
2355 wip_nav.unit,
2356 wip_nav.entry,
2357 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2358 ) else try wip_nav.refType(ptr_child_type);
2359 }
2360 if (ptr_type.flags.is_volatile) {
2361 try uleb128(diw, @intFromEnum(AbbrevCode.is_volatile));
2362 try wip_nav.refType(ptr_child_type);
2363 }
2364 },
2365 .Slice => {
2366 try uleb128(diw, @intFromEnum(AbbrevCode.struct_type));
2367 try wip_nav.strp(name);
2368 try uleb128(diw, ty.abiSize(pt));
2369 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2370 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2371 try wip_nav.strp("ptr");
2372 const ptr_field_type = ty.slicePtrFieldType(zcu);
2373 try wip_nav.refType(ptr_field_type);
2374 try uleb128(diw, 0);
2375 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2376 try wip_nav.strp("len");
2377 const len_field_type = Type.usize;
2378 try wip_nav.refType(len_field_type);
2379 try uleb128(diw, len_field_type.abiAlignment(pt).forward(ptr_field_type.abiSize(pt)));
2380 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2381 },
2382 },
2383 inline .array_type, .vector_type => |array_type, ty_tag| {
2384 try uleb128(diw, @intFromEnum(AbbrevCode.array_type));
2385 try wip_nav.strp(name);
2386 try wip_nav.refType(Type.fromInterned(array_type.child));
2387 try diw.writeByte(@intFromBool(ty_tag == .vector_type));
2388 try uleb128(diw, @intFromEnum(AbbrevCode.array_index));
2389 try wip_nav.refType(Type.usize);
2390 try uleb128(diw, array_type.len);
2391 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2392 },
2393 .opt_type => |opt_child_type_index| {
2394 const opt_child_type = Type.fromInterned(opt_child_type_index);
2395 try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
2396 try wip_nav.strp(name);
2397 try uleb128(diw, ty.abiSize(pt));
2398 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2399 if (opt_child_type.isNoReturn(zcu)) {
2400 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2401 try wip_nav.strp("null");
2402 try wip_nav.refType(Type.null);
2403 try uleb128(diw, 0);
2404 } else {
2405 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
2406 try wip_nav.infoSectionOffset(
2407 .debug_info,
2408 wip_nav.unit,
2409 wip_nav.entry,
2410 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2411 );
2412 {
2413 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2414 try wip_nav.strp("has_value");
2415 const repr: enum { unpacked, error_set, pointer } = switch (opt_child_type_index) {
2416 .anyerror_type => .error_set,
2417 else => switch (ip.indexToKey(opt_child_type_index)) {
2418 else => .unpacked,
2419 .error_set_type, .inferred_error_set_type => .error_set,
2420 .ptr_type => |ptr_type| if (ptr_type.flags.is_allowzero) .unpacked else .pointer,
2421 },
2422 };
2423 switch (repr) {
2424 .unpacked => {
2425 try wip_nav.refType(Type.bool);
2426 try uleb128(diw, if (opt_child_type.hasRuntimeBits(pt))
2427 opt_child_type.abiSize(pt)
2428 else
2429 0);
2430 },
2431 .error_set => {
2432 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
2433 .signedness = .unsigned,
2434 .bits = pt.zcu.errorSetBits(),
2435 } })));
2436 try uleb128(diw, 0);
2437 },
2438 .pointer => {
2439 try wip_nav.refType(Type.usize);
2440 try uleb128(diw, 0);
2441 },
2442 }
25982443
2599/// The reloc offset for the line offset of a function from the previous function's line.
2600/// It's a fixed-size 4-byte ULEB128.
2601fn getRelocDbgLineOff(self: Dwarf) usize {
2602 return dbg_line_vaddr_reloc_index + self.ptrWidthBytes() + 1;
2603}
2444 try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_tagged_union_field));
2445 try uleb128(diw, 0);
2446 {
2447 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2448 try wip_nav.strp("null");
2449 try wip_nav.refType(Type.null);
2450 try uleb128(diw, 0);
2451 }
2452 try uleb128(diw, @intFromEnum(AbbrevCode.null));
26042453
2605fn getRelocDbgFileIndex(self: Dwarf) usize {
2606 return self.getRelocDbgLineOff() + 5;
2607}
2454 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union_default_field));
2455 {
2456 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2457 try wip_nav.strp("?");
2458 try wip_nav.refType(opt_child_type);
2459 try uleb128(diw, 0);
2460 }
2461 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2462 }
2463 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2464 }
2465 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2466 },
2467 .anyframe_type => unreachable,
2468 .error_union_type => |error_union_type| {
2469 const error_union_error_set_type = Type.fromInterned(error_union_type.error_set_type);
2470 const error_union_payload_type = Type.fromInterned(error_union_type.payload_type);
2471 const error_union_error_set_offset = codegen.errUnionErrorOffset(error_union_payload_type, pt);
2472 const error_union_payload_offset = codegen.errUnionPayloadOffset(error_union_payload_type, pt);
2473
2474 try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
2475 try wip_nav.strp(name);
2476 try uleb128(diw, ty.abiSize(pt));
2477 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2478 {
2479 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
2480 try wip_nav.infoSectionOffset(
2481 .debug_info,
2482 wip_nav.unit,
2483 wip_nav.entry,
2484 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2485 );
2486 {
2487 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2488 try wip_nav.strp("is_error");
2489 const is_error_field_type = Type.fromInterned(try pt.intern(.{
2490 .opt_type = error_union_type.error_set_type,
2491 }));
2492 try wip_nav.refType(is_error_field_type);
2493 try uleb128(diw, error_union_error_set_offset);
2494
2495 try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_tagged_union_field));
2496 try uleb128(diw, 0);
2497 {
2498 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2499 try wip_nav.strp("value");
2500 try wip_nav.refType(error_union_payload_type);
2501 try uleb128(diw, error_union_payload_offset);
2502 }
2503 try uleb128(diw, @intFromEnum(AbbrevCode.null));
26082504
2609fn getRelocDbgInfoSubprogramHighPC(self: Dwarf) u32 {
2610 return dbg_info_low_pc_reloc_index + self.ptrWidthBytes();
2611}
2505 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union_default_field));
2506 {
2507 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2508 try wip_nav.strp("error");
2509 try wip_nav.refType(error_union_error_set_type);
2510 try uleb128(diw, error_union_error_set_offset);
2511 }
2512 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2513 }
2514 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2515 }
2516 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2517 },
2518 .simple_type => |simple_type| switch (simple_type) {
2519 .f16,
2520 .f32,
2521 .f64,
2522 .f80,
2523 .f128,
2524 .usize,
2525 .isize,
2526 .c_char,
2527 .c_short,
2528 .c_ushort,
2529 .c_int,
2530 .c_uint,
2531 .c_long,
2532 .c_ulong,
2533 .c_longlong,
2534 .c_ulonglong,
2535 .c_longdouble,
2536 .bool,
2537 => {
2538 try uleb128(diw, @intFromEnum(AbbrevCode.numeric_type));
2539 try wip_nav.strp(name);
2540 try diw.writeByte(if (type_index == .bool_type)
2541 DW.ATE.boolean
2542 else if (ty.isRuntimeFloat())
2543 DW.ATE.float
2544 else if (ty.isSignedInt(zcu))
2545 DW.ATE.signed
2546 else if (ty.isUnsignedInt(zcu))
2547 DW.ATE.unsigned
2548 else
2549 unreachable);
2550 try uleb128(diw, ty.bitSize(pt));
2551 try uleb128(diw, ty.abiSize(pt));
2552 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2553 },
2554 .anyopaque,
2555 .void,
2556 .type,
2557 .comptime_int,
2558 .comptime_float,
2559 .noreturn,
2560 .null,
2561 .undefined,
2562 .enum_literal,
2563 .generic_poison,
2564 => {
2565 try uleb128(diw, @intFromEnum(AbbrevCode.void_type));
2566 try wip_nav.strp(if (type_index == .generic_poison_type) "anytype" else name);
2567 },
2568 .anyerror => return, // delay until flush
2569 .atomic_order,
2570 .atomic_rmw_op,
2571 .calling_convention,
2572 .address_space,
2573 .float_mode,
2574 .reduce_op,
2575 .call_modifier,
2576 .prefetch_options,
2577 .export_options,
2578 .extern_options,
2579 .type_info,
2580 .adhoc_inferred_error_set,
2581 => unreachable,
2582 },
2583 .struct_type,
2584 .union_type,
2585 .opaque_type,
2586 => unreachable,
2587 .anon_struct_type => |anon_struct_type| {
2588 try uleb128(diw, @intFromEnum(AbbrevCode.struct_type));
2589 try wip_nav.strp(name);
2590 try uleb128(diw, ty.abiSize(pt));
2591 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2592 var field_byte_offset: u64 = 0;
2593 for (0..anon_struct_type.types.len) |field_index| {
2594 const comptime_value = anon_struct_type.values.get(ip)[field_index];
2595 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (comptime_value != .none) .struct_field_comptime else .struct_field)));
2596 if (anon_struct_type.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
2597 const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
2598 defer dwarf.gpa.free(field_name);
2599 try wip_nav.strp(field_name);
2600 }
2601 const field_type = Type.fromInterned(anon_struct_type.types.get(ip)[field_index]);
2602 try wip_nav.refType(field_type);
2603 if (comptime_value == .none) {
2604 const field_align = field_type.abiAlignment(pt);
2605 field_byte_offset = field_align.forward(field_byte_offset);
2606 try uleb128(diw, field_byte_offset);
2607 try uleb128(diw, field_type.abiAlignment(pt).toByteUnits().?);
2608 field_byte_offset += field_type.abiSize(pt);
2609 }
2610 }
2611 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2612 },
2613 .enum_type => {
2614 const loaded_enum = ip.loadEnumType(type_index);
2615 try uleb128(diw, @intFromEnum(AbbrevCode.enum_type));
2616 try wip_nav.strp(name);
2617 try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
2618 for (0..loaded_enum.names.len) |field_index| {
2619 try wip_nav.enumConstValue(loaded_enum, .{
2620 .signed = .signed_enum_field,
2621 .unsigned = .unsigned_enum_field,
2622 }, field_index);
2623 try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
2624 }
2625 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2626 },
2627 .func_type => |func_type| {
2628 const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
2629 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_nullary) .nullary_func_type else .func_type)));
2630 try wip_nav.strp(name);
2631 try diw.writeByte(@intFromEnum(@as(DW.CC, switch (func_type.cc) {
2632 .Unspecified, .C => .normal,
2633 .Naked, .Async, .Inline => .nocall,
2634 .Interrupt, .Signal => .nocall,
2635 .Stdcall => .BORLAND_stdcall,
2636 .Fastcall => .BORLAND_fastcall,
2637 .Vectorcall => .LLVM_vectorcall,
2638 .Thiscall => .BORLAND_thiscall,
2639 .APCS => .nocall,
2640 .AAPCS => .LLVM_AAPCS,
2641 .AAPCSVFP => .LLVM_AAPCS_VFP,
2642 .SysV => .LLVM_X86_64SysV,
2643 .Win64 => .LLVM_Win64,
2644 .Kernel, .Fragment, .Vertex => .nocall,
2645 })));
2646 try wip_nav.refType(Type.fromInterned(func_type.return_type));
2647 if (!is_nullary) {
2648 for (0..func_type.param_types.len) |param_index| {
2649 try uleb128(diw, @intFromEnum(AbbrevCode.func_type_param));
2650 try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index]));
2651 }
2652 if (func_type.is_var_args) try uleb128(diw, @intFromEnum(AbbrevCode.is_var_args));
2653 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2654 }
2655 },
2656 .error_set_type => |error_set_type| {
2657 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (error_set_type.names.len > 0) .enum_type else .empty_enum_type)));
2658 try wip_nav.strp(name);
2659 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
2660 .signedness = .unsigned,
2661 .bits = pt.zcu.errorSetBits(),
2662 } })));
2663 for (0..error_set_type.names.len) |field_index| {
2664 const field_name = error_set_type.names.get(ip)[field_index];
2665 try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_enum_field));
2666 try uleb128(diw, ip.getErrorValueIfExists(field_name).?);
2667 try wip_nav.strp(field_name.toSlice(ip));
2668 }
2669 if (error_set_type.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
2670 },
2671 .inferred_error_set_type => |func| {
2672 try uleb128(diw, @intFromEnum(AbbrevCode.inferred_error_set_type));
2673 try wip_nav.strp(name);
2674 try wip_nav.refType(Type.fromInterned(ip.funcIesResolvedUnordered(func)));
2675 },
26122676
2613fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
2614 return actual_size +| (actual_size / ideal_factor);
2677 // values, not types
2678 .undef,
2679 .simple_value,
2680 .variable,
2681 .@"extern",
2682 .func,
2683 .int,
2684 .err,
2685 .error_union,
2686 .enum_literal,
2687 .enum_tag,
2688 .empty_enum_value,
2689 .float,
2690 .ptr,
2691 .slice,
2692 .opt,
2693 .aggregate,
2694 .un,
2695 // memoization, not types
2696 .memoized_call,
2697 => unreachable,
2698 }
2699 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
26152700}
26162701
2617pub fn flushModule(self: *Dwarf, pt: Zcu.PerThread) !void {
2618 const comp = self.bin_file.comp;
2619 const target = comp.root_mod.resolved_target.result;
2620
2621 if (self.global_abbrev_relocs.items.len > 0) {
2622 const gpa = self.allocator;
2623 var arena_alloc = std.heap.ArenaAllocator.init(gpa);
2624 defer arena_alloc.deinit();
2625 const arena = arena_alloc.allocator();
2626
2627 var dbg_info_buffer = std.ArrayList(u8).init(arena);
2628 try addDbgInfoErrorSetNames(
2629 pt,
2630 Type.anyerror,
2631 pt.zcu.intern_pool.global_error_set.getNamesFromMainThread(),
2632 target,
2633 &dbg_info_buffer,
2634 );
2635
2636 const di_atom_index = try self.createAtom(.di_atom);
2637 log.debug("updateNavDebugInfoAllocation in flushModule", .{});
2638 try self.updateNavDebugInfoAllocation(di_atom_index, @intCast(dbg_info_buffer.items.len));
2639 log.debug("writeNavDebugInfo in flushModule", .{});
2640 try self.writeNavDebugInfo(di_atom_index, dbg_info_buffer.items);
2641
2642 const file_pos = if (self.bin_file.cast(.elf)) |elf_file| pos: {
2643 const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?];
2644 break :pos debug_info_sect.sh_offset;
2645 } else if (self.bin_file.cast(.macho)) |macho_file| pos: {
2646 if (macho_file.base.isRelocatable()) {
2647 const debug_info_sect = &macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?];
2648 break :pos debug_info_sect.offset;
2649 } else {
2650 const d_sym = macho_file.getDebugSymbols().?;
2651 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
2652 break :pos debug_info_sect.offset;
2702pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternPool.Index) UpdateError!void {
2703 const zcu = pt.zcu;
2704 const ip = &zcu.intern_pool;
2705 const ty = Type.fromInterned(type_index);
2706 log.debug("updateContainerType({}({d}))", .{ ty.fmt(pt), @intFromEnum(type_index) });
2707
2708 const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip);
2709 const file = zcu.fileByIndex(inst_info.file);
2710 if (inst_info.inst == .main_struct_inst) {
2711 const unit = try dwarf.getUnit(file.mod);
2712 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
2713 if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2714 var wip_nav: WipNav = .{
2715 .dwarf = dwarf,
2716 .pt = pt,
2717 .unit = unit,
2718 .entry = type_gop.value_ptr.*,
2719 .any_children = false,
2720 .func = .none,
2721 .func_high_reloc = undefined,
2722 .debug_info = .{},
2723 .debug_line = .{},
2724 .debug_loclists = .{},
2725 .pending_types = .{},
2726 };
2727 defer wip_nav.deinit();
2728
2729 const loaded_struct = ip.loadStructType(type_index);
2730
2731 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2732 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0) .namespace_file else .file)));
2733 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
2734 try uleb128(diw, file_gop.index);
2735 try wip_nav.strp(loaded_struct.name.toSlice(ip));
2736 if (loaded_struct.field_types.len > 0) {
2737 try uleb128(diw, ty.abiSize(pt));
2738 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2739 for (0..loaded_struct.field_types.len) |field_index| {
2740 const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
2741 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
2742 if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
2743 const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
2744 defer dwarf.gpa.free(field_name);
2745 try wip_nav.strp(field_name);
2746 }
2747 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
2748 try wip_nav.refType(field_type);
2749 if (!is_comptime) {
2750 try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
2751 try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
2752 field_type.abiAlignment(pt).toByteUnits().?);
2753 }
26532754 }
2654 } else if (self.bin_file.cast(.wasm)) |_|
2655 // for wasm, the offset is always 0 as we write to memory first
2656 0
2657 else
2658 unreachable;
2755 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2756 }
26592757
2660 var buf: [@sizeOf(u32)]u8 = undefined;
2661 mem.writeInt(u32, &buf, self.getAtom(.di_atom, di_atom_index).off, target.cpu.arch.endian());
2662
2663 while (self.global_abbrev_relocs.popOrNull()) |reloc| {
2664 const atom = self.getAtom(.di_atom, reloc.atom_index);
2665 if (self.bin_file.cast(.elf)) |elf_file| {
2666 try elf_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
2667 } else if (self.bin_file.cast(.macho)) |macho_file| {
2668 if (macho_file.base.isRelocatable()) {
2669 try macho_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
2670 } else {
2671 const d_sym = macho_file.getDebugSymbols().?;
2672 try d_sym.file.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
2758 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2759 try wip_nav.flush();
2760 } else {
2761 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
2762 assert(decl_inst.tag == .extended);
2763 if (switch (decl_inst.data.extended.opcode) {
2764 .struct_decl => @as(Zir.Inst.StructDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
2765 .enum_decl => @as(Zir.Inst.EnumDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
2766 .union_decl => @as(Zir.Inst.UnionDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
2767 .opaque_decl => @as(Zir.Inst.OpaqueDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
2768 .reify => @as(Zir.Inst.NameStrategy, @enumFromInt(decl_inst.data.extended.small)),
2769 else => unreachable,
2770 } == .parent) return;
2771
2772 const unit = try dwarf.getUnit(file.mod);
2773 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
2774 if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2775 var wip_nav: WipNav = .{
2776 .dwarf = dwarf,
2777 .pt = pt,
2778 .unit = unit,
2779 .entry = type_gop.value_ptr.*,
2780 .any_children = false,
2781 .func = .none,
2782 .func_high_reloc = undefined,
2783 .debug_info = .{},
2784 .debug_line = .{},
2785 .debug_loclists = .{},
2786 .pending_types = .{},
2787 };
2788 defer wip_nav.deinit();
2789 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2790 const name = try std.fmt.allocPrint(dwarf.gpa, "{}", .{ty.fmt(pt)});
2791 defer dwarf.gpa.free(name);
2792
2793 switch (ip.indexToKey(type_index)) {
2794 .struct_type => {
2795 const loaded_struct = ip.loadStructType(type_index);
2796 switch (loaded_struct.layout) {
2797 .auto, .@"extern" => {
2798 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0)
2799 .namespace_struct_type
2800 else
2801 .struct_type)));
2802 try wip_nav.strp(name);
2803 if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
2804 try uleb128(diw, ty.abiSize(pt));
2805 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2806 for (0..loaded_struct.field_types.len) |field_index| {
2807 const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
2808 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
2809 if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
2810 const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
2811 defer dwarf.gpa.free(field_name);
2812 try wip_nav.strp(field_name);
2813 }
2814 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
2815 try wip_nav.refType(field_type);
2816 if (!is_comptime) {
2817 try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
2818 try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
2819 field_type.abiAlignment(pt).toByteUnits().?);
2820 }
2821 }
2822 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2823 }
2824 },
2825 .@"packed" => {
2826 try uleb128(diw, @intFromEnum(AbbrevCode.packed_struct_type));
2827 try wip_nav.strp(name);
2828 try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
2829 var field_bit_offset: u16 = 0;
2830 for (0..loaded_struct.field_types.len) |field_index| {
2831 try uleb128(diw, @intFromEnum(@as(AbbrevCode, .packed_struct_field)));
2832 try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip));
2833 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
2834 try wip_nav.refType(field_type);
2835 try uleb128(diw, field_bit_offset);
2836 field_bit_offset += @intCast(field_type.bitSize(pt));
2837 }
2838 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2839 },
2840 }
2841 },
2842 .enum_type => {
2843 const loaded_enum = ip.loadEnumType(type_index);
2844 try uleb128(diw, @intFromEnum(AbbrevCode.enum_type));
2845 try wip_nav.strp(name);
2846 try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
2847 for (0..loaded_enum.names.len) |field_index| {
2848 try wip_nav.enumConstValue(loaded_enum, .{
2849 .signed = .signed_enum_field,
2850 .unsigned = .unsigned_enum_field,
2851 }, field_index);
2852 try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
26732853 }
2674 } else if (self.bin_file.cast(.wasm)) |wasm_file| {
2675 _ = wasm_file;
2676 // const debug_info = wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;
2677 // debug_info.items[atom.off + reloc.offset ..][0..buf.len].* = buf;
2678 } else unreachable;
2854 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2855 },
2856 .union_type => {
2857 const loaded_union = ip.loadUnionType(type_index);
2858 try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
2859 try wip_nav.strp(name);
2860 const union_layout = pt.getUnionLayout(loaded_union);
2861 try uleb128(diw, union_layout.abi_size);
2862 try uleb128(diw, union_layout.abi_align.toByteUnits().?);
2863 const loaded_tag = loaded_union.loadTagType(ip);
2864 if (loaded_union.hasTag(ip)) {
2865 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
2866 try wip_nav.infoSectionOffset(
2867 .debug_info,
2868 wip_nav.unit,
2869 wip_nav.entry,
2870 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2871 );
2872 {
2873 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2874 try wip_nav.strp("tag");
2875 try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty));
2876 try uleb128(diw, union_layout.tagOffset());
2877
2878 for (0..loaded_union.field_types.len) |field_index| {
2879 try wip_nav.enumConstValue(loaded_tag, .{
2880 .signed = .signed_tagged_union_field,
2881 .unsigned = .unsigned_tagged_union_field,
2882 }, field_index);
2883 {
2884 try uleb128(diw, @intFromEnum(AbbrevCode.struct_field));
2885 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
2886 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
2887 try wip_nav.refType(field_type);
2888 try uleb128(diw, union_layout.payloadOffset());
2889 try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
2890 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(pt).toByteUnits().?);
2891 }
2892 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2893 }
2894 }
2895 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2896
2897 if (ip.indexToKey(loaded_union.enum_tag_ty).enum_type == .generated_tag)
2898 try wip_nav.pending_types.append(dwarf.gpa, loaded_union.enum_tag_ty);
2899 } else for (0..loaded_union.field_types.len) |field_index| {
2900 try uleb128(diw, @intFromEnum(AbbrevCode.untagged_union_field));
2901 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
2902 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
2903 try wip_nav.refType(field_type);
2904 try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
2905 field_type.abiAlignment(pt).toByteUnits().?);
2906 }
2907 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2908 },
2909 .opaque_type => {
2910 try uleb128(diw, @intFromEnum(AbbrevCode.namespace_struct_type));
2911 try wip_nav.strp(name);
2912 try diw.writeByte(@intFromBool(true));
2913 },
2914 else => unreachable,
26792915 }
2916 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2917 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items);
2918 try wip_nav.flush();
26802919 }
26812920}
26822921
2683fn addDIFile(self: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !u28 {
2684 const file_scope = zcu.navFileScope(nav_index);
2685 const gop = try self.di_files.getOrPut(self.allocator, file_scope);
2686 if (!gop.found_existing) {
2687 if (self.bin_file.cast(.elf)) |elf_file| {
2688 elf_file.markDirty(elf_file.debug_line_section_index.?);
2689 } else if (self.bin_file.cast(.macho)) |macho_file| {
2690 if (macho_file.base.isRelocatable()) {
2691 macho_file.markDirty(macho_file.debug_line_sect_index.?);
2692 } else {
2693 const d_sym = macho_file.getDebugSymbols().?;
2694 d_sym.markDirty(d_sym.debug_line_section_index.?, macho_file);
2695 }
2696 } else if (self.bin_file.cast(.wasm)) |_| {} else unreachable;
2697 }
2698 return @intCast(gop.index + 1);
2922pub fn updateNavLineNumber(dwarf: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.Index) UpdateError!void {
2923 const ip = &zcu.intern_pool;
2924
2925 const zir_index = ip.getCau(ip.getNav(nav_index).analysis_owner.unwrap() orelse return).zir_index;
2926 const inst_info = zir_index.resolveFull(ip);
2927 assert(inst_info.inst != .main_struct_inst);
2928 const file = zcu.fileByIndex(inst_info.file);
2929
2930 const inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
2931 assert(inst.tag == .declaration);
2932 const line = file.zir.extraData(Zir.Inst.Declaration, inst.data.declaration.payload_index).data.src_line;
2933 var line_buf: [4]u8 = undefined;
2934 std.mem.writeInt(u32, &line_buf, line, dwarf.endian);
2935
2936 const unit = dwarf.debug_line.section.getUnit(dwarf.mods.get(file.mod).?);
2937 const entry = unit.getEntry(dwarf.navs.get(nav_index).?);
2938 try dwarf.getFile().?.pwriteAll(&line, dwarf.debug_line.section.off + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf));
26992939}
27002940
2701fn genIncludeDirsAndFileNames(self: *Dwarf, arena: Allocator) !struct {
2702 dirs: []const []const u8,
2703 files: []const []const u8,
2704 files_dirs_indexes: []u28,
2705} {
2706 var dirs = std.StringArrayHashMap(void).init(arena);
2707 try dirs.ensureTotalCapacity(self.di_files.count());
2708
2709 var files = std.ArrayList([]const u8).init(arena);
2710 try files.ensureTotalCapacityPrecise(self.di_files.count());
2711
2712 var files_dir_indexes = std.ArrayList(u28).init(arena);
2713 try files_dir_indexes.ensureTotalCapacity(self.di_files.count());
2714
2715 for (self.di_files.keys()) |dif| {
2716 const full_path = try dif.mod.root.joinString(arena, dif.sub_file_path);
2717 const dir_path = std.fs.path.dirname(full_path) orelse ".";
2718 const sub_file_path = std.fs.path.basename(full_path);
2719 // https://github.com/ziglang/zig/issues/19353
2720 var buffer: [std.fs.max_path_bytes]u8 = undefined;
2721 const resolved = if (!std.fs.path.isAbsolute(dir_path))
2722 std.posix.realpath(dir_path, &buffer) catch dir_path
2723 else
2724 dir_path;
2941pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void {
2942 _ = dwarf;
2943 _ = nav_index;
2944}
27252945
2726 const dir_index: u28 = index: {
2727 const dirs_gop = dirs.getOrPutAssumeCapacity(try arena.dupe(u8, resolved));
2728 break :index @intCast(dirs_gop.index + 1);
2946pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
2947 const ip = &pt.zcu.intern_pool;
2948 if (dwarf.types.get(.anyerror_type)) |entry| {
2949 var wip_nav: WipNav = .{
2950 .dwarf = dwarf,
2951 .pt = pt,
2952 .unit = .main,
2953 .entry = entry,
2954 .any_children = false,
2955 .func = .none,
2956 .func_high_reloc = undefined,
2957 .debug_info = .{},
2958 .debug_line = .{},
2959 .debug_loclists = .{},
2960 .pending_types = .{},
27292961 };
2962 defer wip_nav.deinit();
2963 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2964 const global_error_set_names = ip.global_error_set.getNamesFromMainThread();
2965 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (global_error_set_names.len > 0) .enum_type else .empty_enum_type)));
2966 try wip_nav.strp("anyerror");
2967 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
2968 .signedness = .unsigned,
2969 .bits = pt.zcu.errorSetBits(),
2970 } })));
2971 for (global_error_set_names, 1..) |name, value| {
2972 try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_enum_field));
2973 try uleb128(diw, value);
2974 try wip_nav.strp(name.toSlice(ip));
2975 }
2976 if (global_error_set_names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
2977 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2978 }
27302979
2731 files_dir_indexes.appendAssumeCapacity(dir_index);
2732 files.appendAssumeCapacity(sub_file_path);
2980 {
2981 const cwd = try std.process.getCwdAlloc(dwarf.gpa);
2982 defer dwarf.gpa.free(cwd);
2983 for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {
2984 const root_dir_path = try std.fs.path.resolve(dwarf.gpa, &.{
2985 cwd,
2986 mod.root.root_dir.path orelse "",
2987 mod.root.sub_path,
2988 });
2989 defer dwarf.gpa.free(root_dir_path);
2990 mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);
2991 }
27332992 }
27342993
2735 return .{
2736 .dirs = dirs.keys(),
2737 .files = files.items,
2738 .files_dirs_indexes = files_dir_indexes.items,
2739 };
2994 var header = std.ArrayList(u8).init(dwarf.gpa);
2995 defer header.deinit();
2996 if (dwarf.debug_abbrev.section.dirty) {
2997 for (1.., &AbbrevCode.abbrevs) |code, *abbrev| {
2998 try uleb128(header.writer(), code);
2999 try uleb128(header.writer(), @intFromEnum(abbrev.tag));
3000 try header.append(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no);
3001 for (abbrev.attrs) |*attr| {
3002 try uleb128(header.writer(), @intFromEnum(attr[0]));
3003 try uleb128(header.writer(), @intFromEnum(attr[1]));
3004 }
3005 try header.appendSlice(&.{ 0, 0 });
3006 }
3007 try header.append(@intFromEnum(AbbrevCode.null));
3008 try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, DebugAbbrev.entry, dwarf, header.items);
3009 dwarf.debug_abbrev.section.dirty = false;
3010 }
3011 if (dwarf.debug_aranges.section.dirty) {
3012 for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| {
3013 const unit: Unit.Index = @enumFromInt(unit_index);
3014 try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 1);
3015 header.clearRetainingCapacity();
3016 try header.ensureTotalCapacity(unit_ptr.header_len);
3017 const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
3018 dwarf.debug_aranges.section.getUnit(next_unit).off
3019 else
3020 dwarf.debug_aranges.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
3021 switch (dwarf.format) {
3022 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3023 .@"64" => {
3024 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3025 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3026 },
3027 }
3028 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 2, dwarf.endian);
3029 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3030 .source_off = @intCast(header.items.len),
3031 .target_sec = .debug_info,
3032 .target_unit = unit,
3033 });
3034 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3035 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
3036 header.appendNTimesAssumeCapacity(0, unit_ptr.header_len - header.items.len);
3037 try unit_ptr.replaceHeader(&dwarf.debug_aranges.section, dwarf, header.items);
3038 try unit_ptr.writeTrailer(&dwarf.debug_aranges.section, dwarf);
3039 }
3040 dwarf.debug_aranges.section.dirty = false;
3041 }
3042 if (dwarf.debug_info.section.dirty) {
3043 for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| {
3044 const unit: Unit.Index = @enumFromInt(unit_index);
3045 try unit_ptr.cross_unit_relocs.ensureUnusedCapacity(dwarf.gpa, 1);
3046 try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 7);
3047 header.clearRetainingCapacity();
3048 try header.ensureTotalCapacity(unit_ptr.header_len);
3049 const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
3050 dwarf.debug_info.section.getUnit(next_unit).off
3051 else
3052 dwarf.debug_info.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
3053 switch (dwarf.format) {
3054 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3055 .@"64" => {
3056 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3057 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3058 },
3059 }
3060 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
3061 header.appendSliceAssumeCapacity(&.{ DW.UT.compile, @intFromEnum(dwarf.address_size) });
3062 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3063 .source_off = @intCast(header.items.len),
3064 .target_sec = .debug_abbrev,
3065 .target_unit = DebugAbbrev.unit,
3066 .target_entry = DebugAbbrev.entry.toOptional(),
3067 });
3068 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3069 const compile_unit_off: u32 = @intCast(header.items.len);
3070 uleb128(header.fixedWriter(), @intFromEnum(AbbrevCode.compile_unit)) catch unreachable;
3071 header.appendAssumeCapacity(DW.LANG.Zig);
3072 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3073 .source_off = @intCast(header.items.len),
3074 .target_sec = .debug_line_str,
3075 .target_unit = StringSection.unit,
3076 .target_entry = (try dwarf.debug_line_str.addString(dwarf, "zig " ++ @import("build_options").version)).toOptional(),
3077 });
3078 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3079 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3080 .source_off = @intCast(header.items.len),
3081 .target_sec = .debug_line_str,
3082 .target_unit = StringSection.unit,
3083 .target_entry = mod_info.root_dir_path.toOptional(),
3084 });
3085 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3086 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3087 .source_off = @intCast(header.items.len),
3088 .target_sec = .debug_line_str,
3089 .target_unit = StringSection.unit,
3090 .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod.root_src_path)).toOptional(),
3091 });
3092 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3093 unit_ptr.cross_unit_relocs.appendAssumeCapacity(.{
3094 .source_off = @intCast(header.items.len),
3095 .target_unit = .main,
3096 .target_off = compile_unit_off,
3097 });
3098 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3099 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3100 .source_off = @intCast(header.items.len),
3101 .target_sec = .debug_line,
3102 .target_unit = unit,
3103 });
3104 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3105 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3106 .source_off = @intCast(header.items.len),
3107 .target_sec = .debug_rnglists,
3108 .target_unit = unit,
3109 .target_off = DebugRngLists.baseOffset(dwarf),
3110 });
3111 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3112 uleb128(header.fixedWriter(), 0) catch unreachable;
3113 uleb128(header.fixedWriter(), @intFromEnum(AbbrevCode.module)) catch unreachable;
3114 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3115 .source_off = @intCast(header.items.len),
3116 .target_sec = .debug_str,
3117 .target_unit = StringSection.unit,
3118 .target_entry = (try dwarf.debug_str.addString(dwarf, mod.fully_qualified_name)).toOptional(),
3119 });
3120 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3121 uleb128(header.fixedWriter(), 0) catch unreachable;
3122 try unit_ptr.replaceHeader(&dwarf.debug_info.section, dwarf, header.items);
3123 try unit_ptr.writeTrailer(&dwarf.debug_info.section, dwarf);
3124 }
3125 dwarf.debug_info.section.dirty = false;
3126 }
3127 if (dwarf.debug_str.section.dirty) {
3128 const contents = dwarf.debug_str.contents.items;
3129 try dwarf.debug_str.section.resize(dwarf, contents.len);
3130 try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_str.section.off);
3131 dwarf.debug_str.section.dirty = false;
3132 }
3133 if (dwarf.debug_line.section.dirty) {
3134 for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit|
3135 try unit.resizeHeader(&dwarf.debug_line.section, dwarf, DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count())));
3136 for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| {
3137 try unit.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 2 * (1 + mod_info.files.count()));
3138 header.clearRetainingCapacity();
3139 try header.ensureTotalCapacity(unit.header_len);
3140 const unit_len = (if (unit.next.unwrap()) |next_unit|
3141 dwarf.debug_line.section.getUnit(next_unit).off
3142 else
3143 dwarf.debug_line.section.len) - unit.off - dwarf.unitLengthBytes();
3144 switch (dwarf.format) {
3145 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3146 .@"64" => {
3147 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3148 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3149 },
3150 }
3151 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
3152 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
3153 switch (dwarf.format) {
3154 inline .@"32", .@"64" => |format| std.mem.writeInt(
3155 SectionOffset(format),
3156 header.addManyAsArrayAssumeCapacity(@sizeOf(SectionOffset(format))),
3157 @intCast(unit.header_len - header.items.len),
3158 dwarf.endian,
3159 ),
3160 }
3161 const StandardOpcode = DeclValEnum(DW.LNS);
3162 header.appendSliceAssumeCapacity(&[_]u8{
3163 dwarf.debug_line.header.minimum_instruction_length,
3164 dwarf.debug_line.header.maximum_operations_per_instruction,
3165 @intFromBool(dwarf.debug_line.header.default_is_stmt),
3166 @bitCast(dwarf.debug_line.header.line_base),
3167 dwarf.debug_line.header.line_range,
3168 dwarf.debug_line.header.opcode_base,
3169 });
3170 header.appendSliceAssumeCapacity(std.enums.EnumArray(StandardOpcode, u8).init(.{
3171 .extended_op = undefined,
3172 .copy = 0,
3173 .advance_pc = 1,
3174 .advance_line = 1,
3175 .set_file = 1,
3176 .set_column = 1,
3177 .negate_stmt = 0,
3178 .set_basic_block = 0,
3179 .const_add_pc = 0,
3180 .fixed_advance_pc = 1,
3181 .set_prologue_end = 0,
3182 .set_epilogue_begin = 0,
3183 .set_isa = 1,
3184 }).values[1..dwarf.debug_line.header.opcode_base]);
3185 header.appendAssumeCapacity(1);
3186 uleb128(header.fixedWriter(), DW.LNCT.path) catch unreachable;
3187 uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable;
3188 uleb128(header.fixedWriter(), mod_info.dirs.count()) catch unreachable;
3189 for (mod_info.dirs.keys()) |dir_unit| {
3190 unit.cross_section_relocs.appendAssumeCapacity(.{
3191 .source_off = @intCast(header.items.len),
3192 .target_sec = .debug_line_str,
3193 .target_unit = StringSection.unit,
3194 .target_entry = dwarf.getModInfo(dir_unit).root_dir_path.toOptional(),
3195 });
3196 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3197 }
3198 const dir_index_info = DebugLine.dirIndexInfo(@intCast(mod_info.dirs.count()));
3199 header.appendAssumeCapacity(3);
3200 uleb128(header.fixedWriter(), DW.LNCT.path) catch unreachable;
3201 uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable;
3202 uleb128(header.fixedWriter(), DW.LNCT.directory_index) catch unreachable;
3203 uleb128(header.fixedWriter(), @intFromEnum(dir_index_info.form)) catch unreachable;
3204 uleb128(header.fixedWriter(), DW.LNCT.LLVM_source) catch unreachable;
3205 uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable;
3206 uleb128(header.fixedWriter(), mod_info.files.count()) catch unreachable;
3207 for (mod_info.files.keys()) |file_index| {
3208 const file = pt.zcu.fileByIndex(file_index);
3209 unit.cross_section_relocs.appendAssumeCapacity(.{
3210 .source_off = @intCast(header.items.len),
3211 .target_sec = .debug_line_str,
3212 .target_unit = StringSection.unit,
3213 .target_entry = (try dwarf.debug_line_str.addString(dwarf, file.sub_file_path)).toOptional(),
3214 });
3215 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3216 dwarf.writeInt(
3217 header.addManyAsSliceAssumeCapacity(dir_index_info.bytes),
3218 mod_info.dirs.getIndex(dwarf.getUnitIfExists(file.mod).?).?,
3219 );
3220 unit.cross_section_relocs.appendAssumeCapacity(.{
3221 .source_off = @intCast(header.items.len),
3222 .target_sec = .debug_line_str,
3223 .target_unit = StringSection.unit,
3224 .target_entry = (try dwarf.debug_line_str.addString(
3225 dwarf,
3226 if (file.mod.builtin_file == file) file.source else "",
3227 )).toOptional(),
3228 });
3229 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3230 }
3231 try unit.replaceHeader(&dwarf.debug_line.section, dwarf, header.items);
3232 try unit.writeTrailer(&dwarf.debug_line.section, dwarf);
3233 }
3234 dwarf.debug_line.section.dirty = false;
3235 }
3236 if (dwarf.debug_line_str.section.dirty) {
3237 const contents = dwarf.debug_line_str.contents.items;
3238 try dwarf.debug_line_str.section.resize(dwarf, contents.len);
3239 try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off);
3240 dwarf.debug_line_str.section.dirty = false;
3241 }
3242 if (dwarf.debug_rnglists.section.dirty) {
3243 for (dwarf.debug_rnglists.section.units.items) |*unit| {
3244 header.clearRetainingCapacity();
3245 try header.ensureTotalCapacity(unit.header_len);
3246 const unit_len = (if (unit.next.unwrap()) |next_unit|
3247 dwarf.debug_rnglists.section.getUnit(next_unit).off
3248 else
3249 dwarf.debug_rnglists.section.len) - unit.off - dwarf.unitLengthBytes();
3250 switch (dwarf.format) {
3251 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3252 .@"64" => {
3253 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3254 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3255 },
3256 }
3257 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
3258 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
3259 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), 1, dwarf.endian);
3260 switch (dwarf.format) {
3261 inline .@"32", .@"64" => |format| std.mem.writeInt(
3262 SectionOffset(format),
3263 header.addManyAsArrayAssumeCapacity(@sizeOf(SectionOffset(format))),
3264 @sizeOf(SectionOffset(format)),
3265 dwarf.endian,
3266 ),
3267 }
3268 try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header.items);
3269 try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf);
3270 }
3271 dwarf.debug_rnglists.section.dirty = false;
3272 }
27403273}
27413274
2742fn addDbgInfoErrorSet(
2743 pt: Zcu.PerThread,
2744 ty: Type,
2745 target: std.Target,
2746 dbg_info_buffer: *std.ArrayList(u8),
2747) !void {
2748 return addDbgInfoErrorSetNames(pt, ty, ty.errorSetNames(pt.zcu).get(&pt.zcu.intern_pool), target, dbg_info_buffer);
3275pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void {
3276 for ([_]*Section{
3277 &dwarf.debug_abbrev.section,
3278 &dwarf.debug_aranges.section,
3279 &dwarf.debug_info.section,
3280 &dwarf.debug_line.section,
3281 &dwarf.debug_line_str.section,
3282 &dwarf.debug_loclists.section,
3283 &dwarf.debug_rnglists.section,
3284 &dwarf.debug_str.section,
3285 }) |sec| try sec.resolveRelocs(dwarf);
27493286}
27503287
2751fn addDbgInfoErrorSetNames(
2752 pt: Zcu.PerThread,
2753 /// Used for printing the type name only.
2754 ty: Type,
2755 error_names: []const InternPool.NullTerminatedString,
2756 target: std.Target,
2757 dbg_info_buffer: *std.ArrayList(u8),
2758) !void {
2759 const target_endian = target.cpu.arch.endian();
2760
2761 // DW.AT.enumeration_type
2762 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.enum_type));
2763 // DW.AT.byte_size, DW.FORM.udata
2764 const abi_size = Type.anyerror.abiSize(pt);
2765 try leb128.writeUleb128(dbg_info_buffer.writer(), abi_size);
2766 // DW.AT.name, DW.FORM.string
2767 try ty.print(dbg_info_buffer.writer(), pt);
2768 try dbg_info_buffer.append(0);
2769
2770 // DW.AT.enumerator
2771 const no_error = "(no error)";
2772 try dbg_info_buffer.ensureUnusedCapacity(no_error.len + 2 + @sizeOf(u64));
2773 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.enum_variant));
2774 // DW.AT.name, DW.FORM.string
2775 dbg_info_buffer.appendSliceAssumeCapacity(no_error);
2776 dbg_info_buffer.appendAssumeCapacity(0);
2777 // DW.AT.const_value, DW.FORM.data8
2778 mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), 0, target_endian);
2779
2780 for (error_names) |error_name| {
2781 const int = try pt.getErrorValue(error_name);
2782 const error_name_slice = error_name.toSlice(&pt.zcu.intern_pool);
2783 // DW.AT.enumerator
2784 try dbg_info_buffer.ensureUnusedCapacity(error_name_slice.len + 2 + @sizeOf(u64));
2785 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.enum_variant));
2786 // DW.AT.name, DW.FORM.string
2787 dbg_info_buffer.appendSliceAssumeCapacity(error_name_slice[0 .. error_name_slice.len + 1]);
2788 // DW.AT.const_value, DW.FORM.data8
2789 mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), int, target_endian);
2790 }
2791
2792 // DW.AT.enumeration_type delimit children
2793 try dbg_info_buffer.append(0);
3288fn DeclValEnum(comptime T: type) type {
3289 const decls = @typeInfo(T).Struct.decls;
3290 @setEvalBranchQuota(7 * decls.len);
3291 var fields: [decls.len]std.builtin.Type.EnumField = undefined;
3292 var fields_len = 0;
3293 var min_value: ?comptime_int = null;
3294 var max_value: ?comptime_int = null;
3295 for (decls) |decl| {
3296 if (std.mem.startsWith(u8, decl.name, "HP_") or std.mem.endsWith(u8, decl.name, "_user")) continue;
3297 const value = @field(T, decl.name);
3298 fields[fields_len] = .{ .name = decl.name, .value = value };
3299 fields_len += 1;
3300 if (min_value == null or min_value.? > value) min_value = value;
3301 if (max_value == null or max_value.? < value) max_value = value;
3302 }
3303 return @Type(.{ .Enum = .{
3304 .tag_type = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0),
3305 .fields = fields[0..fields_len],
3306 .decls = &.{},
3307 .is_exhaustive = true,
3308 } });
27943309}
27953310
2796const Kind = enum { src_fn, di_atom };
3311const AbbrevCode = enum(u8) {
3312 null,
3313 // padding codes must be one byte uleb128 values to function
3314 pad_1,
3315 pad_n,
3316 // decl codes are assumed to all have the same uleb128 length
3317 decl_alias,
3318 decl_enum,
3319 decl_namespace_struct,
3320 decl_struct,
3321 decl_packed_struct,
3322 decl_union,
3323 decl_var,
3324 decl_func,
3325 decl_func_empty,
3326 // the rest are unrestricted
3327 compile_unit,
3328 module,
3329 namespace_file,
3330 file,
3331 signed_enum_field,
3332 unsigned_enum_field,
3333 generated_field,
3334 struct_field,
3335 struct_field_comptime,
3336 packed_struct_field,
3337 untagged_union_field,
3338 tagged_union,
3339 signed_tagged_union_field,
3340 unsigned_tagged_union_field,
3341 tagged_union_default_field,
3342 void_type,
3343 numeric_type,
3344 inferred_error_set_type,
3345 ptr_type,
3346 is_const,
3347 is_volatile,
3348 array_type,
3349 array_index,
3350 nullary_func_type,
3351 func_type,
3352 func_type_param,
3353 is_var_args,
3354 enum_type,
3355 empty_enum_type,
3356 namespace_struct_type,
3357 struct_type,
3358 packed_struct_type,
3359 union_type,
3360 local_arg,
3361 local_var,
27973362
2798fn createAtom(self: *Dwarf, comptime kind: Kind) !Atom.Index {
2799 const index = blk: {
2800 switch (kind) {
2801 .src_fn => {
2802 const index: Atom.Index = @intCast(self.src_fns.items.len);
2803 _ = try self.src_fns.addOne(self.allocator);
2804 break :blk index;
2805 },
2806 .di_atom => {
2807 const index: Atom.Index = @intCast(self.di_atoms.items.len);
2808 _ = try self.di_atoms.addOne(self.allocator);
2809 break :blk index;
2810 },
2811 }
3363 const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_func_empty));
3364
3365 const Attr = struct {
3366 DeclValEnum(DW.AT),
3367 DeclValEnum(DW.FORM),
28123368 };
2813 const atom = self.getAtomPtr(kind, index);
2814 atom.* = .{
2815 .off = 0,
2816 .len = 0,
2817 .prev_index = null,
2818 .next_index = null,
3369 const decl_abbrev_common_attrs = &[_]Attr{
3370 .{ .ZIG_parent, .ref_addr },
3371 .{ .decl_line, .data4 },
3372 .{ .decl_column, .udata },
3373 .{ .accessibility, .data1 },
3374 .{ .name, .strp },
28193375 };
2820 return index;
2821}
2822
2823fn getOrCreateAtomForNav(self: *Dwarf, comptime kind: Kind, nav_index: InternPool.Nav.Index) !Atom.Index {
2824 switch (kind) {
2825 .src_fn => {
2826 const gop = try self.src_fn_navs.getOrPut(self.allocator, nav_index);
2827 if (!gop.found_existing) {
2828 gop.value_ptr.* = try self.createAtom(kind);
2829 }
2830 return gop.value_ptr.*;
3376 const abbrevs = std.EnumArray(AbbrevCode, struct {
3377 tag: DeclValEnum(DW.TAG),
3378 children: bool = false,
3379 attrs: []const Attr = &.{},
3380 }).init(.{
3381 .pad_1 = .{
3382 .tag = .ZIG_padding,
28313383 },
2832 .di_atom => {
2833 const gop = try self.di_atom_navs.getOrPut(self.allocator, nav_index);
2834 if (!gop.found_existing) {
2835 gop.value_ptr.* = try self.createAtom(kind);
2836 }
2837 return gop.value_ptr.*;
3384 .pad_n = .{
3385 .tag = .ZIG_padding,
3386 .attrs = &.{
3387 .{ .ZIG_padding, .block },
3388 },
3389 },
3390 .decl_alias = .{
3391 .tag = .imported_declaration,
3392 .attrs = decl_abbrev_common_attrs ++ .{
3393 .{ .import, .ref_addr },
3394 },
3395 },
3396 .decl_enum = .{
3397 .tag = .enumeration_type,
3398 .children = true,
3399 .attrs = decl_abbrev_common_attrs ++ .{
3400 .{ .type, .ref_addr },
3401 },
3402 },
3403 .decl_namespace_struct = .{
3404 .tag = .structure_type,
3405 .attrs = decl_abbrev_common_attrs ++ .{
3406 .{ .declaration, .flag },
3407 },
3408 },
3409 .decl_struct = .{
3410 .tag = .structure_type,
3411 .children = true,
3412 .attrs = decl_abbrev_common_attrs ++ .{
3413 .{ .byte_size, .udata },
3414 .{ .alignment, .udata },
3415 },
3416 },
3417 .decl_packed_struct = .{
3418 .tag = .structure_type,
3419 .children = true,
3420 .attrs = decl_abbrev_common_attrs ++ .{
3421 .{ .type, .ref_addr },
3422 },
3423 },
3424 .decl_union = .{
3425 .tag = .union_type,
3426 .children = true,
3427 .attrs = decl_abbrev_common_attrs ++ .{
3428 .{ .byte_size, .udata },
3429 .{ .alignment, .udata },
3430 },
3431 },
3432 .decl_var = .{
3433 .tag = .variable,
3434 .attrs = decl_abbrev_common_attrs ++ .{
3435 .{ .linkage_name, .strp },
3436 .{ .type, .ref_addr },
3437 .{ .location, .exprloc },
3438 .{ .alignment, .udata },
3439 .{ .external, .flag },
3440 },
3441 },
3442 .decl_func = .{
3443 .tag = .subprogram,
3444 .children = true,
3445 .attrs = decl_abbrev_common_attrs ++ .{
3446 .{ .linkage_name, .strp },
3447 .{ .type, .ref_addr },
3448 .{ .low_pc, .addr },
3449 .{ .high_pc, .addr },
3450 .{ .alignment, .udata },
3451 .{ .external, .flag },
3452 .{ .noreturn, .flag },
3453 },
3454 },
3455 .decl_func_empty = .{
3456 .tag = .subprogram,
3457 .attrs = decl_abbrev_common_attrs ++ .{
3458 .{ .linkage_name, .strp },
3459 .{ .type, .ref_addr },
3460 .{ .low_pc, .addr },
3461 .{ .high_pc, .addr },
3462 .{ .alignment, .udata },
3463 .{ .external, .flag },
3464 .{ .noreturn, .flag },
3465 },
3466 },
3467 .compile_unit = .{
3468 .tag = .compile_unit,
3469 .children = true,
3470 .attrs = &.{
3471 .{ .language, .data1 },
3472 .{ .producer, .line_strp },
3473 .{ .comp_dir, .line_strp },
3474 .{ .name, .line_strp },
3475 .{ .base_types, .ref_addr },
3476 .{ .stmt_list, .sec_offset },
3477 .{ .rnglists_base, .sec_offset },
3478 .{ .ranges, .rnglistx },
3479 },
3480 },
3481 .module = .{
3482 .tag = .module,
3483 .children = true,
3484 .attrs = &.{
3485 .{ .name, .strp },
3486 .{ .ranges, .rnglistx },
3487 },
3488 },
3489 .namespace_file = .{
3490 .tag = .structure_type,
3491 .attrs = &.{
3492 .{ .decl_file, .udata },
3493 .{ .name, .strp },
3494 },
3495 },
3496 .file = .{
3497 .tag = .structure_type,
3498 .children = true,
3499 .attrs = &.{
3500 .{ .decl_file, .udata },
3501 .{ .name, .strp },
3502 .{ .byte_size, .udata },
3503 .{ .alignment, .udata },
3504 },
3505 },
3506 .signed_enum_field = .{
3507 .tag = .enumerator,
3508 .attrs = &.{
3509 .{ .const_value, .sdata },
3510 .{ .name, .strp },
3511 },
3512 },
3513 .unsigned_enum_field = .{
3514 .tag = .enumerator,
3515 .attrs = &.{
3516 .{ .const_value, .udata },
3517 .{ .name, .strp },
3518 },
3519 },
3520 .generated_field = .{
3521 .tag = .member,
3522 .attrs = &.{
3523 .{ .name, .strp },
3524 .{ .type, .ref_addr },
3525 .{ .data_member_location, .udata },
3526 .{ .artificial, .flag_present },
3527 },
3528 },
3529 .struct_field = .{
3530 .tag = .member,
3531 .attrs = &.{
3532 .{ .name, .strp },
3533 .{ .type, .ref_addr },
3534 .{ .data_member_location, .udata },
3535 .{ .alignment, .udata },
3536 },
3537 },
3538 .struct_field_comptime = .{
3539 .tag = .member,
3540 .attrs = &.{
3541 .{ .name, .strp },
3542 .{ .type, .ref_addr },
3543 .{ .const_expr, .flag_present },
3544 },
3545 },
3546 .packed_struct_field = .{
3547 .tag = .member,
3548 .attrs = &.{
3549 .{ .name, .strp },
3550 .{ .type, .ref_addr },
3551 .{ .data_bit_offset, .udata },
3552 },
3553 },
3554 .untagged_union_field = .{
3555 .tag = .member,
3556 .attrs = &.{
3557 .{ .name, .strp },
3558 .{ .type, .ref_addr },
3559 .{ .alignment, .udata },
3560 },
3561 },
3562 .tagged_union = .{
3563 .tag = .variant_part,
3564 .children = true,
3565 .attrs = &.{
3566 .{ .discr, .ref_addr },
3567 },
3568 },
3569 .signed_tagged_union_field = .{
3570 .tag = .variant,
3571 .children = true,
3572 .attrs = &.{
3573 .{ .discr_value, .sdata },
3574 },
3575 },
3576 .unsigned_tagged_union_field = .{
3577 .tag = .variant,
3578 .children = true,
3579 .attrs = &.{
3580 .{ .discr_value, .udata },
3581 },
3582 },
3583 .tagged_union_default_field = .{
3584 .tag = .variant,
3585 .children = true,
3586 .attrs = &.{},
3587 },
3588 .void_type = .{
3589 .tag = .unspecified_type,
3590 .attrs = &.{
3591 .{ .name, .strp },
3592 },
3593 },
3594 .numeric_type = .{
3595 .tag = .base_type,
3596 .attrs = &.{
3597 .{ .name, .strp },
3598 .{ .encoding, .data1 },
3599 .{ .bit_size, .udata },
3600 .{ .byte_size, .udata },
3601 .{ .alignment, .udata },
3602 },
3603 },
3604 .inferred_error_set_type = .{
3605 .tag = .typedef,
3606 .attrs = &.{
3607 .{ .name, .strp },
3608 .{ .type, .ref_addr },
3609 },
3610 },
3611 .ptr_type = .{
3612 .tag = .pointer_type,
3613 .attrs = &.{
3614 .{ .name, .strp },
3615 .{ .ZIG_is_allowzero, .flag },
3616 .{ .alignment, .udata },
3617 .{ .address_class, .data1 },
3618 .{ .type, .ref_addr },
3619 },
3620 },
3621 .is_const = .{
3622 .tag = .const_type,
3623 .attrs = &.{
3624 .{ .type, .ref_addr },
3625 },
3626 },
3627 .is_volatile = .{
3628 .tag = .volatile_type,
3629 .attrs = &.{
3630 .{ .type, .ref_addr },
3631 },
3632 },
3633 .array_type = .{
3634 .tag = .array_type,
3635 .children = true,
3636 .attrs = &.{
3637 .{ .name, .strp },
3638 .{ .type, .ref_addr },
3639 .{ .GNU_vector, .flag },
3640 },
3641 },
3642 .array_index = .{
3643 .tag = .subrange_type,
3644 .attrs = &.{
3645 .{ .type, .ref_addr },
3646 .{ .count, .udata },
3647 },
3648 },
3649 .nullary_func_type = .{
3650 .tag = .subroutine_type,
3651 .attrs = &.{
3652 .{ .name, .strp },
3653 .{ .calling_convention, .data1 },
3654 .{ .type, .ref_addr },
3655 },
3656 },
3657 .func_type = .{
3658 .tag = .subroutine_type,
3659 .children = true,
3660 .attrs = &.{
3661 .{ .name, .strp },
3662 .{ .calling_convention, .data1 },
3663 .{ .type, .ref_addr },
3664 },
28383665 },
3666 .func_type_param = .{
3667 .tag = .formal_parameter,
3668 .attrs = &.{
3669 .{ .type, .ref_addr },
3670 },
3671 },
3672 .is_var_args = .{
3673 .tag = .unspecified_parameters,
3674 },
3675 .enum_type = .{
3676 .tag = .enumeration_type,
3677 .children = true,
3678 .attrs = &.{
3679 .{ .name, .strp },
3680 .{ .type, .ref_addr },
3681 },
3682 },
3683 .empty_enum_type = .{
3684 .tag = .enumeration_type,
3685 .attrs = &.{
3686 .{ .name, .strp },
3687 .{ .type, .ref_addr },
3688 },
3689 },
3690 .namespace_struct_type = .{
3691 .tag = .structure_type,
3692 .attrs = &.{
3693 .{ .name, .strp },
3694 .{ .declaration, .flag },
3695 },
3696 },
3697 .struct_type = .{
3698 .tag = .structure_type,
3699 .children = true,
3700 .attrs = &.{
3701 .{ .name, .strp },
3702 .{ .byte_size, .udata },
3703 .{ .alignment, .udata },
3704 },
3705 },
3706 .packed_struct_type = .{
3707 .tag = .structure_type,
3708 .children = true,
3709 .attrs = &.{
3710 .{ .name, .strp },
3711 .{ .type, .ref_addr },
3712 },
3713 },
3714 .union_type = .{
3715 .tag = .union_type,
3716 .children = true,
3717 .attrs = &.{
3718 .{ .name, .strp },
3719 .{ .byte_size, .udata },
3720 .{ .alignment, .udata },
3721 },
3722 },
3723 .local_arg = .{
3724 .tag = .formal_parameter,
3725 .attrs = &.{
3726 .{ .name, .strp },
3727 .{ .type, .ref_addr },
3728 .{ .location, .exprloc },
3729 },
3730 },
3731 .local_var = .{
3732 .tag = .variable,
3733 .attrs = &.{
3734 .{ .name, .strp },
3735 .{ .type, .ref_addr },
3736 .{ .location, .exprloc },
3737 },
3738 },
3739 .null = undefined,
3740 }).values[1..].*;
3741};
3742
3743fn getFile(dwarf: *Dwarf) ?std.fs.File {
3744 if (dwarf.bin_file.cast(.macho)) |macho_file| if (macho_file.d_sym) |*d_sym| return d_sym.file;
3745 return dwarf.bin_file.file;
3746}
3747
3748fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {
3749 const entry = try dwarf.debug_aranges.section.addEntry(unit, dwarf);
3750 assert(try dwarf.debug_info.section.addEntry(unit, dwarf) == entry);
3751 assert(try dwarf.debug_line.section.addEntry(unit, dwarf) == entry);
3752 assert(try dwarf.debug_loclists.section.addEntry(unit, dwarf) == entry);
3753 assert(try dwarf.debug_rnglists.section.addEntry(unit, dwarf) == entry);
3754 return entry;
3755}
3756
3757fn writeInt(dwarf: *Dwarf, buf: []u8, int: u64) void {
3758 switch (buf.len) {
3759 inline 0...8 => |len| std.mem.writeInt(@Type(.{ .Int = .{
3760 .signedness = .unsigned,
3761 .bits = len * 8,
3762 } }), buf[0..len], @intCast(int), dwarf.endian),
3763 else => unreachable,
28393764 }
28403765}
28413766
2842fn getAtom(self: *const Dwarf, comptime kind: Kind, index: Atom.Index) Atom {
2843 return switch (kind) {
2844 .src_fn => self.src_fns.items[index],
2845 .di_atom => self.di_atoms.items[index],
2846 };
3767fn resolveReloc(dwarf: *Dwarf, source: u64, target: u64, size: u32) RelocError!void {
3768 var buf: [8]u8 = undefined;
3769 dwarf.writeInt(buf[0..size], target);
3770 try dwarf.getFile().?.pwriteAll(buf[0..size], source);
28473771}
28483772
2849fn getAtomPtr(self: *Dwarf, comptime kind: Kind, index: Atom.Index) *Atom {
2850 return switch (kind) {
2851 .src_fn => &self.src_fns.items[index],
2852 .di_atom => &self.di_atoms.items[index],
3773fn unitLengthBytes(dwarf: *Dwarf) u32 {
3774 return switch (dwarf.format) {
3775 .@"32" => 4,
3776 .@"64" => 4 + 8,
28533777 };
28543778}
28553779
2856pub const Format = enum {
2857 dwarf32,
2858 dwarf64,
2859};
3780fn sectionOffsetBytes(dwarf: *Dwarf) u32 {
3781 return switch (dwarf.format) {
3782 .@"32" => 4,
3783 .@"64" => 8,
3784 };
3785}
28603786
2861const Dwarf = @This();
3787fn SectionOffset(comptime format: DW.Format) type {
3788 return switch (format) {
3789 .@"32" => u32,
3790 .@"64" => u64,
3791 };
3792}
28623793
2863const std = @import("std");
2864const builtin = @import("builtin");
2865const assert = std.debug.assert;
2866const fs = std.fs;
2867const leb128 = std.leb;
2868const log = std.log.scoped(.dwarf);
2869const mem = std.mem;
3794fn uleb128Bytes(value: anytype) u32 {
3795 var cw = std.io.countingWriter(std.io.null_writer);
3796 try uleb128(cw.writer(), value);
3797 return @intCast(cw.bytes_written);
3798}
28703799
2871const link = @import("../link.zig");
2872const trace = @import("../tracy.zig").trace;
3800/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
3801const force_incremental = false;
3802inline fn incremental(dwarf: Dwarf) bool {
3803 return force_incremental or dwarf.bin_file.comp.incremental;
3804}
28733805
2874const Allocator = mem.Allocator;
28753806const DW = std.dwarf;
2876const File = link.File;
2877const LinkBlock = File.LinkBlock;
2878const LinkFn = File.LinkFn;
2879const LinkerLoad = @import("../codegen.zig").LinkerLoad;
2880const Zcu = @import("../Zcu.zig");
3807const Dwarf = @This();
28813808const InternPool = @import("../InternPool.zig");
2882const StringTable = @import("StringTable.zig");
3809const Module = @import("../Package.zig").Module;
28833810const Type = @import("../Type.zig");
2884const Value = @import("../Value.zig");
3811const Zcu = @import("../Zcu.zig");
3812const Zir = std.zig.Zir;
3813const assert = std.debug.assert;
3814const codegen = @import("../codegen.zig");
3815const link = @import("../link.zig");
3816const log = std.log.scoped(.dwarf);
3817const sleb128 = std.leb.writeIleb128;
3818const std = @import("std");
3819const target_info = @import("../target.zig");
3820const uleb128 = std.leb.writeUleb128;
src/link/Elf.zig+138-94
......@@ -143,6 +143,9 @@ debug_abbrev_section_index: ?u32 = null,
143143debug_str_section_index: ?u32 = null,
144144debug_aranges_section_index: ?u32 = null,
145145debug_line_section_index: ?u32 = null,
146debug_line_str_section_index: ?u32 = null,
147debug_loclists_section_index: ?u32 = null,
148debug_rnglists_section_index: ?u32 = null,
146149
147150copy_rel_section_index: ?u32 = null,
148151dynamic_section_index: ?u32 = null,
......@@ -492,12 +495,13 @@ pub fn getUavVAddr(self: *Elf, uav: InternPool.Index, reloc_info: link.File.Relo
492495}
493496
494497/// Returns end pos of collision, if any.
495fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
498fn detectAllocCollision(self: *Elf, start: u64, size: u64) !?u64 {
496499 const small_ptr = self.ptr_width == .p32;
497500 const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr);
498501 if (start < ehdr_size)
499502 return ehdr_size;
500503
504 var at_end = true;
501505 const end = start + padToIdeal(size);
502506
503507 if (self.shdr_table_offset) |off| {
......@@ -505,8 +509,9 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
505509 const tight_size = self.shdrs.items.len * shdr_size;
506510 const increased_size = padToIdeal(tight_size);
507511 const test_end = off +| increased_size;
508 if (end > off and start < test_end) {
509 return test_end;
512 if (start < test_end) {
513 if (end > off) return test_end;
514 if (test_end < std.math.maxInt(u64)) at_end = false;
510515 }
511516 }
512517
......@@ -514,8 +519,9 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
514519 if (shdr.sh_type == elf.SHT_NOBITS) continue;
515520 const increased_size = padToIdeal(shdr.sh_size);
516521 const test_end = shdr.sh_offset +| increased_size;
517 if (end > shdr.sh_offset and start < test_end) {
518 return test_end;
522 if (start < test_end) {
523 if (end > shdr.sh_offset) return test_end;
524 if (test_end < std.math.maxInt(u64)) at_end = false;
519525 }
520526 }
521527
......@@ -523,11 +529,13 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
523529 if (phdr.p_type != elf.PT_LOAD) continue;
524530 const increased_size = padToIdeal(phdr.p_filesz);
525531 const test_end = phdr.p_offset +| increased_size;
526 if (end > phdr.p_offset and start < test_end) {
527 return test_end;
532 if (start < test_end) {
533 if (end > phdr.p_offset) return test_end;
534 if (test_end < std.math.maxInt(u64)) at_end = false;
528535 }
529536 }
530537
538 if (at_end) try self.base.file.?.setEndPos(end);
531539 return null;
532540}
533541
......@@ -558,9 +566,9 @@ fn allocatedVirtualSize(self: *Elf, start: u64) u64 {
558566 return min_pos - start;
559567}
560568
561pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {
569pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) !u64 {
562570 var start: u64 = 0;
563 while (self.detectAllocCollision(start, object_size)) |item_end| {
571 while (try self.detectAllocCollision(start, object_size)) |item_end| {
564572 start = mem.alignForward(u64, item_end, min_alignment);
565573 }
566574 return start;
......@@ -580,9 +588,9 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
580588 const zig_object = self.zigObjectPtr().?;
581589
582590 const fillSection = struct {
583 fn fillSection(elf_file: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) void {
591 fn fillSection(elf_file: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) !void {
584592 if (elf_file.base.isRelocatable()) {
585 const off = elf_file.findFreeSpace(size, shdr.sh_addralign);
593 const off = try elf_file.findFreeSpace(size, shdr.sh_addralign);
586594 shdr.sh_offset = off;
587595 shdr.sh_size = size;
588596 } else {
......@@ -599,7 +607,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
599607 if (!self.base.isRelocatable()) {
600608 if (self.phdr_zig_load_re_index == null) {
601609 const filesz = options.program_code_size_hint;
602 const off = self.findFreeSpace(filesz, self.page_size);
610 const off = try self.findFreeSpace(filesz, self.page_size);
603611 self.phdr_zig_load_re_index = try self.addPhdr(.{
604612 .type = elf.PT_LOAD,
605613 .offset = off,
......@@ -614,7 +622,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
614622 if (self.phdr_zig_load_ro_index == null) {
615623 const alignment = self.page_size;
616624 const filesz: u64 = 1024;
617 const off = self.findFreeSpace(filesz, alignment);
625 const off = try self.findFreeSpace(filesz, alignment);
618626 self.phdr_zig_load_ro_index = try self.addPhdr(.{
619627 .type = elf.PT_LOAD,
620628 .offset = off,
......@@ -629,7 +637,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
629637 if (self.phdr_zig_load_rw_index == null) {
630638 const alignment = self.page_size;
631639 const filesz: u64 = 1024;
632 const off = self.findFreeSpace(filesz, alignment);
640 const off = try self.findFreeSpace(filesz, alignment);
633641 self.phdr_zig_load_rw_index = try self.addPhdr(.{
634642 .type = elf.PT_LOAD,
635643 .offset = off,
......@@ -662,7 +670,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
662670 .offset = std.math.maxInt(u64),
663671 });
664672 const shdr = &self.shdrs.items[self.zig_text_section_index.?];
665 fillSection(self, shdr, options.program_code_size_hint, self.phdr_zig_load_re_index);
673 try fillSection(self, shdr, options.program_code_size_hint, self.phdr_zig_load_re_index);
666674 if (self.base.isRelocatable()) {
667675 const rela_shndx = try self.addRelaShdr(try self.insertShString(".rela.text.zig"), self.zig_text_section_index.?);
668676 try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{
......@@ -688,7 +696,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
688696 .offset = std.math.maxInt(u64),
689697 });
690698 const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];
691 fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
699 try fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
692700 if (self.base.isRelocatable()) {
693701 const rela_shndx = try self.addRelaShdr(
694702 try self.insertShString(".rela.data.rel.ro.zig"),
......@@ -717,7 +725,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
717725 .offset = std.math.maxInt(u64),
718726 });
719727 const shdr = &self.shdrs.items[self.zig_data_section_index.?];
720 fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
728 try fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
721729 if (self.base.isRelocatable()) {
722730 const rela_shndx = try self.addRelaShdr(
723731 try self.insertShString(".rela.data.zig"),
......@@ -758,24 +766,16 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
758766 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
759767 }
760768
761 if (zig_object.dwarf) |*dw| {
769 if (zig_object.dwarf) |*dwarf| {
762770 if (self.debug_str_section_index == null) {
763 assert(dw.strtab.buffer.items.len == 0);
764 try dw.strtab.buffer.append(gpa, 0);
765771 self.debug_str_section_index = try self.addSection(.{
766772 .name = try self.insertShString(".debug_str"),
767773 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
768774 .entsize = 1,
769775 .type = elf.SHT_PROGBITS,
770776 .addralign = 1,
771 .offset = std.math.maxInt(u64),
772777 });
773 const shdr = &self.shdrs.items[self.debug_str_section_index.?];
774 const size = @as(u64, @intCast(dw.strtab.buffer.items.len));
775 const off = self.findFreeSpace(size, 1);
776 shdr.sh_offset = off;
777 shdr.sh_size = size;
778 zig_object.debug_strtab_dirty = true;
778 zig_object.debug_str_section_dirty = true;
779779 try self.output_sections.putNoClobber(gpa, self.debug_str_section_index.?, .{});
780780 }
781781
......@@ -784,14 +784,8 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
784784 .name = try self.insertShString(".debug_info"),
785785 .type = elf.SHT_PROGBITS,
786786 .addralign = 1,
787 .offset = std.math.maxInt(u64),
788787 });
789 const shdr = &self.shdrs.items[self.debug_info_section_index.?];
790 const size: u64 = 200;
791 const off = self.findFreeSpace(size, 1);
792 shdr.sh_offset = off;
793 shdr.sh_size = size;
794 zig_object.debug_info_header_dirty = true;
788 zig_object.debug_info_section_dirty = true;
795789 try self.output_sections.putNoClobber(gpa, self.debug_info_section_index.?, .{});
796790 }
797791
......@@ -800,13 +794,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
800794 .name = try self.insertShString(".debug_abbrev"),
801795 .type = elf.SHT_PROGBITS,
802796 .addralign = 1,
803 .offset = std.math.maxInt(u64),
804797 });
805 const shdr = &self.shdrs.items[self.debug_abbrev_section_index.?];
806 const size: u64 = 128;
807 const off = self.findFreeSpace(size, 1);
808 shdr.sh_offset = off;
809 shdr.sh_size = size;
810798 zig_object.debug_abbrev_section_dirty = true;
811799 try self.output_sections.putNoClobber(gpa, self.debug_abbrev_section_index.?, .{});
812800 }
......@@ -816,13 +804,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
816804 .name = try self.insertShString(".debug_aranges"),
817805 .type = elf.SHT_PROGBITS,
818806 .addralign = 16,
819 .offset = std.math.maxInt(u64),
820807 });
821 const shdr = &self.shdrs.items[self.debug_aranges_section_index.?];
822 const size: u64 = 160;
823 const off = self.findFreeSpace(size, 16);
824 shdr.sh_offset = off;
825 shdr.sh_size = size;
826808 zig_object.debug_aranges_section_dirty = true;
827809 try self.output_sections.putNoClobber(gpa, self.debug_aranges_section_index.?, .{});
828810 }
......@@ -832,62 +814,83 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
832814 .name = try self.insertShString(".debug_line"),
833815 .type = elf.SHT_PROGBITS,
834816 .addralign = 1,
835 .offset = std.math.maxInt(u64),
836817 });
837 const shdr = &self.shdrs.items[self.debug_line_section_index.?];
838 const size: u64 = 250;
839 const off = self.findFreeSpace(size, 1);
840 shdr.sh_offset = off;
841 shdr.sh_size = size;
842 zig_object.debug_line_header_dirty = true;
818 zig_object.debug_line_section_dirty = true;
843819 try self.output_sections.putNoClobber(gpa, self.debug_line_section_index.?, .{});
844820 }
845 }
846821
847 // We need to find current max assumed file offset, and actually write to file to make it a reality.
848 var end_pos: u64 = 0;
849 for (self.shdrs.items) |shdr| {
850 if (shdr.sh_offset == std.math.maxInt(u64)) continue;
851 end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size);
822 if (self.debug_line_str_section_index == null) {
823 self.debug_line_str_section_index = try self.addSection(.{
824 .name = try self.insertShString(".debug_line_str"),
825 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
826 .entsize = 1,
827 .type = elf.SHT_PROGBITS,
828 .addralign = 1,
829 });
830 zig_object.debug_line_str_section_dirty = true;
831 try self.output_sections.putNoClobber(gpa, self.debug_line_str_section_index.?, .{});
832 }
833
834 if (self.debug_loclists_section_index == null) {
835 self.debug_loclists_section_index = try self.addSection(.{
836 .name = try self.insertShString(".debug_loclists"),
837 .type = elf.SHT_PROGBITS,
838 .addralign = 1,
839 });
840 zig_object.debug_loclists_section_dirty = true;
841 try self.output_sections.putNoClobber(gpa, self.debug_loclists_section_index.?, .{});
842 }
843
844 if (self.debug_rnglists_section_index == null) {
845 self.debug_rnglists_section_index = try self.addSection(.{
846 .name = try self.insertShString(".debug_rnglists"),
847 .type = elf.SHT_PROGBITS,
848 .addralign = 1,
849 });
850 zig_object.debug_rnglists_section_dirty = true;
851 try self.output_sections.putNoClobber(gpa, self.debug_rnglists_section_index.?, .{});
852 }
853
854 try dwarf.initMetadata();
852855 }
853 try self.base.file.?.pwriteAll(&[1]u8{0}, end_pos);
854856}
855857
856858pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
857859 const shdr = &self.shdrs.items[shdr_index];
858860 const maybe_phdr = if (self.phdr_to_shdr_table.get(shdr_index)) |phndx| &self.phdrs.items[phndx] else null;
859 const is_zerofill = shdr.sh_type == elf.SHT_NOBITS;
860861 log.debug("allocated size {x} of {s}, needed size {x}", .{
861862 self.allocatedSize(shdr.sh_offset),
862863 self.getShString(shdr.sh_name),
863864 needed_size,
864865 });
865866
866 if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) {
867 const existing_size = shdr.sh_size;
868 shdr.sh_size = 0;
869 // Must move the entire section.
870 const alignment = if (maybe_phdr) |phdr| phdr.p_align else shdr.sh_addralign;
871 const new_offset = self.findFreeSpace(needed_size, alignment);
872
873 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
874 self.getShString(shdr.sh_name),
875 new_offset,
876 new_offset + existing_size,
877 });
867 if (shdr.sh_type != elf.SHT_NOBITS) {
868 const allocated_size = self.allocatedSize(shdr.sh_offset);
869 if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
870 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
871 } else if (needed_size > allocated_size) {
872 const existing_size = shdr.sh_size;
873 shdr.sh_size = 0;
874 // Must move the entire section.
875 const alignment = if (maybe_phdr) |phdr| phdr.p_align else shdr.sh_addralign;
876 const new_offset = try self.findFreeSpace(needed_size, alignment);
878877
879 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, existing_size);
880 // TODO figure out what to about this error condition - how to communicate it up.
881 if (amt != existing_size) return error.InputOutput;
878 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
879 self.getShString(shdr.sh_name),
880 new_offset,
881 new_offset + existing_size,
882 });
882883
883 shdr.sh_offset = new_offset;
884 if (maybe_phdr) |phdr| phdr.p_offset = new_offset;
885 }
884 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, existing_size);
885 // TODO figure out what to about this error condition - how to communicate it up.
886 if (amt != existing_size) return error.InputOutput;
886887
887 shdr.sh_size = needed_size;
888 if (!is_zerofill) {
888 shdr.sh_offset = new_offset;
889 if (maybe_phdr) |phdr| phdr.p_offset = new_offset;
890 }
889891 if (maybe_phdr) |phdr| phdr.p_filesz = needed_size;
890892 }
893 shdr.sh_size = needed_size;
891894
892895 if (maybe_phdr) |phdr| {
893896 const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr);
......@@ -915,11 +918,14 @@ pub fn growNonAllocSection(
915918) !void {
916919 const shdr = &self.shdrs.items[shdr_index];
917920
918 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
921 const allocated_size = self.allocatedSize(shdr.sh_offset);
922 if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
923 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
924 } else if (needed_size > allocated_size) {
919925 const existing_size = shdr.sh_size;
920926 shdr.sh_size = 0;
921927 // Move all the symbols to a new file location.
922 const new_offset = self.findFreeSpace(needed_size, min_alignment);
928 const new_offset = try self.findFreeSpace(needed_size, min_alignment);
923929
924930 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
925931 self.getShString(shdr.sh_name),
......@@ -939,7 +945,6 @@ pub fn growNonAllocSection(
939945
940946 shdr.sh_offset = new_offset;
941947 }
942
943948 shdr.sh_size = needed_size;
944949
945950 self.markDirty(shdr_index);
......@@ -949,15 +954,21 @@ pub fn markDirty(self: *Elf, shdr_index: u32) void {
949954 const zig_object = self.zigObjectPtr().?;
950955 if (zig_object.dwarf) |_| {
951956 if (self.debug_info_section_index.? == shdr_index) {
952 zig_object.debug_info_header_dirty = true;
953 } else if (self.debug_line_section_index.? == shdr_index) {
954 zig_object.debug_line_header_dirty = true;
957 zig_object.debug_info_section_dirty = true;
955958 } else if (self.debug_abbrev_section_index.? == shdr_index) {
956959 zig_object.debug_abbrev_section_dirty = true;
957960 } else if (self.debug_str_section_index.? == shdr_index) {
958 zig_object.debug_strtab_dirty = true;
961 zig_object.debug_str_section_dirty = true;
959962 } else if (self.debug_aranges_section_index.? == shdr_index) {
960963 zig_object.debug_aranges_section_dirty = true;
964 } else if (self.debug_line_section_index.? == shdr_index) {
965 zig_object.debug_line_section_dirty = true;
966 } else if (self.debug_line_str_section_index.? == shdr_index) {
967 zig_object.debug_line_str_section_dirty = true;
968 } else if (self.debug_loclists_section_index.? == shdr_index) {
969 zig_object.debug_loclists_section_dirty = true;
970 } else if (self.debug_rnglists_section_index.? == shdr_index) {
971 zig_object.debug_rnglists_section_dirty = true;
961972 }
962973 }
963974}
......@@ -1306,6 +1317,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
13061317 try self.base.file.?.pwriteAll(code, file_offset);
13071318 }
13081319
1320 if (zo.dwarf) |*dwarf| try dwarf.resolveRelocs();
1321
13091322 if (has_reloc_errors) return error.FlushFailure;
13101323 }
13111324
......@@ -2667,7 +2680,7 @@ pub fn writeShdrTable(self: *Elf) !void {
26672680
26682681 if (needed_size > self.allocatedSize(shoff)) {
26692682 self.shdr_table_offset = null;
2670 self.shdr_table_offset = self.findFreeSpace(needed_size, shalign);
2683 self.shdr_table_offset = try self.findFreeSpace(needed_size, shalign);
26712684 }
26722685
26732686 log.debug("writing section headers from 0x{x} to 0x{x}", .{
......@@ -2900,6 +2913,18 @@ pub fn updateNav(
29002913 return self.zigObjectPtr().?.updateNav(self, pt, nav);
29012914}
29022915
2916pub fn updateContainerType(
2917 self: *Elf,
2918 pt: Zcu.PerThread,
2919 ty: InternPool.Index,
2920) link.File.UpdateNavError!void {
2921 if (build_options.skip_non_native and builtin.object_format != .elf) {
2922 @panic("Attempted to compile for object format that was disabled by build configuration");
2923 }
2924 if (self.llvm_object) |_| return;
2925 return self.zigObjectPtr().?.updateContainerType(pt, ty);
2926}
2927
29032928pub fn updateExports(
29042929 self: *Elf,
29052930 pt: Zcu.PerThread,
......@@ -3658,11 +3683,14 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {
36583683 &self.zig_data_rel_ro_section_index,
36593684 &self.zig_data_section_index,
36603685 &self.zig_bss_section_index,
3661 &self.debug_str_section_index,
36623686 &self.debug_info_section_index,
36633687 &self.debug_abbrev_section_index,
3688 &self.debug_str_section_index,
36643689 &self.debug_aranges_section_index,
36653690 &self.debug_line_section_index,
3691 &self.debug_line_str_section_index,
3692 &self.debug_loclists_section_index,
3693 &self.debug_rnglists_section_index,
36663694 }) |maybe_index| {
36673695 if (maybe_index.*) |*index| {
36683696 index.* = backlinks[index.*];
......@@ -3787,6 +3815,7 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {
37873815 const atom_ptr = zo.atom(atom_index) orelse continue;
37883816 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
37893817 }
3818 if (zo.dwarf) |*dwarf| dwarf.reloadSectionMetadata();
37903819 }
37913820
37923821 for (self.output_rela_sections.keys(), self.output_rela_sections.values()) |shndx, sec| {
......@@ -3992,7 +4021,7 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {
39924021
39934022/// Allocates alloc sections and creates load segments for sections
39944023/// extracted from input object files.
3995pub fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
4024pub fn allocateAllocSections(self: *Elf) !void {
39964025 // We use this struct to track maximum alignment of all TLS sections.
39974026 // According to https://github.com/rui314/mold/commit/bd46edf3f0fe9e1a787ea453c4657d535622e61f in mold,
39984027 // in-file offsets have to be aligned against the start of TLS program header.
......@@ -4112,7 +4141,7 @@ pub fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
41124141 }
41134142
41144143 const first = self.shdrs.items[cover.items[0]];
4115 var off = self.findFreeSpace(filesz, @"align");
4144 var off = try self.findFreeSpace(filesz, @"align");
41164145 const phndx = try self.addPhdr(.{
41174146 .type = elf.PT_LOAD,
41184147 .offset = off,
......@@ -4147,7 +4176,7 @@ pub fn allocateNonAllocSections(self: *Elf) !void {
41474176 const needed_size = shdr.sh_size;
41484177 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
41494178 shdr.sh_size = 0;
4150 const new_offset = self.findFreeSpace(needed_size, shdr.sh_addralign);
4179 const new_offset = try self.findFreeSpace(needed_size, shdr.sh_addralign);
41514180
41524181 if (self.isDebugSection(@intCast(shndx))) {
41534182 log.debug("moving {s} from 0x{x} to 0x{x}", .{
......@@ -4167,6 +4196,12 @@ pub fn allocateNonAllocSections(self: *Elf) !void {
41674196 break :blk zig_object.debug_aranges_section_zig_size;
41684197 if (shndx == self.debug_line_section_index.?)
41694198 break :blk zig_object.debug_line_section_zig_size;
4199 if (shndx == self.debug_line_str_section_index.?)
4200 break :blk zig_object.debug_line_str_section_zig_size;
4201 if (shndx == self.debug_loclists_section_index.?)
4202 break :blk zig_object.debug_loclists_section_zig_size;
4203 if (shndx == self.debug_rnglists_section_index.?)
4204 break :blk zig_object.debug_rnglists_section_zig_size;
41704205 unreachable;
41714206 };
41724207 const amt = try self.base.file.?.copyRangeAll(
......@@ -4275,6 +4310,12 @@ fn writeAtoms(self: *Elf) !void {
42754310 break :blk zig_object.debug_aranges_section_zig_size;
42764311 if (shndx == self.debug_line_section_index.?)
42774312 break :blk zig_object.debug_line_section_zig_size;
4313 if (shndx == self.debug_line_str_section_index.?)
4314 break :blk zig_object.debug_line_str_section_zig_size;
4315 if (shndx == self.debug_loclists_section_index.?)
4316 break :blk zig_object.debug_loclists_section_zig_size;
4317 if (shndx == self.debug_rnglists_section_index.?)
4318 break :blk zig_object.debug_rnglists_section_zig_size;
42784319 unreachable;
42794320 } else 0;
42804321 const sh_offset = shdr.sh_offset + base_offset;
......@@ -5044,6 +5085,9 @@ pub fn isDebugSection(self: Elf, shndx: u32) bool {
50445085 self.debug_str_section_index,
50455086 self.debug_aranges_section_index,
50465087 self.debug_line_section_index,
5088 self.debug_line_str_section_index,
5089 self.debug_loclists_section_index,
5090 self.debug_rnglists_section_index,
50475091 }) |maybe_index| {
50485092 if (maybe_index) |index| {
50495093 if (index == shndx) return true;
......@@ -5109,7 +5153,7 @@ pub const AddSectionOpts = struct {
51095153
51105154pub fn addSection(self: *Elf, opts: AddSectionOpts) !u32 {
51115155 const gpa = self.base.comp.gpa;
5112 const index = @as(u32, @intCast(self.shdrs.items.len));
5156 const index: u32 = @intCast(self.shdrs.items.len);
51135157 const shdr = try self.shdrs.addOne(gpa);
51145158 shdr.* = .{
51155159 .sh_name = opts.name,
src/link/Elf/Atom.zig+2-1
......@@ -201,11 +201,12 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
201201 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
202202 // range of the compilation unit. When we expand the text section, this range changes,
203203 // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
204 zig_object.debug_info_header_dirty = true;
204 zig_object.debug_info_section_dirty = true;
205205 // This becomes dirty for the same reason. We could potentially make this more
206206 // fine-grained with the addition of support for more compilation units. It is planned to
207207 // model each package as a different compilation unit.
208208 zig_object.debug_aranges_section_dirty = true;
209 zig_object.debug_rnglists_section_dirty = true;
209210 }
210211 }
211212 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnits().?);
src/link/Elf/ZigObject.zig+104-102
......@@ -41,11 +41,14 @@ tls_variables: TlsTable = .{},
4141/// Table of tracked `Uav`s.
4242uavs: UavTable = .{},
4343
44debug_strtab_dirty: bool = false,
44debug_info_section_dirty: bool = false,
4545debug_abbrev_section_dirty: bool = false,
4646debug_aranges_section_dirty: bool = false,
47debug_info_header_dirty: bool = false,
48debug_line_header_dirty: bool = false,
47debug_str_section_dirty: bool = false,
48debug_line_section_dirty: bool = false,
49debug_line_str_section_dirty: bool = false,
50debug_loclists_section_dirty: bool = false,
51debug_rnglists_section_dirty: bool = false,
4952
5053/// Size contribution of Zig's metadata to each debug section.
5154/// Used to track start of metadata from input object files.
......@@ -54,6 +57,9 @@ debug_abbrev_section_zig_size: u64 = 0,
5457debug_str_section_zig_size: u64 = 0,
5558debug_aranges_section_zig_size: u64 = 0,
5659debug_line_section_zig_size: u64 = 0,
60debug_line_str_section_zig_size: u64 = 0,
61debug_loclists_section_zig_size: u64 = 0,
62debug_rnglists_section_zig_size: u64 = 0,
5763
5864pub const global_symbol_bit: u32 = 0x80000000;
5965pub const symbol_mask: u32 = 0x7fffffff;
......@@ -76,10 +82,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
7682
7783 switch (comp.config.debug_format) {
7884 .strip => {},
79 .dwarf => |v| {
80 assert(v == .@"32");
81 self.dwarf = Dwarf.init(&elf_file.base, .dwarf32);
82 },
85 .dwarf => |v| self.dwarf = Dwarf.init(&elf_file.base, v),
8386 .code_view => unreachable,
8487 }
8588}
......@@ -119,8 +122,8 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
119122 }
120123 self.tls_variables.deinit(allocator);
121124
122 if (self.dwarf) |*dw| {
123 dw.deinit();
125 if (self.dwarf) |*dwarf| {
126 dwarf.deinit();
124127 }
125128}
126129
......@@ -165,44 +168,14 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
165168 }
166169 }
167170
168 if (self.dwarf) |*dw| {
171 if (self.dwarf) |*dwarf| {
169172 const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };
170 try dw.flushModule(pt);
171
172 // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections
173 // extracted from input object files correctly.
174 if (self.debug_abbrev_section_dirty) {
175 try dw.writeDbgAbbrev();
176 self.debug_abbrev_section_dirty = false;
177 }
178
179 if (self.debug_info_header_dirty) {
180 const text_shdr = elf_file.shdrs.items[elf_file.zig_text_section_index.?];
181 const low_pc = text_shdr.sh_addr;
182 const high_pc = text_shdr.sh_addr + text_shdr.sh_size;
183 try dw.writeDbgInfoHeader(pt.zcu, low_pc, high_pc);
184 self.debug_info_header_dirty = false;
185 }
186
187 if (self.debug_aranges_section_dirty) {
188 const text_shdr = elf_file.shdrs.items[elf_file.zig_text_section_index.?];
189 try dw.writeDbgAranges(text_shdr.sh_addr, text_shdr.sh_size);
190 self.debug_aranges_section_dirty = false;
191 }
173 try dwarf.flushModule(pt);
192174
193 if (self.debug_line_header_dirty) {
194 try dw.writeDbgLineHeader();
195 self.debug_line_header_dirty = false;
196 }
197
198 if (elf_file.debug_str_section_index) |shndx| {
199 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != elf_file.shdrs.items[shndx].sh_size) {
200 try elf_file.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false);
201 const shdr = elf_file.shdrs.items[shndx];
202 try elf_file.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset);
203 self.debug_strtab_dirty = false;
204 }
205 }
175 self.debug_abbrev_section_dirty = false;
176 self.debug_aranges_section_dirty = false;
177 self.debug_rnglists_section_dirty = false;
178 self.debug_str_section_dirty = false;
206179
207180 self.saveDebugSectionsSizes(elf_file);
208181 }
......@@ -213,7 +186,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
213186 // such as debug_line_header_dirty and debug_info_header_dirty.
214187 assert(!self.debug_abbrev_section_dirty);
215188 assert(!self.debug_aranges_section_dirty);
216 assert(!self.debug_strtab_dirty);
189 assert(!self.debug_rnglists_section_dirty);
190 assert(!self.debug_str_section_dirty);
217191}
218192
219193fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {
......@@ -232,6 +206,15 @@ fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {
232206 if (elf_file.debug_line_section_index) |shndx| {
233207 self.debug_line_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
234208 }
209 if (elf_file.debug_line_str_section_index) |shndx| {
210 self.debug_line_str_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
211 }
212 if (elf_file.debug_loclists_section_index) |shndx| {
213 self.debug_loclists_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
214 }
215 if (elf_file.debug_rnglists_section_index) |shndx| {
216 self.debug_rnglists_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
217 }
235218}
236219
237220fn newSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, st_bind: u4) !Symbol.Index {
......@@ -783,8 +766,8 @@ pub fn freeNav(self: *ZigObject, elf_file: *Elf, nav_index: InternPool.Nav.Index
783766 kv.value.exports.deinit(gpa);
784767 }
785768
786 if (self.dwarf) |*dw| {
787 dw.freeNav(nav_index);
769 if (self.dwarf) |*dwarf| {
770 dwarf.freeNav(nav_index);
788771 }
789772}
790773
......@@ -1034,8 +1017,8 @@ pub fn updateFunc(
10341017 var code_buffer = std.ArrayList(u8).init(gpa);
10351018 defer code_buffer.deinit();
10361019
1037 var dwarf_state = if (self.dwarf) |*dw| try dw.initNavState(pt, func.owner_nav) else null;
1038 defer if (dwarf_state) |*ds| ds.deinit();
1020 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null;
1021 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
10391022
10401023 const res = try codegen.generateFunction(
10411024 &elf_file.base,
......@@ -1045,7 +1028,7 @@ pub fn updateFunc(
10451028 air,
10461029 liveness,
10471030 &code_buffer,
1048 if (dwarf_state) |*ds| .{ .dwarf = ds } else .none,
1031 if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none,
10491032 );
10501033
10511034 const code = switch (res) {
......@@ -1072,14 +1055,17 @@ pub fn updateFunc(
10721055 break :blk .{ atom_ptr.value, atom_ptr.alignment };
10731056 };
10741057
1075 if (dwarf_state) |*ds| {
1058 if (debug_wip_nav) |*wip_nav| {
10761059 const sym = self.symbol(sym_index);
1077 try self.dwarf.?.commitNavState(
1060 try self.dwarf.?.finishWipNav(
10781061 pt,
10791062 func.owner_nav,
1080 @intCast(sym.address(.{}, elf_file)),
1081 sym.atom(elf_file).?.size,
1082 ds,
1063 .{
1064 .index = sym_index,
1065 .addr = @intCast(sym.address(.{}, elf_file)),
1066 .size = sym.atom(elf_file).?.size,
1067 },
1068 wip_nav,
10831069 );
10841070 }
10851071
......@@ -1152,59 +1138,75 @@ pub fn updateNav(
11521138 else => nav_val,
11531139 };
11541140
1155 const sym_index = try self.getOrCreateMetadataForNav(elf_file, nav_index);
1156 self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
1157
1158 var code_buffer = std.ArrayList(u8).init(zcu.gpa);
1159 defer code_buffer.deinit();
1160
1161 var nav_state: ?Dwarf.NavState = if (self.dwarf) |*dw| try dw.initNavState(pt, nav_index) else null;
1162 defer if (nav_state) |*ns| ns.deinit();
1163
1164 // TODO implement .debug_info for global variables
1165 const res = try codegen.generateSymbol(
1166 &elf_file.base,
1167 pt,
1168 zcu.navSrcLoc(nav_index),
1169 nav_init,
1170 &code_buffer,
1171 if (nav_state) |*ns| .{ .dwarf = ns } else .none,
1172 .{ .parent_atom_index = sym_index },
1173 );
1141 if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
1142 const sym_index = try self.getOrCreateMetadataForNav(elf_file, nav_index);
1143 self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
11741144
1175 const code = switch (res) {
1176 .ok => code_buffer.items,
1177 .fail => |em| {
1178 try zcu.failed_codegen.put(zcu.gpa, nav_index, em);
1179 return;
1180 },
1181 };
1145 var code_buffer = std.ArrayList(u8).init(zcu.gpa);
1146 defer code_buffer.deinit();
11821147
1183 const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code);
1184 log.debug("setting shdr({x},{s}) for {}", .{
1185 shndx,
1186 elf_file.getShString(elf_file.shdrs.items[shndx].sh_name),
1187 nav.fqn.fmt(ip),
1188 });
1189 if (elf_file.shdrs.items[shndx].sh_flags & elf.SHF_TLS != 0)
1190 try self.updateTlv(elf_file, pt, nav_index, sym_index, shndx, code)
1191 else
1192 try self.updateNavCode(elf_file, pt, nav_index, sym_index, shndx, code, elf.STT_OBJECT);
1148 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null;
1149 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
11931150
1194 if (nav_state) |*ns| {
1195 const sym = self.symbol(sym_index);
1196 try self.dwarf.?.commitNavState(
1151 // TODO implement .debug_info for global variables
1152 const res = try codegen.generateSymbol(
1153 &elf_file.base,
11971154 pt,
1198 nav_index,
1199 @intCast(sym.address(.{}, elf_file)),
1200 sym.atom(elf_file).?.size,
1201 ns,
1155 zcu.navSrcLoc(nav_index),
1156 nav_init,
1157 &code_buffer,
1158 if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
1159 .{ .parent_atom_index = sym_index },
12021160 );
1203 }
1161
1162 const code = switch (res) {
1163 .ok => code_buffer.items,
1164 .fail => |em| {
1165 try zcu.failed_codegen.put(zcu.gpa, nav_index, em);
1166 return;
1167 },
1168 };
1169
1170 const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code);
1171 log.debug("setting shdr({x},{s}) for {}", .{
1172 shndx,
1173 elf_file.getShString(elf_file.shdrs.items[shndx].sh_name),
1174 nav.fqn.fmt(ip),
1175 });
1176 if (elf_file.shdrs.items[shndx].sh_flags & elf.SHF_TLS != 0)
1177 try self.updateTlv(elf_file, pt, nav_index, sym_index, shndx, code)
1178 else
1179 try self.updateNavCode(elf_file, pt, nav_index, sym_index, shndx, code, elf.STT_OBJECT);
1180
1181 if (debug_wip_nav) |*wip_nav| {
1182 const sym = self.symbol(sym_index);
1183 try self.dwarf.?.finishWipNav(
1184 pt,
1185 nav_index,
1186 .{
1187 .index = sym_index,
1188 .addr = @intCast(sym.address(.{}, elf_file)),
1189 .size = sym.atom(elf_file).?.size,
1190 },
1191 wip_nav,
1192 );
1193 }
1194 } else if (self.dwarf) |*dwarf| try dwarf.updateComptimeNav(pt, nav_index);
12041195
12051196 // Exports will be updated by `Zcu.processExports` after the update.
12061197}
12071198
1199pub fn updateContainerType(
1200 self: *ZigObject,
1201 pt: Zcu.PerThread,
1202 ty: InternPool.Index,
1203) link.File.UpdateNavError!void {
1204 const tracy = trace(@src());
1205 defer tracy.end();
1206
1207 if (self.dwarf) |*dwarf| try dwarf.updateContainerType(pt, ty);
1208}
1209
12081210fn updateLazySymbol(
12091211 self: *ZigObject,
12101212 elf_file: *Elf,
......@@ -1441,8 +1443,8 @@ pub fn updateNavLineNumber(
14411443
14421444 log.debug("updateNavLineNumber {}({d})", .{ nav.fqn.fmt(ip), nav_index });
14431445
1444 if (self.dwarf) |*dw| {
1445 try dw.updateNavLineNumber(pt.zcu, nav_index);
1446 if (self.dwarf) |*dwarf| {
1447 try dwarf.updateNavLineNumber(pt.zcu, nav_index);
14461448 }
14471449}
14481450
src/link/Elf/relocatable.zig+7-1
......@@ -401,7 +401,7 @@ fn allocateAllocSections(elf_file: *Elf) !void {
401401 const needed_size = shdr.sh_size;
402402 if (needed_size > elf_file.allocatedSize(shdr.sh_offset)) {
403403 shdr.sh_size = 0;
404 const new_offset = elf_file.findFreeSpace(needed_size, shdr.sh_addralign);
404 const new_offset = try elf_file.findFreeSpace(needed_size, shdr.sh_addralign);
405405 shdr.sh_offset = new_offset;
406406 shdr.sh_size = needed_size;
407407 }
......@@ -434,6 +434,12 @@ fn writeAtoms(elf_file: *Elf) !void {
434434 break :blk zig_object.debug_aranges_section_zig_size;
435435 if (shndx == elf_file.debug_line_section_index.?)
436436 break :blk zig_object.debug_line_section_zig_size;
437 if (shndx == elf_file.debug_line_str_section_index.?)
438 break :blk zig_object.debug_line_str_section_zig_size;
439 if (shndx == elf_file.debug_loclists_section_index.?)
440 break :blk zig_object.debug_loclists_section_zig_size;
441 if (shndx == elf_file.debug_rnglists_section_index.?)
442 break :blk zig_object.debug_rnglists_section_zig_size;
437443 unreachable;
438444 } else 0;
439445 const sh_offset = shdr.sh_offset + base_offset;
src/link/MachO.zig+128-121
......@@ -94,6 +94,9 @@ debug_abbrev_sect_index: ?u8 = null,
9494debug_str_sect_index: ?u8 = null,
9595debug_aranges_sect_index: ?u8 = null,
9696debug_line_sect_index: ?u8 = null,
97debug_line_str_sect_index: ?u8 = null,
98debug_loclists_sect_index: ?u8 = null,
99debug_rnglists_sect_index: ?u8 = null,
97100
98101has_tlv: AtomicBool = AtomicBool.init(false),
99102binds_to_weak: AtomicBool = AtomicBool.init(false),
......@@ -1789,12 +1792,42 @@ pub fn sortSections(self: *MachO) !void {
17891792 self.sections.appendAssumeCapacity(slice.get(sorted.index));
17901793 }
17911794
1795 for (&[_]*?u8{
1796 &self.data_sect_index,
1797 &self.got_sect_index,
1798 &self.zig_text_sect_index,
1799 &self.zig_got_sect_index,
1800 &self.zig_const_sect_index,
1801 &self.zig_data_sect_index,
1802 &self.zig_bss_sect_index,
1803 &self.stubs_sect_index,
1804 &self.stubs_helper_sect_index,
1805 &self.la_symbol_ptr_sect_index,
1806 &self.tlv_ptr_sect_index,
1807 &self.eh_frame_sect_index,
1808 &self.unwind_info_sect_index,
1809 &self.objc_stubs_sect_index,
1810 &self.debug_str_sect_index,
1811 &self.debug_info_sect_index,
1812 &self.debug_abbrev_sect_index,
1813 &self.debug_aranges_sect_index,
1814 &self.debug_line_sect_index,
1815 &self.debug_line_str_sect_index,
1816 &self.debug_loclists_sect_index,
1817 &self.debug_rnglists_sect_index,
1818 }) |maybe_index| {
1819 if (maybe_index.*) |*index| {
1820 index.* = backlinks[index.*];
1821 }
1822 }
1823
17921824 if (self.getZigObject()) |zo| {
17931825 for (zo.getAtoms()) |atom_index| {
17941826 const atom = zo.getAtom(atom_index) orelse continue;
17951827 if (!atom.isAlive()) continue;
17961828 atom.out_n_sect = backlinks[atom.out_n_sect];
17971829 }
1830 if (zo.dwarf) |*dwarf| dwarf.reloadSectionMetadata();
17981831 }
17991832
18001833 for (self.objects.items) |index| {
......@@ -1813,32 +1846,6 @@ pub fn sortSections(self: *MachO) !void {
18131846 atom.out_n_sect = backlinks[atom.out_n_sect];
18141847 }
18151848 }
1816
1817 for (&[_]*?u8{
1818 &self.data_sect_index,
1819 &self.got_sect_index,
1820 &self.zig_text_sect_index,
1821 &self.zig_got_sect_index,
1822 &self.zig_const_sect_index,
1823 &self.zig_data_sect_index,
1824 &self.zig_bss_sect_index,
1825 &self.stubs_sect_index,
1826 &self.stubs_helper_sect_index,
1827 &self.la_symbol_ptr_sect_index,
1828 &self.tlv_ptr_sect_index,
1829 &self.eh_frame_sect_index,
1830 &self.unwind_info_sect_index,
1831 &self.objc_stubs_sect_index,
1832 &self.debug_info_sect_index,
1833 &self.debug_str_sect_index,
1834 &self.debug_line_sect_index,
1835 &self.debug_abbrev_sect_index,
1836 &self.debug_info_sect_index,
1837 }) |maybe_index| {
1838 if (maybe_index.*) |*index| {
1839 index.* = backlinks[index.*];
1840 }
1841 }
18421849}
18431850
18441851pub fn addAtomsToSections(self: *MachO) !void {
......@@ -2189,7 +2196,7 @@ fn allocateSections(self: *MachO) !void {
21892196 header.size = 0;
21902197
21912198 // Must move the entire section.
2192 const new_offset = self.findFreeSpace(existing_size, page_size);
2199 const new_offset = try self.findFreeSpace(existing_size, page_size);
21932200
21942201 log.debug("moving '{s},{s}' from 0x{x} to 0x{x}", .{
21952202 header.segName(),
......@@ -3066,32 +3073,36 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
30663073 return actual_size +| (actual_size / ideal_factor);
30673074}
30683075
3069fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
3076fn detectAllocCollision(self: *MachO, start: u64, size: u64) !?u64 {
30703077 // Conservatively commit one page size as reserved space for the headers as we
30713078 // expect it to grow and everything else be moved in flush anyhow.
30723079 const header_size = self.getPageSize();
30733080 if (start < header_size)
30743081 return header_size;
30753082
3083 var at_end = true;
30763084 const end = start + padToIdeal(size);
30773085
30783086 for (self.sections.items(.header)) |header| {
30793087 if (header.isZerofill()) continue;
30803088 const increased_size = padToIdeal(header.size);
30813089 const test_end = header.offset +| increased_size;
3082 if (end > header.offset and start < test_end) {
3083 return test_end;
3090 if (start < test_end) {
3091 if (end > header.offset) return test_end;
3092 if (test_end < std.math.maxInt(u64)) at_end = false;
30843093 }
30853094 }
30863095
30873096 for (self.segments.items) |seg| {
30883097 const increased_size = padToIdeal(seg.filesize);
30893098 const test_end = seg.fileoff +| increased_size;
3090 if (end > seg.fileoff and start < test_end) {
3091 return test_end;
3099 if (start < test_end) {
3100 if (end > seg.fileoff) return test_end;
3101 if (test_end < std.math.maxInt(u64)) at_end = false;
30923102 }
30933103 }
30943104
3105 if (at_end) try self.base.file.?.setEndPos(end);
30953106 return null;
30963107}
30973108
......@@ -3159,9 +3170,9 @@ pub fn allocatedSizeVirtual(self: *MachO, start: u64) u64 {
31593170 return min_pos - start;
31603171}
31613172
3162pub fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 {
3173pub fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) !u64 {
31633174 var start: u64 = 0;
3164 while (self.detectAllocCollision(start, object_size)) |item_end| {
3175 while (try self.detectAllocCollision(start, object_size)) |item_end| {
31653176 start = mem.alignForward(u64, item_end, min_alignment);
31663177 }
31673178 return start;
......@@ -3210,7 +3221,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
32103221
32113222 {
32123223 const filesize = options.program_code_size_hint;
3213 const off = self.findFreeSpace(filesize, self.getPageSize());
3224 const off = try self.findFreeSpace(filesize, self.getPageSize());
32143225 self.zig_text_seg_index = try self.addSegment("__TEXT_ZIG", .{
32153226 .fileoff = off,
32163227 .filesize = filesize,
......@@ -3222,7 +3233,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
32223233
32233234 {
32243235 const filesize = options.symbol_count_hint * @sizeOf(u64);
3225 const off = self.findFreeSpace(filesize, self.getPageSize());
3236 const off = try self.findFreeSpace(filesize, self.getPageSize());
32263237 self.zig_got_seg_index = try self.addSegment("__GOT_ZIG", .{
32273238 .fileoff = off,
32283239 .filesize = filesize,
......@@ -3234,7 +3245,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
32343245
32353246 {
32363247 const filesize: u64 = 1024;
3237 const off = self.findFreeSpace(filesize, self.getPageSize());
3248 const off = try self.findFreeSpace(filesize, self.getPageSize());
32383249 self.zig_const_seg_index = try self.addSegment("__CONST_ZIG", .{
32393250 .fileoff = off,
32403251 .filesize = filesize,
......@@ -3246,7 +3257,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
32463257
32473258 {
32483259 const filesize: u64 = 1024;
3249 const off = self.findFreeSpace(filesize, self.getPageSize());
3260 const off = try self.findFreeSpace(filesize, self.getPageSize());
32503261 self.zig_data_seg_index = try self.addSegment("__DATA_ZIG", .{
32513262 .fileoff = off,
32523263 .filesize = filesize,
......@@ -3265,7 +3276,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
32653276 });
32663277 }
32673278
3268 if (options.zo.dwarf) |_| {
3279 if (options.zo.dwarf) |*dwarf| {
32693280 // Create dSYM bundle.
32703281 log.debug("creating {s}.dSYM bundle", .{options.emit.sub_path});
32713282
......@@ -3288,6 +3299,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
32883299
32893300 self.d_sym = .{ .allocator = gpa, .file = d_sym_file };
32903301 try self.d_sym.?.initMetadata(self);
3302 try dwarf.initMetadata();
32913303 }
32923304 }
32933305
......@@ -3307,7 +3319,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
33073319 const sect = &macho_file.sections.items(.header)[sect_id];
33083320 const alignment = try math.powi(u32, 2, sect.@"align");
33093321 if (!sect.isZerofill()) {
3310 sect.offset = math.cast(u32, macho_file.findFreeSpace(size, alignment)) orelse
3322 sect.offset = math.cast(u32, try macho_file.findFreeSpace(size, alignment)) orelse
33113323 return error.Overflow;
33123324 }
33133325 sect.addr = macho_file.findFreeSpaceVirtual(size, alignment);
......@@ -3367,43 +3379,34 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
33673379 }
33683380 }
33693381
3370 if (self.base.isRelocatable() and options.zo.dwarf != null) {
3371 {
3372 self.debug_str_sect_index = try self.addSection("__DWARF", "__debug_str", .{
3373 .flags = macho.S_ATTR_DEBUG,
3374 });
3375 try allocSect(self, self.debug_str_sect_index.?, 200);
3376 }
3377
3378 {
3379 self.debug_info_sect_index = try self.addSection("__DWARF", "__debug_info", .{
3380 .flags = macho.S_ATTR_DEBUG,
3381 });
3382 try allocSect(self, self.debug_info_sect_index.?, 200);
3383 }
3384
3385 {
3386 self.debug_abbrev_sect_index = try self.addSection("__DWARF", "__debug_abbrev", .{
3387 .flags = macho.S_ATTR_DEBUG,
3388 });
3389 try allocSect(self, self.debug_abbrev_sect_index.?, 128);
3390 }
3391
3392 {
3393 self.debug_aranges_sect_index = try self.addSection("__DWARF", "__debug_aranges", .{
3394 .alignment = 4,
3395 .flags = macho.S_ATTR_DEBUG,
3396 });
3397 try allocSect(self, self.debug_aranges_sect_index.?, 160);
3398 }
3399
3400 {
3401 self.debug_line_sect_index = try self.addSection("__DWARF", "__debug_line", .{
3402 .flags = macho.S_ATTR_DEBUG,
3403 });
3404 try allocSect(self, self.debug_line_sect_index.?, 250);
3405 }
3406 }
3382 if (self.base.isRelocatable()) if (options.zo.dwarf) |*dwarf| {
3383 self.debug_str_sect_index = try self.addSection("__DWARF", "__debug_str", .{
3384 .flags = macho.S_ATTR_DEBUG,
3385 });
3386 self.debug_info_sect_index = try self.addSection("__DWARF", "__debug_info", .{
3387 .flags = macho.S_ATTR_DEBUG,
3388 });
3389 self.debug_abbrev_sect_index = try self.addSection("__DWARF", "__debug_abbrev", .{
3390 .flags = macho.S_ATTR_DEBUG,
3391 });
3392 self.debug_aranges_sect_index = try self.addSection("__DWARF", "__debug_aranges", .{
3393 .alignment = 4,
3394 .flags = macho.S_ATTR_DEBUG,
3395 });
3396 self.debug_line_sect_index = try self.addSection("__DWARF", "__debug_line", .{
3397 .flags = macho.S_ATTR_DEBUG,
3398 });
3399 self.debug_line_str_sect_index = try self.addSection("__DWARF", "__debug_line_str", .{
3400 .flags = macho.S_ATTR_DEBUG,
3401 });
3402 self.debug_loclists_sect_index = try self.addSection("__DWARF", "__debug_loclists", .{
3403 .flags = macho.S_ATTR_DEBUG,
3404 });
3405 self.debug_rnglists_sect_index = try self.addSection("__DWARF", "__debug_rnglists", .{
3406 .flags = macho.S_ATTR_DEBUG,
3407 });
3408 try dwarf.initMetadata();
3409 };
34073410}
34083411
34093412pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
......@@ -3417,35 +3420,36 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
34173420fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void {
34183421 const sect = &self.sections.items(.header)[sect_index];
34193422
3420 if (needed_size > self.allocatedSize(sect.offset) and !sect.isZerofill()) {
3421 const existing_size = sect.size;
3422 sect.size = 0;
3423
3424 // Must move the entire section.
3425 const alignment = self.getPageSize();
3426 const new_offset = self.findFreeSpace(needed_size, alignment);
3427
3428 log.debug("moving '{s},{s}' from 0x{x} to 0x{x}", .{
3429 sect.segName(),
3430 sect.sectName(),
3431 sect.offset,
3432 new_offset,
3433 });
3423 const seg_id = self.sections.items(.segment_id)[sect_index];
3424 const seg = &self.segments.items[seg_id];
34343425
3435 try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);
3426 if (!sect.isZerofill()) {
3427 const allocated_size = self.allocatedSize(sect.offset);
3428 if (sect.offset + allocated_size == std.math.maxInt(u64)) {
3429 try self.base.file.?.setEndPos(sect.offset + needed_size);
3430 } else if (needed_size > allocated_size) {
3431 const existing_size = sect.size;
3432 sect.size = 0;
34363433
3437 sect.offset = @intCast(new_offset);
3438 }
3434 // Must move the entire section.
3435 const alignment = self.getPageSize();
3436 const new_offset = try self.findFreeSpace(needed_size, alignment);
34393437
3440 sect.size = needed_size;
3438 log.debug("moving '{s},{s}' from 0x{x} to 0x{x}", .{
3439 sect.segName(),
3440 sect.sectName(),
3441 sect.offset,
3442 new_offset,
3443 });
34413444
3442 const seg_id = self.sections.items(.segment_id)[sect_index];
3443 const seg = &self.segments.items[seg_id];
3444 seg.fileoff = sect.offset;
3445 try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);
34453446
3446 if (!sect.isZerofill()) {
3447 sect.offset = @intCast(new_offset);
3448 }
34473449 seg.filesize = needed_size;
34483450 }
3451 sect.size = needed_size;
3452 seg.fileoff = sect.offset;
34493453
34503454 const mem_capacity = self.allocatedSizeVirtual(seg.vmaddr);
34513455 if (needed_size > mem_capacity) {
......@@ -3464,30 +3468,34 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
34643468fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void {
34653469 const sect = &self.sections.items(.header)[sect_index];
34663470
3467 if (needed_size > self.allocatedSize(sect.offset) and !sect.isZerofill()) {
3468 const existing_size = sect.size;
3469 sect.size = 0;
3470
3471 // Must move the entire section.
3472 const alignment = try math.powi(u32, 2, sect.@"align");
3473 const new_offset = self.findFreeSpace(needed_size, alignment);
3474 const new_addr = self.findFreeSpaceVirtual(needed_size, alignment);
3475
3476 log.debug("new '{s},{s}' file offset 0x{x} to 0x{x} (0x{x} - 0x{x})", .{
3477 sect.segName(),
3478 sect.sectName(),
3479 new_offset,
3480 new_offset + existing_size,
3481 new_addr,
3482 new_addr + existing_size,
3483 });
3471 if (!sect.isZerofill()) {
3472 const allocated_size = self.allocatedSize(sect.offset);
3473 if (sect.offset + allocated_size == std.math.maxInt(u64)) {
3474 try self.base.file.?.setEndPos(sect.offset + needed_size);
3475 } else if (needed_size > allocated_size) {
3476 const existing_size = sect.size;
3477 sect.size = 0;
34843478
3485 try self.copyRangeAll(sect.offset, new_offset, existing_size);
3479 // Must move the entire section.
3480 const alignment = try math.powi(u32, 2, sect.@"align");
3481 const new_offset = try self.findFreeSpace(needed_size, alignment);
3482 const new_addr = self.findFreeSpaceVirtual(needed_size, alignment);
34863483
3487 sect.offset = @intCast(new_offset);
3488 sect.addr = new_addr;
3489 }
3484 log.debug("new '{s},{s}' file offset 0x{x} to 0x{x} (0x{x} - 0x{x})", .{
3485 sect.segName(),
3486 sect.sectName(),
3487 new_offset,
3488 new_offset + existing_size,
3489 new_addr,
3490 new_addr + existing_size,
3491 });
34903492
3493 try self.copyRangeAll(sect.offset, new_offset, existing_size);
3494
3495 sect.offset = @intCast(new_offset);
3496 sect.addr = new_addr;
3497 }
3498 }
34913499 sect.size = needed_size;
34923500}
34933501
......@@ -4591,7 +4599,6 @@ const std = @import("std");
45914599const build_options = @import("build_options");
45924600const builtin = @import("builtin");
45934601const assert = std.debug.assert;
4594const dwarf = std.dwarf;
45954602const fs = std.fs;
45964603const log = std.log.scoped(.link);
45974604const state_log = std.log.scoped(.link_state);
src/link/MachO/DebugSymbols.zig+36-31
......@@ -15,6 +15,9 @@ debug_abbrev_section_index: ?u8 = null,
1515debug_str_section_index: ?u8 = null,
1616debug_aranges_section_index: ?u8 = null,
1717debug_line_section_index: ?u8 = null,
18debug_line_str_section_index: ?u8 = null,
19debug_loclists_section_index: ?u8 = null,
20debug_rnglists_section_index: ?u8 = null,
1821
1922relocs: std.ArrayListUnmanaged(Reloc) = .{},
2023
......@@ -56,13 +59,16 @@ pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {
5659 });
5760 }
5861
59 self.debug_str_section_index = try self.allocateSection("__debug_str", 200, 0);
60 self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0);
61 self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0);
62 self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4);
63 self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0);
62 self.debug_str_section_index = try self.createSection("__debug_str", 0);
63 self.debug_info_section_index = try self.createSection("__debug_info", 0);
64 self.debug_abbrev_section_index = try self.createSection("__debug_abbrev", 0);
65 self.debug_aranges_section_index = try self.createSection("__debug_aranges", 4);
66 self.debug_line_section_index = try self.createSection("__debug_line", 0);
67 self.debug_line_str_section_index = try self.createSection("__debug_line_str", 0);
68 self.debug_loclists_section_index = try self.createSection("__debug_loclists", 0);
69 self.debug_rnglists_section_index = try self.createSection("__debug_rnglists", 0);
6470
65 self.linkedit_segment_cmd_index = @as(u8, @intCast(self.segments.items.len));
71 self.linkedit_segment_cmd_index = @intCast(self.segments.items.len);
6672 try self.segments.append(self.allocator, .{
6773 .segname = makeStaticString("__LINKEDIT"),
6874 .maxprot = macho.PROT.READ,
......@@ -71,27 +77,17 @@ pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {
7177 });
7278}
7379
74fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u8 {
80fn createSection(self: *DebugSymbols, sectname: []const u8, alignment: u16) !u8 {
7581 const segment = self.getDwarfSegmentPtr();
7682 var sect = macho.section_64{
7783 .sectname = makeStaticString(sectname),
7884 .segname = segment.segname,
79 .size = @as(u32, @intCast(size)),
8085 .@"align" = alignment,
8186 };
82 const alignment_pow_2 = try math.powi(u32, 2, alignment);
83 const off = self.findFreeSpace(size, alignment_pow_2);
84
85 log.debug("found {s},{s} section free space 0x{x} to 0x{x}", .{
86 sect.segName(),
87 sect.sectName(),
88 off,
89 off + size,
90 });
9187
92 sect.offset = @as(u32, @intCast(off));
88 log.debug("create {s},{s} section", .{ sect.segName(), sect.sectName() });
9389
94 const index = @as(u8, @intCast(self.sections.items.len));
90 const index: u8 = @intCast(self.sections.items.len);
9591 try self.sections.append(self.allocator, sect);
9692 segment.cmdsize += @sizeOf(macho.section_64);
9793 segment.nsects += 1;
......@@ -102,16 +98,19 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
10298pub fn growSection(
10399 self: *DebugSymbols,
104100 sect_index: u8,
105 needed_size: u32,
101 needed_size: u64,
106102 requires_file_copy: bool,
107103 macho_file: *MachO,
108104) !void {
109105 const sect = self.getSectionPtr(sect_index);
110106
111 if (needed_size > self.allocatedSize(sect.offset)) {
107 const allocated_size = self.allocatedSize(sect.offset);
108 if (sect.offset + allocated_size == std.math.maxInt(u64)) {
109 try self.file.setEndPos(sect.offset + needed_size);
110 } else if (needed_size > allocated_size) {
112111 const existing_size = sect.size;
113112 sect.size = 0; // free the space
114 const new_offset = self.findFreeSpace(needed_size, 1);
113 const new_offset = try self.findFreeSpace(needed_size, 1);
115114
116115 log.debug("moving {s} section: {} bytes from 0x{x} to 0x{x}", .{
117116 sect.sectName(),
......@@ -130,7 +129,7 @@ pub fn growSection(
130129 if (amt != existing_size) return error.InputOutput;
131130 }
132131
133 sect.offset = @as(u32, @intCast(new_offset));
132 sect.offset = @intCast(new_offset);
134133 }
135134
136135 sect.size = needed_size;
......@@ -153,22 +152,27 @@ pub fn markDirty(self: *DebugSymbols, sect_index: u8, macho_file: *MachO) void {
153152 }
154153}
155154
156fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {
155fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) !?u64 {
156 var at_end = true;
157157 const end = start + padToIdeal(size);
158
158159 for (self.sections.items) |section| {
159160 const increased_size = padToIdeal(section.size);
160161 const test_end = section.offset + increased_size;
161 if (end > section.offset and start < test_end) {
162 return test_end;
162 if (start < test_end) {
163 if (end > section.offset) return test_end;
164 if (test_end < std.math.maxInt(u64)) at_end = false;
163165 }
164166 }
167
168 if (at_end) try self.file.setEndPos(end);
165169 return null;
166170}
167171
168fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 {
172fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) !u64 {
169173 const segment = self.getDwarfSegmentPtr();
170174 var offset: u64 = segment.fileoff;
171 while (self.detectAllocCollision(offset, object_size)) |item_end| {
175 while (try self.detectAllocCollision(offset, object_size)) |item_end| {
172176 offset = mem.alignForward(u64, item_end, min_alignment);
173177 }
174178 return offset;
......@@ -346,6 +350,7 @@ fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds
346350}
347351
348352fn allocatedSize(self: *DebugSymbols, start: u64) u64 {
353 if (start == 0) return 0;
349354 const seg = self.getDwarfSegmentPtr();
350355 assert(start >= seg.fileoff);
351356 var min_pos: u64 = std.math.maxInt(u64);
......@@ -413,9 +418,9 @@ pub fn writeStrtab(self: *DebugSymbols, off: u32) !u32 {
413418
414419pub fn getSectionIndexes(self: *DebugSymbols, segment_index: u8) struct { start: u8, end: u8 } {
415420 var start: u8 = 0;
416 const nsects = for (self.segments.items, 0..) |seg, i| {
417 if (i == segment_index) break @as(u8, @intCast(seg.nsects));
418 start += @as(u8, @intCast(seg.nsects));
421 const nsects: u8 = for (self.segments.items, 0..) |seg, i| {
422 if (i == segment_index) break @intCast(seg.nsects);
423 start += @intCast(seg.nsects);
419424 } else 0;
420425 return .{ .start = start, .end = start + nsects };
421426}
src/link/MachO/ZigObject.zig+64-99
......@@ -55,8 +55,7 @@ pub fn init(self: *ZigObject, macho_file: *MachO) !void {
5555 switch (comp.config.debug_format) {
5656 .strip => {},
5757 .dwarf => |v| {
58 assert(v == .@"32");
59 self.dwarf = Dwarf.init(&macho_file.base, .dwarf32);
58 self.dwarf = Dwarf.init(&macho_file.base, v);
6059 self.debug_strtab_dirty = true;
6160 self.debug_abbrev_dirty = true;
6261 self.debug_aranges_dirty = true;
......@@ -101,8 +100,8 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
101100 }
102101 self.tlv_initializers.deinit(allocator);
103102
104 if (self.dwarf) |*dw| {
105 dw.deinit();
103 if (self.dwarf) |*dwarf| {
104 dwarf.deinit();
106105 }
107106}
108107
......@@ -595,56 +594,13 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id)
595594 if (metadata.const_state != .unused) metadata.const_state = .flushed;
596595 }
597596
598 if (self.dwarf) |*dw| {
597 if (self.dwarf) |*dwarf| {
599598 const pt: Zcu.PerThread = .{ .zcu = macho_file.base.comp.module.?, .tid = tid };
600 try dw.flushModule(pt);
599 try dwarf.flushModule(pt);
601600
602 if (self.debug_abbrev_dirty) {
603 try dw.writeDbgAbbrev();
604 self.debug_abbrev_dirty = false;
605 }
606
607 if (self.debug_info_header_dirty) {
608 // Currently only one compilation unit is supported, so the address range is simply
609 // identical to the main program header virtual address and memory size.
610 const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?];
611 const low_pc = text_section.addr;
612 const high_pc = text_section.addr + text_section.size;
613 try dw.writeDbgInfoHeader(pt.zcu, low_pc, high_pc);
614 self.debug_info_header_dirty = false;
615 }
616
617 if (self.debug_aranges_dirty) {
618 // Currently only one compilation unit is supported, so the address range is simply
619 // identical to the main program header virtual address and memory size.
620 const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?];
621 try dw.writeDbgAranges(text_section.addr, text_section.size);
622 self.debug_aranges_dirty = false;
623 }
624
625 if (self.debug_line_header_dirty) {
626 try dw.writeDbgLineHeader();
627 self.debug_line_header_dirty = false;
628 }
629
630 if (!macho_file.base.isRelocatable()) {
631 const d_sym = macho_file.getDebugSymbols().?;
632 const sect_index = d_sym.debug_str_section_index.?;
633 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != d_sym.getSection(sect_index).size) {
634 const needed_size = @as(u32, @intCast(dw.strtab.buffer.items.len));
635 try d_sym.growSection(sect_index, needed_size, false, macho_file);
636 try d_sym.file.pwriteAll(dw.strtab.buffer.items, d_sym.getSection(sect_index).offset);
637 self.debug_strtab_dirty = false;
638 }
639 } else {
640 const sect_index = macho_file.debug_str_sect_index.?;
641 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != macho_file.sections.items(.header)[sect_index].size) {
642 const needed_size = @as(u32, @intCast(dw.strtab.buffer.items.len));
643 try macho_file.growSection(sect_index, needed_size);
644 try macho_file.base.file.?.pwriteAll(dw.strtab.buffer.items, macho_file.sections.items(.header)[sect_index].offset);
645 self.debug_strtab_dirty = false;
646 }
647 }
601 self.debug_abbrev_dirty = false;
602 self.debug_aranges_dirty = false;
603 self.debug_strtab_dirty = false;
648604 }
649605
650606 // The point of flushModule() is to commit changes, so in theory, nothing should
......@@ -816,8 +772,8 @@ pub fn updateFunc(
816772 var code_buffer = std.ArrayList(u8).init(gpa);
817773 defer code_buffer.deinit();
818774
819 var dwarf_state = if (self.dwarf) |*dw| try dw.initNavState(pt, func.owner_nav) else null;
820 defer if (dwarf_state) |*ds| ds.deinit();
775 var dwarf_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null;
776 defer if (dwarf_wip_nav) |*wip_nav| wip_nav.deinit();
821777
822778 const res = try codegen.generateFunction(
823779 &macho_file.base,
......@@ -827,7 +783,7 @@ pub fn updateFunc(
827783 air,
828784 liveness,
829785 &code_buffer,
830 if (dwarf_state) |*ds| .{ .dwarf = ds } else .none,
786 if (dwarf_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
831787 );
832788
833789 const code = switch (res) {
......@@ -841,14 +797,17 @@ pub fn updateFunc(
841797 const sect_index = try self.getNavOutputSection(macho_file, zcu, func.owner_nav, code);
842798 try self.updateNavCode(macho_file, pt, func.owner_nav, sym_index, sect_index, code);
843799
844 if (dwarf_state) |*ds| {
800 if (dwarf_wip_nav) |*wip_nav| {
845801 const sym = self.symbols.items[sym_index];
846 try self.dwarf.?.commitNavState(
802 try self.dwarf.?.finishWipNav(
847803 pt,
848804 func.owner_nav,
849 sym.getAddress(.{}, macho_file),
850 sym.getAtom(macho_file).?.size,
851 ds,
805 .{
806 .index = sym_index,
807 .addr = sym.getAddress(.{}, macho_file),
808 .size = sym.getAtom(macho_file).?.size,
809 },
810 wip_nav,
852811 );
853812 }
854813
......@@ -866,6 +825,7 @@ pub fn updateNav(
866825
867826 const zcu = pt.zcu;
868827 const ip = &zcu.intern_pool;
828
869829 const nav_val = zcu.navValue(nav_index);
870830 const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
871831 .variable => |variable| Value.fromInterned(variable.init),
......@@ -882,48 +842,53 @@ pub fn updateNav(
882842 else => nav_val,
883843 };
884844
885 const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index);
886 self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);
887
888 var code_buffer = std.ArrayList(u8).init(zcu.gpa);
889 defer code_buffer.deinit();
890
891 var nav_state: ?Dwarf.NavState = if (self.dwarf) |*dw| try dw.initNavState(pt, nav_index) else null;
892 defer if (nav_state) |*ns| ns.deinit();
845 if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
846 const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index);
847 self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);
893848
894 const res = try codegen.generateSymbol(
895 &macho_file.base,
896 pt,
897 zcu.navSrcLoc(nav_index),
898 nav_init,
899 &code_buffer,
900 if (nav_state) |*ns| .{ .dwarf = ns } else .none,
901 .{ .parent_atom_index = sym_index },
902 );
849 var code_buffer = std.ArrayList(u8).init(zcu.gpa);
850 defer code_buffer.deinit();
903851
904 const code = switch (res) {
905 .ok => code_buffer.items,
906 .fail => |em| {
907 try zcu.failed_codegen.put(zcu.gpa, nav_index, em);
908 return;
909 },
910 };
911 const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code);
912 if (isThreadlocal(macho_file, nav_index))
913 try self.updateTlv(macho_file, pt, nav_index, sym_index, sect_index, code)
914 else
915 try self.updateNavCode(macho_file, pt, nav_index, sym_index, sect_index, code);
852 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null;
853 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
916854
917 if (nav_state) |*ns| {
918 const sym = self.symbols.items[sym_index];
919 try self.dwarf.?.commitNavState(
855 const res = try codegen.generateSymbol(
856 &macho_file.base,
920857 pt,
921 nav_index,
922 sym.getAddress(.{}, macho_file),
923 sym.getAtom(macho_file).?.size,
924 ns,
858 zcu.navSrcLoc(nav_index),
859 nav_init,
860 &code_buffer,
861 if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
862 .{ .parent_atom_index = sym_index },
925863 );
926 }
864
865 const code = switch (res) {
866 .ok => code_buffer.items,
867 .fail => |em| {
868 try zcu.failed_codegen.put(zcu.gpa, nav_index, em);
869 return;
870 },
871 };
872 const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code);
873 if (isThreadlocal(macho_file, nav_index))
874 try self.updateTlv(macho_file, pt, nav_index, sym_index, sect_index, code)
875 else
876 try self.updateNavCode(macho_file, pt, nav_index, sym_index, sect_index, code);
877
878 if (debug_wip_nav) |*wip_nav| {
879 const sym = self.symbols.items[sym_index];
880 try self.dwarf.?.finishWipNav(
881 pt,
882 nav_index,
883 .{
884 .index = sym_index,
885 .addr = sym.getAddress(.{}, macho_file),
886 .size = sym.getAtom(macho_file).?.size,
887 },
888 wip_nav,
889 );
890 }
891 } else if (self.dwarf) |*dwarf| try dwarf.updateComptimeNav(pt, nav_index);
927892
928893 // Exports will be updated by `Zcu.processExports` after the update.
929894}
......@@ -1435,8 +1400,8 @@ pub fn updateNavLineNumber(
14351400 pt: Zcu.PerThread,
14361401 nav_index: InternPool.Nav.Index,
14371402) !void {
1438 if (self.dwarf) |*dw| {
1439 try dw.updateNavLineNumber(pt.zcu, nav_index);
1403 if (self.dwarf) |*dwarf| {
1404 try dwarf.updateNavLineNumber(pt.zcu, nav_index);
14401405 }
14411406}
14421407
src/link/MachO/relocatable.zig+1-1
......@@ -465,7 +465,7 @@ fn allocateSections(macho_file: *MachO) !void {
465465 const alignment = try math.powi(u32, 2, header.@"align");
466466 if (!header.isZerofill()) {
467467 if (needed_size > macho_file.allocatedSize(header.offset)) {
468 header.offset = math.cast(u32, macho_file.findFreeSpace(needed_size, alignment)) orelse
468 header.offset = math.cast(u32, try macho_file.findFreeSpace(needed_size, alignment)) orelse
469469 return error.Overflow;
470470 }
471471 }
src/link/Plan9.zig+23-20
......@@ -454,28 +454,31 @@ pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
454454 },
455455 else => nav_val,
456456 };
457 const atom_idx = try self.seeNav(pt, nav_index);
458457
459 var code_buffer = std.ArrayList(u8).init(gpa);
460 defer code_buffer.deinit();
461 // TODO we need the symbol index for symbol in the table of locals for the containing atom
462 const res = try codegen.generateSymbol(&self.base, pt, zcu.navSrcLoc(nav_index), nav_init, &code_buffer, .none, .{
463 .parent_atom_index = @intCast(atom_idx),
464 });
465 const code = switch (res) {
466 .ok => code_buffer.items,
467 .fail => |em| {
468 try zcu.failed_codegen.put(gpa, nav_index, em);
469 return;
470 },
471 };
472 try self.data_nav_table.ensureUnusedCapacity(gpa, 1);
473 const duped_code = try gpa.dupe(u8, code);
474 self.getAtomPtr(self.navs.get(nav_index).?.index).code = .{ .code_ptr = null, .other = .{ .nav_index = nav_index } };
475 if (self.data_nav_table.fetchPutAssumeCapacity(nav_index, duped_code)) |old_entry| {
476 gpa.free(old_entry.value);
458 if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
459 const atom_idx = try self.seeNav(pt, nav_index);
460
461 var code_buffer = std.ArrayList(u8).init(gpa);
462 defer code_buffer.deinit();
463 // TODO we need the symbol index for symbol in the table of locals for the containing atom
464 const res = try codegen.generateSymbol(&self.base, pt, zcu.navSrcLoc(nav_index), nav_init, &code_buffer, .none, .{
465 .parent_atom_index = @intCast(atom_idx),
466 });
467 const code = switch (res) {
468 .ok => code_buffer.items,
469 .fail => |em| {
470 try zcu.failed_codegen.put(gpa, nav_index, em);
471 return;
472 },
473 };
474 try self.data_nav_table.ensureUnusedCapacity(gpa, 1);
475 const duped_code = try gpa.dupe(u8, code);
476 self.getAtomPtr(self.navs.get(nav_index).?.index).code = .{ .code_ptr = null, .other = .{ .nav_index = nav_index } };
477 if (self.data_nav_table.fetchPutAssumeCapacity(nav_index, duped_code)) |old_entry| {
478 gpa.free(old_entry.value);
479 }
480 try self.updateFinish(pt, nav_index);
477481 }
478 return self.updateFinish(pt, nav_index);
479482}
480483
481484/// called at the end of update{Decl,Func}
src/link/Wasm/ZigObject.zig+32-29
......@@ -248,46 +248,49 @@ pub fn updateNav(
248248 const ip = &zcu.intern_pool;
249249 const nav = ip.getNav(nav_index);
250250
251 const is_extern, const lib_name, const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
252 .variable => |variable| .{ false, variable.lib_name, variable.init },
251 const nav_val = zcu.navValue(nav_index);
252 const is_extern, const lib_name, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
253 .variable => |variable| .{ false, variable.lib_name, Value.fromInterned(variable.init) },
253254 .func => return,
254255 .@"extern" => |@"extern"| if (ip.isFunctionType(nav.typeOf(ip)))
255256 return
256257 else
257 .{ true, @"extern".lib_name, nav.status.resolved.val },
258 else => .{ false, .none, nav.status.resolved.val },
258 .{ true, @"extern".lib_name, nav_val },
259 else => .{ false, .none, nav_val },
259260 };
260261
261 const gpa = wasm_file.base.comp.gpa;
262 const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index);
263 const atom = wasm_file.getAtomPtr(atom_index);
264 atom.clear();
262 if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
263 const gpa = wasm_file.base.comp.gpa;
264 const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index);
265 const atom = wasm_file.getAtomPtr(atom_index);
266 atom.clear();
265267
266 if (is_extern)
267 return zig_object.addOrUpdateImport(wasm_file, nav.name.toSlice(ip), atom.sym_index, lib_name.toSlice(ip), null);
268 if (is_extern)
269 return zig_object.addOrUpdateImport(wasm_file, nav.name.toSlice(ip), atom.sym_index, lib_name.toSlice(ip), null);
268270
269 var code_writer = std.ArrayList(u8).init(gpa);
270 defer code_writer.deinit();
271 var code_writer = std.ArrayList(u8).init(gpa);
272 defer code_writer.deinit();
271273
272 const res = try codegen.generateSymbol(
273 &wasm_file.base,
274 pt,
275 zcu.navSrcLoc(nav_index),
276 Value.fromInterned(nav_init),
277 &code_writer,
278 .none,
279 .{ .parent_atom_index = @intFromEnum(atom.sym_index) },
280 );
274 const res = try codegen.generateSymbol(
275 &wasm_file.base,
276 pt,
277 zcu.navSrcLoc(nav_index),
278 nav_init,
279 &code_writer,
280 .none,
281 .{ .parent_atom_index = @intFromEnum(atom.sym_index) },
282 );
281283
282 const code = switch (res) {
283 .ok => code_writer.items,
284 .fail => |em| {
285 try zcu.failed_codegen.put(zcu.gpa, nav_index, em);
286 return;
287 },
288 };
284 const code = switch (res) {
285 .ok => code_writer.items,
286 .fail => |em| {
287 try zcu.failed_codegen.put(zcu.gpa, nav_index, em);
288 return;
289 },
290 };
289291
290 return zig_object.finishUpdateNav(wasm_file, pt, nav_index, code);
292 try zig_object.finishUpdateNav(wasm_file, pt, nav_index, code);
293 }
291294}
292295
293296pub fn updateFunc(
src/print_zir.zig+1-1
......@@ -746,7 +746,7 @@ const Writer = struct {
746746 fn writeIntBig(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
747747 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str;
748748 const byte_count = inst_data.len * @sizeOf(std.math.big.Limb);
749 const limb_bytes = self.code.nullTerminatedString(inst_data.start)[0..byte_count];
749 const limb_bytes = self.code.string_bytes[@intFromEnum(inst_data.start)..][0..byte_count];
750750 // limb_bytes is not aligned properly; we must allocate and copy the bytes
751751 // in order to accomplish this.
752752 const limbs = try self.gpa.alloc(std.math.big.Limb, inst_data.len);
src/register_manager.zig+2-1
......@@ -10,6 +10,7 @@ const Zcu = @import("Zcu.zig");
1010const expect = std.testing.expect;
1111const expectEqual = std.testing.expectEqual;
1212const expectEqualSlices = std.testing.expectEqualSlices;
13const link = @import("link.zig");
1314
1415const log = std.log.scoped(.register_manager);
1516
......@@ -25,7 +26,7 @@ pub const AllocateRegistersError = error{
2526 /// Can happen when spilling an instruction triggers a codegen
2627 /// error, so we propagate that error
2728 CodegenFail,
28};
29} || link.File.UpdateDebugInfoError;
2930
3031pub fn RegisterManager(
3132 comptime Function: type,
test/src/Debugger.zig created+500
......@@ -0,0 +1,500 @@
1b: *std.Build,
2options: Options,
3root_step: *std.Build.Step,
4
5pub const Options = struct {
6 test_filters: []const []const u8,
7 gdb: ?[]const u8,
8 lldb: ?[]const u8,
9 optimize_modes: []const std.builtin.OptimizeMode,
10 skip_single_threaded: bool,
11 skip_non_native: bool,
12 skip_libc: bool,
13};
14
15pub const Target = struct {
16 resolved: std.Build.ResolvedTarget,
17 optimize_mode: std.builtin.OptimizeMode = .Debug,
18 link_libc: ?bool = null,
19 single_threaded: ?bool = null,
20 pic: ?bool = null,
21 test_name_suffix: []const u8,
22};
23
24pub fn addTestsForTarget(db: *Debugger, target: Target) void {
25 db.addLldbTest(
26 "basic",
27 target,
28 &.{
29 .{
30 .path = "basic.zig",
31 .source =
32 \\const Basic = struct {
33 \\ void: void = {},
34 \\ bool_false: bool = false,
35 \\ bool_true: bool = true,
36 \\ u0_0: u0 = 0,
37 \\ u1_0: u1 = 0,
38 \\ u1_1: u1 = 1,
39 \\ u2_0: u2 = 0,
40 \\ u2_3: u2 = 3,
41 \\ u3_0: u3 = 0,
42 \\ u3_7: u3 = 7,
43 \\ u4_0: u4 = 0,
44 \\ u4_15: u4 = 15,
45 \\ u5_0: u5 = 0,
46 \\ u5_31: u5 = 31,
47 \\ u6_0: u6 = 0,
48 \\ u6_63: u6 = 63,
49 \\ u7_0: u7 = 0,
50 \\ u7_127: u7 = 127,
51 \\ u8_0: u8 = 0,
52 \\ u8_255: u8 = 255,
53 \\ u16_0: u16 = 0,
54 \\ u16_65535: u16 = 65535,
55 \\ u24_0: u24 = 0,
56 \\ u24_16777215: u24 = 16777215,
57 \\ u32_0: u32 = 0,
58 \\ u32_4294967295: u32 = 4294967295,
59 \\ i0_0: i0 = 0,
60 \\ @"i1_-1": i1 = -1,
61 \\ i1_0: i1 = 0,
62 \\ @"i2_-2": i2 = -2,
63 \\ i2_0: i2 = 0,
64 \\ i2_1: i2 = 1,
65 \\ @"i3_-4": i3 = -4,
66 \\ i3_0: i3 = 0,
67 \\ i3_3: i3 = 3,
68 \\ @"i4_-8": i4 = -8,
69 \\ i4_0: i4 = 0,
70 \\ i4_7: i4 = 7,
71 \\ @"i5_-16": i5 = -16,
72 \\ i5_0: i5 = 0,
73 \\ i5_15: i5 = 15,
74 \\ @"i6_-32": i6 = -32,
75 \\ i6_0: i6 = 0,
76 \\ i6_31: i6 = 31,
77 \\ @"i7_-64": i7 = -64,
78 \\ i7_0: i7 = 0,
79 \\ i7_63: i7 = 63,
80 \\ @"i8_-128": i8 = -128,
81 \\ i8_0: i8 = 0,
82 \\ i8_127: i8 = 127,
83 \\ @"i16_-32768": i16 = -32768,
84 \\ i16_0: i16 = 0,
85 \\ i16_32767: i16 = 32767,
86 \\ @"i24_-8388608": i24 = -8388608,
87 \\ i24_0: i24 = 0,
88 \\ i24_8388607: i24 = 8388607,
89 \\ @"i32_-2147483648": i32 = -2147483648,
90 \\ i32_0: i32 = 0,
91 \\ i32_2147483647: i32 = 2147483647,
92 \\ @"f16_42.625": f16 = 42.625,
93 \\ @"f32_-2730.65625": f32 = -2730.65625,
94 \\ @"f64_357913941.33203125": f64 = 357913941.33203125,
95 \\ @"f80_-91625968981.3330078125": f80 = -91625968981.3330078125,
96 \\ @"f128_384307168202282325.333332061767578125": f128 = 384307168202282325.333332061767578125,
97 \\};
98 \\fn testBasic(basic: Basic) void {
99 \\ _ = basic;
100 \\}
101 \\pub fn main() void {
102 \\ testBasic(.{});
103 \\}
104 \\
105 ,
106 },
107 },
108 \\breakpoint set --file basic.zig --source-pattern-regexp '_ = basic;'
109 \\process launch
110 \\frame variable --show-types basic
111 \\breakpoint delete --force 1
112 ,
113 &.{
114 \\(lldb) frame variable --show-types basic
115 \\(root.basic.Basic) basic = {
116 \\ (void) void = {}
117 \\ (bool) bool_false = false
118 \\ (bool) bool_true = true
119 \\ (u0) u0_0 = 0
120 \\ (u1) u1_0 = 0
121 \\ (u1) u1_1 = 1
122 \\ (u2) u2_0 = 0
123 \\ (u2) u2_3 = 3
124 \\ (u3) u3_0 = 0
125 \\ (u3) u3_7 = 7
126 \\ (u4) u4_0 = 0
127 \\ (u4) u4_15 = 15
128 \\ (u5) u5_0 = 0
129 \\ (u5) u5_31 = 31
130 \\ (u6) u6_0 = 0
131 \\ (u6) u6_63 = 63
132 \\ (u7) u7_0 = 0
133 \\ (u7) u7_127 = 127
134 \\ (u8) u8_0 = 0
135 \\ (u8) u8_255 = 255
136 \\ (u16) u16_0 = 0
137 \\ (u16) u16_65535 = 65535
138 \\ (u24) u24_0 = 0
139 \\ (u24) u24_16777215 = 16777215
140 \\ (u32) u32_0 = 0
141 \\ (u32) u32_4294967295 = 4294967295
142 \\ (i0) i0_0 = 0
143 \\ (i1) i1_-1 = -1
144 \\ (i1) i1_0 = 0
145 \\ (i2) i2_-2 = -2
146 \\ (i2) i2_0 = 0
147 \\ (i2) i2_1 = 1
148 \\ (i3) i3_-4 = -4
149 \\ (i3) i3_0 = 0
150 \\ (i3) i3_3 = 3
151 \\ (i4) i4_-8 = -8
152 \\ (i4) i4_0 = 0
153 \\ (i4) i4_7 = 7
154 \\ (i5) i5_-16 = -16
155 \\ (i5) i5_0 = 0
156 \\ (i5) i5_15 = 15
157 \\ (i6) i6_-32 = -32
158 \\ (i6) i6_0 = 0
159 \\ (i6) i6_31 = 31
160 \\ (i7) i7_-64 = -64
161 \\ (i7) i7_0 = 0
162 \\ (i7) i7_63 = 63
163 \\ (i8) i8_-128 = -128
164 \\ (i8) i8_0 = 0
165 \\ (i8) i8_127 = 127
166 \\ (i16) i16_-32768 = -32768
167 \\ (i16) i16_0 = 0
168 \\ (i16) i16_32767 = 32767
169 \\ (i24) i24_-8388608 = -8388608
170 \\ (i24) i24_0 = 0
171 \\ (i24) i24_8388607 = 8388607
172 \\ (i32) i32_-2147483648 = -2147483648
173 \\ (i32) i32_0 = 0
174 \\ (i32) i32_2147483647 = 2147483647
175 \\ (f16) f16_42.625 = 42.625
176 \\ (f32) f32_-2730.65625 = -2730.65625
177 \\ (f64) f64_357913941.33203125 = 357913941.33203125
178 \\ (f80) f80_-91625968981.3330078125 = -91625968981.3330078125
179 \\ (f128) f128_384307168202282325.333332061767578125 = 384307168202282325.333332061767578125
180 \\}
181 \\(lldb) breakpoint delete --force 1
182 \\1 breakpoints deleted; 0 breakpoint locations disabled.
183 },
184 );
185 db.addLldbTest(
186 "storage",
187 target,
188 &.{
189 .{
190 .path = "storage.zig",
191 .source =
192 \\const global_const: u64 = 0x19e50dc8d6002077;
193 \\var global_var: u64 = 0xcc423cec08622e32;
194 \\threadlocal var global_threadlocal1: u64 = 0xb4d643528c042121;
195 \\threadlocal var global_threadlocal2: u64 = 0x43faea1cf5ad7a22;
196 \\fn testStorage(
197 \\ param1: u64,
198 \\ param2: u64,
199 \\ param3: u64,
200 \\ param4: u64,
201 \\ param5: u64,
202 \\ param6: u64,
203 \\ param7: u64,
204 \\ param8: u64,
205 \\) callconv(.C) void {
206 \\ const local_comptime_val: u64 = global_const *% global_const;
207 \\ const local_comptime_ptr: struct { u64 } = .{ local_comptime_val *% local_comptime_val };
208 \\ const local_const: u64 = global_var ^ global_threadlocal1 ^ global_threadlocal2 ^
209 \\ param1 ^ param2 ^ param3 ^ param4 ^ param5 ^ param6 ^ param7 ^ param8;
210 \\ var local_var: u64 = local_comptime_ptr[0] ^ local_const;
211 \\ local_var = local_var;
212 \\}
213 \\pub fn main() void {
214 \\ testStorage(
215 \\ 0x6a607e08125c7e00,
216 \\ 0x98944cb2a45a8b51,
217 \\ 0xa320cf10601ee6fb,
218 \\ 0x691ed3535bad3274,
219 \\ 0x63690e6867a5799f,
220 \\ 0x8e163f0ec76067f2,
221 \\ 0xf9a252c455fb4c06,
222 \\ 0xc88533722601e481,
223 \\ );
224 \\}
225 \\
226 ,
227 },
228 },
229 \\breakpoint set --file storage.zig --source-pattern-regexp 'local_var = local_var;'
230 \\process launch
231 \\target variable --show-types --format hex global_const global_var global_threadlocal1 global_threadlocal2
232 \\frame variable --show-types --format hex param1 param2 param3 param4 param5 param6 param7 param8 local_comptime_val local_comptime_ptr.0 local_const local_var
233 \\breakpoint delete --force 1
234 ,
235 &.{
236 \\(lldb) target variable --show-types --format hex global_const global_var global_threadlocal1 global_threadlocal2
237 \\(u64) global_const = 0x19e50dc8d6002077
238 \\(u64) global_var = 0xcc423cec08622e32
239 \\(u64) global_threadlocal1 = 0xb4d643528c042121
240 \\(u64) global_threadlocal2 = 0x43faea1cf5ad7a22
241 \\(lldb) frame variable --show-types --format hex param1 param2 param3 param4 param5 param6 param7 param8 local_comptime_val local_comptime_ptr.0 local_const local_var
242 \\(u64) param1 = 0x6a607e08125c7e00
243 \\(u64) param2 = 0x98944cb2a45a8b51
244 \\(u64) param3 = 0xa320cf10601ee6fb
245 \\(u64) param4 = 0x691ed3535bad3274
246 \\(u64) param5 = 0x63690e6867a5799f
247 \\(u64) param6 = 0x8e163f0ec76067f2
248 \\(u64) param7 = 0xf9a252c455fb4c06
249 \\(u64) param8 = 0xc88533722601e481
250 \\(u64) local_comptime_val = 0x69490636f81df751
251 \\(u64) local_comptime_ptr.0 = 0x82e834dae74767a1
252 \\(u64) local_const = 0xdffceb8b2f41e205
253 \\(u64) local_var = 0x5d14df51c80685a4
254 \\(lldb) breakpoint delete --force 1
255 \\1 breakpoints deleted; 0 breakpoint locations disabled.
256 },
257 );
258 db.addLldbTest(
259 "slices",
260 target,
261 &.{
262 .{
263 .path = "slices.zig",
264 .source =
265 \\pub fn main() void {
266 \\ {
267 \\ var array: [4]u32 = .{ 1, 2, 4, 8 };
268 \\ const slice: []u32 = &array;
269 \\ _ = slice;
270 \\ }
271 \\}
272 \\
273 ,
274 },
275 },
276 \\breakpoint set --file slices.zig --source-pattern-regexp '_ = slice;'
277 \\process launch
278 \\frame variable --show-types array slice
279 \\breakpoint delete --force 1
280 ,
281 &.{
282 \\(lldb) frame variable --show-types array slice
283 \\([4]u32) array = {
284 \\ (u32) [0] = 1
285 \\ (u32) [1] = 2
286 \\ (u32) [2] = 4
287 \\ (u32) [3] = 8
288 \\}
289 \\([]u32) slice = {
290 \\ (u32) [0] = 1
291 \\ (u32) [1] = 2
292 \\ (u32) [2] = 4
293 \\ (u32) [3] = 8
294 \\}
295 \\(lldb) breakpoint delete --force 1
296 \\1 breakpoints deleted; 0 breakpoint locations disabled.
297 },
298 );
299 db.addLldbTest(
300 "optionals",
301 target,
302 &.{
303 .{
304 .path = "optionals.zig",
305 .source =
306 \\pub fn main() void {
307 \\ {
308 \\ var null_u32: ?u32 = null;
309 \\ var maybe_u32: ?u32 = null;
310 \\ var nonnull_u32: ?u32 = 456;
311 \\ maybe_u32 = 123;
312 \\ _ = .{ &null_u32, &nonnull_u32 };
313 \\ }
314 \\}
315 \\
316 ,
317 },
318 },
319 \\breakpoint set --file optionals.zig --source-pattern-regexp 'maybe_u32 = 123;'
320 \\process launch
321 \\frame variable null_u32 maybe_u32 nonnull_u32
322 \\breakpoint delete --force 1
323 \\
324 \\breakpoint set --file optionals.zig --source-pattern-regexp '_ = .{ &null_u32, &nonnull_u32 };'
325 \\process continue
326 \\frame variable --show-types null_u32 maybe_u32 nonnull_u32
327 \\breakpoint delete --force 2
328 ,
329 &.{
330 \\(lldb) frame variable null_u32 maybe_u32 nonnull_u32
331 \\(?u32) null_u32 = null
332 \\(?u32) maybe_u32 = null
333 \\(?u32) nonnull_u32 = (nonnull_u32.? = 456)
334 \\(lldb) breakpoint delete --force 1
335 \\1 breakpoints deleted; 0 breakpoint locations disabled.
336 ,
337 \\(lldb) frame variable --show-types null_u32 maybe_u32 nonnull_u32
338 \\(?u32) null_u32 = null
339 \\(?u32) maybe_u32 = {
340 \\ (u32) maybe_u32.? = 123
341 \\}
342 \\(?u32) nonnull_u32 = {
343 \\ (u32) nonnull_u32.? = 456
344 \\}
345 \\(lldb) breakpoint delete --force 2
346 \\1 breakpoints deleted; 0 breakpoint locations disabled.
347 },
348 );
349 db.addLldbTest(
350 "cross_module_call",
351 target,
352 &.{
353 .{
354 .path = "main.zig",
355 .source =
356 \\const module = @import("module");
357 \\pub fn main() void {
358 \\ module.foo(123);
359 \\ module.bar(456);
360 \\}
361 ,
362 },
363 .{
364 .import = "module",
365 .path = "module.zig",
366 .source =
367 \\pub fn foo(x: u32) void {
368 \\ _ = x;
369 \\}
370 \\pub inline fn bar(y: u32) void {
371 \\ _ = y;
372 \\}
373 ,
374 },
375 },
376 \\breakpoint set --file module.zig --source-pattern-regexp '_ = x;'
377 \\process launch
378 \\source info
379 \\breakpoint delete --force 1
380 \\
381 \\breakpoint set --file module.zig --line 5
382 \\process continue
383 \\source info
384 \\breakpoint delete --force 2
385 ,
386 &.{
387 \\/module.zig:2:5
388 \\(lldb) breakpoint delete --force 1
389 \\1 breakpoints deleted; 0 breakpoint locations disabled.
390 ,
391 \\/module.zig:5:5
392 \\(lldb) breakpoint delete --force 2
393 \\1 breakpoints deleted; 0 breakpoint locations disabled.
394 },
395 );
396}
397
398const File = struct { import: ?[]const u8 = null, path: []const u8, source: []const u8 };
399
400fn addGdbTest(
401 db: *Debugger,
402 name: []const u8,
403 target: Target,
404 files: []const File,
405 commands: []const u8,
406 expected_output: []const []const u8,
407) void {
408 db.addTest(
409 name,
410 target,
411 files,
412 &.{
413 db.options.gdb orelse return,
414 "--batch",
415 "--command",
416 },
417 commands,
418 &.{
419 "--args",
420 },
421 expected_output,
422 );
423}
424
425fn addLldbTest(
426 db: *Debugger,
427 name: []const u8,
428 target: Target,
429 files: []const File,
430 commands: []const u8,
431 expected_output: []const []const u8,
432) void {
433 db.addTest(
434 name,
435 target,
436 files,
437 &.{
438 db.options.lldb orelse return,
439 "--batch",
440 "--source",
441 },
442 commands,
443 &.{
444 "--",
445 },
446 expected_output,
447 );
448}
449
450/// After a failure while running a script, the debugger starts accepting commands from stdin, and
451/// because it is empty, the debugger exits normally with status 0. Choose a non-zero status to
452/// return from the debugger script instead to detect it running to completion and indicate success.
453const success = 99;
454
455fn addTest(
456 db: *Debugger,
457 name: []const u8,
458 target: Target,
459 files: []const File,
460 db_argv1: []const []const u8,
461 commands: []const u8,
462 db_argv2: []const []const u8,
463 expected_output: []const []const u8,
464) void {
465 for (db.options.test_filters) |test_filter| {
466 if (std.mem.indexOf(u8, name, test_filter)) |_| return;
467 }
468 const files_wf = db.b.addWriteFiles();
469 const exe = db.b.addExecutable(.{
470 .name = name,
471 .target = target.resolved,
472 .root_source_file = files_wf.add(files[0].path, files[0].source),
473 .optimize = target.optimize_mode,
474 .link_libc = target.link_libc,
475 .single_threaded = target.single_threaded,
476 .pic = target.pic,
477 .strip = false,
478 .use_llvm = false,
479 .use_lld = false,
480 });
481 for (files[1..]) |file| {
482 const path = files_wf.add(file.path, file.source);
483 if (file.import) |import| exe.root_module.addImport(import, db.b.createModule(.{
484 .root_source_file = path,
485 }));
486 }
487 const commands_wf = db.b.addWriteFiles();
488 const run = std.Build.Step.Run.create(db.b, db.b.fmt("run {s} {s}", .{ name, target.test_name_suffix }));
489 run.addArgs(db_argv1);
490 run.addFileArg(commands_wf.add(db.b.fmt("{s}.cmd", .{name}), db.b.fmt("{s}\n\nquit {d}\n", .{ commands, success })));
491 run.addArgs(db_argv2);
492 run.addArtifactArg(exe);
493 for (expected_output) |expected| run.addCheck(.{ .expect_stdout_match = db.b.fmt("{s}\n", .{expected}) });
494 run.addCheck(.{ .expect_term = .{ .Exited = success } });
495 run.setStdIn(.{ .bytes = "" });
496 db.root_step.dependOn(&run.step);
497}
498
499const Debugger = @This();
500const std = @import("std");
test/tests.zig+34
......@@ -17,6 +17,7 @@ pub const TranslateCContext = @import("src/TranslateC.zig");
1717pub const RunTranslatedCContext = @import("src/RunTranslatedC.zig");
1818pub const CompareOutputContext = @import("src/CompareOutput.zig");
1919pub const StackTracesContext = @import("src/StackTrace.zig");
20pub const DebuggerContext = @import("src/Debugger.zig");
2021
2122const TestTarget = struct {
2223 target: std.Target.Query = .{},
......@@ -1283,3 +1284,36 @@ pub fn addCases(
12831284 test_filters,
12841285 );
12851286}
1287
1288pub fn addDebuggerTests(b: *std.Build, options: DebuggerContext.Options) ?*Step {
1289 const step = b.step("test-debugger", "Run the debugger tests");
1290 if (options.gdb == null and options.lldb == null) {
1291 step.dependOn(&b.addFail("test-debugger requires -Dgdb and/or -Dlldb").step);
1292 return null;
1293 }
1294
1295 var context: DebuggerContext = .{
1296 .b = b,
1297 .options = options,
1298 .root_step = step,
1299 };
1300 context.addTestsForTarget(.{
1301 .resolved = b.resolveTargetQuery(.{
1302 .cpu_arch = .x86_64,
1303 .os_tag = .linux,
1304 .abi = .none,
1305 }),
1306 .pic = false,
1307 .test_name_suffix = "x86_64-linux",
1308 });
1309 context.addTestsForTarget(.{
1310 .resolved = b.resolveTargetQuery(.{
1311 .cpu_arch = .x86_64,
1312 .os_tag = .linux,
1313 .abi = .none,
1314 }),
1315 .pic = true,
1316 .test_name_suffix = "x86_64-linux-pic",
1317 });
1318 return step;
1319}