authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-08-06 11:22:37-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-08-16 15:22:55-04:00
logef11bc9899002620d67cfce9c79b6c0dc0f5ea61
tree7b05fe17340c06e4c40c45ebe249361c0c281c72
parent90989be0e31a91335f8d1c1eafb84c3b34792a8c

Dwarf: rework self-hosted debug info from scratch

This is in preparation for incremental and actually being able to debug executables built by the x86_64 backend.

50 files changed, 5127 insertions(+), 3502 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/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+138-95
......@@ -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,
......@@ -2425,7 +2438,7 @@ fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayo
24252438 const callee_preserved_regs =
24262439 abi.getCalleePreservedRegs(abi.resolveCallingConvention(cc, self.target.*));
24272440 for (callee_preserved_regs) |reg| {
2428 if (self.register_manager.isRegAllocated(reg) or true) {
2441 if (self.register_manager.isRegAllocated(reg)) {
24292442 save_reg_list.push(callee_preserved_regs, reg);
24302443 }
24312444 }
......@@ -5985,10 +5998,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
59855998 switch (operand) {
59865999 .load_frame => |frame_addr| {
59876000 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;
6001 const off: i32 = @intCast(layout.tagOffset());
59926002 break :blk try self.copyToRegisterWithInstTracking(inst, tag_ty, .{
59936003 .load_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off },
59946004 });
......@@ -6000,10 +6010,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
60006010 );
60016011 },
60026012 .register => {
6003 const shift: u6 = if (layout.tag_align.compare(.lt, layout.payload_align))
6004 @intCast(layout.payload_size * 8)
6005 else
6006 0;
6013 const shift: u6 = @intCast(layout.tagOffset() * 8);
60076014 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
60086015 try self.genShiftBinOpMir(
60096016 .{ ._r, .sh },
......@@ -11819,7 +11826,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
1181911826 while (self.args[arg_index] == .none) arg_index += 1;
1182011827 self.arg_index = arg_index + 1;
1182111828
11822 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
11829 const result: MCValue = if (self.debug_output == .none and self.liveness.isUnused(inst)) .unreach else result: {
11830 const name = switch (self.debug_output) {
11831 .none => "",
11832 else => name: {
11833 const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
11834 break :name self.air.nullTerminatedString(@intFromEnum(name_nts));
11835 },
11836 };
11837 if (name.len == 0 and self.liveness.isUnused(inst)) break :result .unreach;
11838
1182311839 const arg_ty = self.typeOfIndex(inst);
1182411840 const src_mcv = self.args[arg_index];
1182511841 const dst_mcv = switch (src_mcv) {
......@@ -11922,90 +11938,86 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
1192211938 else => return self.fail("TODO implement arg for {}", .{src_mcv}),
1192311939 };
1192411940
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),
11929 }
11941 if (name.len > 0) try self.genVarDebugInfo(.local_arg, .dbg_var_val, name, arg_ty, dst_mcv);
1193011942
11943 if (self.liveness.isUnused(inst)) {
11944 assert(self.debug_output != .none and name.len > 0);
11945 try self.freeValue(dst_mcv);
11946 break :result .none;
11947 }
1193111948 break :result dst_mcv;
1193211949 };
1193311950 return self.finishAir(inst, result, .{ .none, .none, .none });
1193411951}
1193511952
11936fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
11953fn genVarDebugInfo(
11954 self: *Self,
11955 var_tag: link.File.Dwarf.WipNav.VarTag,
11956 tag: Air.Inst.Tag,
11957 name: []const u8,
11958 ty: Type,
11959 mcv: MCValue,
11960) !void {
11961 const stack_vars = switch (var_tag) {
11962 .local_arg => &self.stack_args,
11963 .local_var => &self.stack_vars,
11964 };
1193711965 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);
11966 .dwarf => |dwarf| switch (tag) {
11967 else => unreachable,
11968 .dbg_var_ptr => {
11969 const var_ty = ty.childType(self.pt.zcu);
11970 switch (mcv) {
11971 else => {
11972 log.info("dbg_var_ptr({s}({}))", .{ @tagName(mcv), mcv });
11973 unreachable;
11974 },
11975 .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
11976 .lea_frame => |frame_addr| try stack_vars.append(self.gpa, .{
11977 .name = name,
11978 .type = var_ty,
11979 .frame_addr = frame_addr,
11980 }),
11981 .lea_symbol => |sym_off| try dwarf.genVarDebugInfo(var_tag, name, var_ty, .{ .plus = .{
11982 &.{ .addr = .{ .sym = sym_off.sym } },
11983 &.{ .consts = sym_off.off },
11984 } }),
11985 }
11986 },
11987 .dbg_var_val => switch (mcv) {
11988 .none => try dwarf.genVarDebugInfo(var_tag, name, ty, .empty),
11989 .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
11990 .immediate => |immediate| try dwarf.genVarDebugInfo(var_tag, name, ty, .{ .stack_value = &.{
11991 .constu = immediate,
11992 } }),
11993 else => {
11994 const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(ty, self.pt));
11995 try self.genSetMem(.{ .frame = frame_index }, 0, ty, mcv, .{});
11996 try stack_vars.append(self.gpa, .{
11997 .name = name,
11998 .type = ty,
11999 .frame_addr = .{ .index = frame_index },
12000 });
12001 },
12002 },
1195912003 },
1196012004 .plan9 => {},
1196112005 .none => {},
1196212006 }
1196312007}
1196412008
11965fn genVarDbgInfo(
12009fn genStackVarDebugInfo(
1196612010 self: Self,
11967 tag: Air.Inst.Tag,
11968 ty: Type,
11969 mcv: MCValue,
11970 name: [:0]const u8,
12011 var_tag: link.File.Dwarf.WipNav.VarTag,
12012 stack_vars: []const StackVar,
1197112013) !void {
11972 const is_ptr = switch (tag) {
11973 .dbg_var_ptr => true,
11974 .dbg_var_val => false,
11975 else => unreachable,
11976 };
11977
1197812014 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;
12003 },
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);
12015 .dwarf => |dwarf| for (stack_vars) |stack_var| {
12016 const frame_loc = self.frame_locs.get(@intFromEnum(stack_var.frame_addr.index));
12017 try dwarf.genVarDebugInfo(var_tag, stack_var.name, stack_var.type, .{ .plus = .{
12018 &.{ .breg = frame_loc.base.dwarfNum() },
12019 &.{ .consts = @as(i33, frame_loc.disp) + stack_var.frame_addr.off },
12020 } });
1200912021 },
1201012022 .plan9 => {},
1201112023 .none => {},
......@@ -13045,7 +13057,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
1304513057 const name = self.air.nullTerminatedString(pl_op.payload);
1304613058
1304713059 const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
13048 try self.genVarDbgInfo(tag, ty, mcv, name);
13060 try self.genVarDebugInfo(.local_var, tag, name, ty, mcv);
1304913061
1305013062 return self.finishAir(inst, .unreach, .{ operand, .none, .none });
1305113063}
......@@ -13154,13 +13166,17 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
1315413166 .lea_direct,
1315513167 .lea_got,
1315613168 .lea_tlv,
13157 .lea_frame,
1315813169 .lea_symbol,
1315913170 .elementwise_regs_then_frame,
1316013171 .reserved_frame,
1316113172 .air_ref,
1316213173 => unreachable,
1316313174
13175 .lea_frame => {
13176 self.eflags_inst = null;
13177 return .{ .immediate = @intFromBool(false) };
13178 },
13179
1316413180 .register => |opt_reg| {
1316513181 if (some_info.off == 0) {
1316613182 const some_abi_size: u32 = @intCast(some_info.ty.abiSize(pt));
......@@ -13402,7 +13418,8 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
1340213418 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
1340313419 const operand = try self.resolveInst(un_op);
1340413420 const ty = self.typeOf(un_op);
13405 const result = switch (try self.isNull(inst, ty, operand)) {
13421 const result: MCValue = switch (try self.isNull(inst, ty, operand)) {
13422 .immediate => |imm| .{ .immediate = @intFromBool(imm == 0) },
1340613423 .eflags => |cc| .{ .eflags = cc.negate() },
1340713424 else => unreachable,
1340813425 };
......@@ -15156,7 +15173,7 @@ fn genSetMem(
1515615173 })).write(
1515715174 self,
1515815175 .{ .base = base, .mod = .{ .rm = .{
15159 .size = self.memSize(ty),
15176 .size = Memory.Size.fromBitSize(@min(self.memSize(ty).bitSize(), src_alias.bitSize())),
1516015177 .disp = disp,
1516115178 } } },
1516215179 src_alias,
......@@ -15202,7 +15219,33 @@ fn genSetMem(
1520215219 @tagName(src_mcv), ty.fmt(pt),
1520315220 }),
1520415221 },
15205 .register_offset,
15222 .register_offset => |reg_off| {
15223 const src_reg = self.copyToTmpRegister(ty, src_mcv) catch |err| switch (err) {
15224 error.OutOfRegisters => {
15225 const src_reg = registerAlias(reg_off.reg, abi_size);
15226 try self.asmRegisterMemory(.{ ._, .lea }, src_reg, .{
15227 .base = .{ .reg = src_reg },
15228 .mod = .{ .rm = .{
15229 .size = .qword,
15230 .disp = reg_off.off,
15231 } },
15232 });
15233 try self.genSetMem(base, disp, ty, .{ .register = reg_off.reg }, opts);
15234 return self.asmRegisterMemory(.{ ._, .lea }, src_reg, .{
15235 .base = .{ .reg = src_reg },
15236 .mod = .{ .rm = .{
15237 .size = .qword,
15238 .disp = -reg_off.off,
15239 } },
15240 });
15241 },
15242 else => |e| return e,
15243 };
15244 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
15245 defer self.register_manager.unlockReg(src_lock);
15246
15247 try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts);
15248 },
1520615249 .memory,
1520715250 .indirect,
1520815251 .load_direct,
......@@ -15422,9 +15465,14 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
1542215465 const src_ty = self.typeOf(ty_op.operand);
1542315466
1542415467 const result = result: {
15468 const src_mcv = try self.resolveInst(ty_op.operand);
15469 if (dst_ty.isPtrAtRuntime(mod) and src_ty.isPtrAtRuntime(mod)) switch (src_mcv) {
15470 .lea_frame => break :result src_mcv,
15471 else => if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv,
15472 };
15473
1542515474 const dst_rc = self.regClassForType(dst_ty);
1542615475 const src_rc = self.regClassForType(src_ty);
15427 const src_mcv = try self.resolveInst(ty_op.operand);
1542815476
1542915477 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
1543015478 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -18236,10 +18284,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
1823618284 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
1823718285 const tag_int_val = try tag_val.intFromEnum(tag_ty, pt);
1823818286 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;
18287 const tag_off: i32 = @intCast(layout.tagOffset());
1824318288 try self.genCopy(
1824418289 tag_ty,
1824518290 dst_mcv.address().offset(tag_off).deref(),
......@@ -18247,10 +18292,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
1824718292 .{},
1824818293 );
1824918294
18250 const pl_off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))
18251 0
18252 else
18253 @intCast(layout.tag_size);
18295 const pl_off: i32 = @intCast(layout.payloadOffset());
1825418296 try self.genCopy(src_ty, dst_mcv.address().offset(pl_off).deref(), src_mcv, .{});
1825518297
1825618298 break :result dst_mcv;
......@@ -18790,6 +18832,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
1879018832 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
1879118833 .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } },
1879218834 .load_direct => |sym_index| .{ .load_direct = sym_index },
18835 .lea_direct => |sym_index| .{ .lea_direct = sym_index },
1879318836 .load_got => |sym_index| .{ .lea_got = sym_index },
1879418837 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
1879518838 },
src/arch/x86_64/Emit.zig+1-1
......@@ -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| {
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+31-28
......@@ -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));
src/link/Dwarf.zig+3566-2666
......@@ -1,2884 +1,3784 @@
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, struct {
8 files: Files,
9}),
10types: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index),
11navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index),
12
13debug_abbrev: DebugAbbrev,
14debug_aranges: DebugAranges,
15debug_info: DebugInfo,
16debug_line: DebugLine,
17debug_line_str: StringSection,
18debug_loclists: DebugLocLists,
19debug_rnglists: DebugRngLists,
20debug_str: StringSection,
21
22pub const UpdateError =
23 std.fs.File.OpenError ||
24 std.fs.File.SetEndPosError ||
25 std.fs.File.CopyRangeError ||
26 std.fs.File.PWriteError ||
27 error{ Overflow, Underflow, UnexpectedEndOfFile };
28
29pub const FlushError =
30 UpdateError ||
31 std.process.GetCwdError;
32
33pub const RelocError =
34 std.fs.File.PWriteError;
35
36pub const AddressSize = enum(u8) {
37 @"32" = 4,
38 @"64" = 8,
39 _,
40};
4841
49 prev_index: ?Index,
50 next_index: ?Index,
42const Files = std.AutoArrayHashMapUnmanaged(Zcu.File.Index, void);
5143
52 pub const Index = u32;
44const DebugAbbrev = struct {
45 section: Section,
46 const unit: Unit.Index = @enumFromInt(0);
47 const entry: Entry.Index = @enumFromInt(0);
5348};
5449
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,
62};
50const DebugAranges = struct {
51 section: Section,
6352
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 });
53 fn headerBytes(dwarf: *Dwarf) u32 {
54 return std.mem.alignForwardAnyAlign(
55 u32,
56 dwarf.unitLengthBytes() + 2 + dwarf.sectionOffsetBytes() + 1 + 1,
57 @intFromEnum(dwarf.address_size) * 2,
58 );
10259 }
10360
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 });
61 fn trailerBytes(dwarf: *Dwarf) u32 {
62 return @intFromEnum(dwarf.address_size) * 2;
12763 }
64};
12865
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;
66const DebugInfo = struct {
67 section: Section,
14068
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 }
69 fn headerBytes(dwarf: *Dwarf) u32 {
70 return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() +
71 uleb128Bytes(@intFromEnum(AbbrevCode.compile_unit)) + 1 + dwarf.sectionOffsetBytes() * 6 + uleb128Bytes(0) +
72 uleb128Bytes(@intFromEnum(AbbrevCode.module)) + dwarf.sectionOffsetBytes() + uleb128Bytes(0);
73 }
32374
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 }
75 fn declEntryLineOff(dwarf: *Dwarf) u32 {
76 return AbbrevCode.decl_bytes + dwarf.sectionOffsetBytes();
77 }
36378
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 }
79 const trailer_bytes = 1 + 1;
80};
39581
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 }
82const DebugLine = struct {
83 header: Header,
84 section: Section,
85
86 const Header = struct {
87 minimum_instruction_length: u8,
88 maximum_operations_per_instruction: u8,
89 default_is_stmt: bool,
90 line_base: i8,
91 line_range: u8,
92 opcode_base: u8,
93 };
43094
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 }
95 fn headerBytes(dwarf: *Dwarf, file_count: u32) u32 {
96 return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() + 1 + 1 + 1 + 1 + 1 + 1 + 1 * (dwarf.debug_line.header.opcode_base - 1) +
97 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(1) + (dwarf.sectionOffsetBytes()) * 1 +
98 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(DW.LNCT.LLVM_source) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(file_count) + (dwarf.sectionOffsetBytes() + dwarf.sectionOffsetBytes()) * file_count;
99 }
442100
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 }
101 const trailer_bytes = 1 + uleb128Bytes(0) +
102 1 + uleb128Bytes(1) + 1;
103};
510104
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 }
105const DebugLocLists = struct {
106 section: Section,
525107
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 }
108 fn baseOffset(dwarf: *Dwarf) u32 {
109 return dwarf.unitLengthBytes() + 2 + 1 + 1 + 4;
534110 }
535111
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 };
112 fn headerBytes(dwarf: *Dwarf) u32 {
113 return baseOffset(dwarf);
114 }
551115
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];
116 const trailer_bytes = 0;
117};
563118
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 }
119const DebugRngLists = struct {
120 section: Section,
660121
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 }
122 const baseOffset = DebugLocLists.baseOffset;
667123
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;
124 fn headerBytes(dwarf: *Dwarf) u32 {
125 return baseOffset(dwarf) + dwarf.sectionOffsetBytes() * 1;
126 }
685127
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 },
128 const trailer_bytes = 1;
129};
705130
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 },
131const StringSection = struct {
132 contents: std.ArrayListUnmanaged(u8),
133 map: std.AutoArrayHashMapUnmanaged(void, void),
134 section: Section,
741135
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 },
136 const unit: Unit.Index = @enumFromInt(0);
778137
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 },
138 const init: StringSection = .{
139 .contents = .{},
140 .map = .{},
141 .section = Section.init,
142 };
829143
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 },
144 fn deinit(str_sec: *StringSection, gpa: std.mem.Allocator) void {
145 str_sec.contents.deinit(gpa);
146 str_sec.map.deinit(gpa);
147 str_sec.section.deinit(gpa);
148 }
868149
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 },
150 fn addString(str_sec: *StringSection, dwarf: *Dwarf, str: []const u8) UpdateError!Entry.Index {
151 const gop = try str_sec.map.getOrPutAdapted(dwarf.gpa, str, Adapter{ .str_sec = str_sec });
152 errdefer _ = str_sec.map.pop();
153 const entry: Entry.Index = @enumFromInt(gop.index);
154 if (!gop.found_existing) {
155 assert(try str_sec.section.addEntry(unit, dwarf) == entry);
156 errdefer _ = str_sec.section.getUnit(unit).entries.pop();
157 const entry_ptr = str_sec.section.getUnit(unit).getEntry(entry);
158 assert(entry_ptr.off == str_sec.contents.items.len);
159 entry_ptr.len = @intCast(str.len + 1);
160 try str_sec.contents.ensureUnusedCapacity(dwarf.gpa, str.len + 1);
161 str_sec.contents.appendSliceAssumeCapacity(str);
162 str_sec.contents.appendAssumeCapacity(0);
163 str_sec.section.dirty = true;
875164 }
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
165 return entry;
882166 }
883167
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);
168 const Adapter = struct {
169 str_sec: *StringSection,
891170
892 const header = self.dwarf.dbg_line_header;
893 assert(header.maximum_operations_per_instruction == 1);
894 const delta_op: u64 = 0;
171 pub fn hash(_: Adapter, key: []const u8) u32 {
172 return @truncate(std.hash.Wyhash.hash(0, key));
173 }
895174
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);
175 pub fn eql(adapter: Adapter, key: []const u8, _: void, rhs_index: usize) bool {
176 const entry = adapter.str_sec.section.getUnit(unit).getEntry(@enumFromInt(rhs_index));
177 return std.mem.eql(u8, key, adapter.str_sec.contents.items[entry.off..][0 .. entry.len - 1 :0]);
178 }
179 };
180};
904181
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);
182/// A linker section containing a sequence of `Unit`s.
183const Section = struct {
184 dirty: bool,
185 pad_to_ideal: bool,
186 alignment: InternPool.Alignment,
187 index: u32,
188 first: Unit.Index.Optional,
189 last: Unit.Index.Optional,
190 off: u64,
191 len: u64,
192 units: std.ArrayListUnmanaged(Unit),
193
194 const Index = enum {
195 debug_abbrev,
196 debug_info,
197 debug_line,
198 debug_line_str,
199 debug_loclists,
200 debug_rnglists,
201 debug_str,
202 };
916203
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 }
204 const init: Section = .{
205 .dirty = true,
206 .pad_to_ideal = true,
207 .alignment = .@"1",
208 .index = std.math.maxInt(u32),
209 .first = .none,
210 .last = .none,
211 .off = 0,
212 .len = 0,
213 .units = .{},
214 };
215
216 fn deinit(sec: *Section, gpa: std.mem.Allocator) void {
217 for (sec.units.items) |*unit| unit.deinit(gpa);
218 sec.units.deinit(gpa);
219 sec.* = undefined;
923220 }
924221
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;
222 fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index {
223 const unit: Unit.Index = @enumFromInt(sec.units.items.len);
224 const unit_ptr = try sec.units.addOne(dwarf.gpa);
225 errdefer sec.popUnit();
226 unit_ptr.* = .{
227 .prev = sec.last,
228 .next = .none,
229 .first = .none,
230 .last = .none,
231 .off = 0,
232 .header_len = header_len,
233 .trailer_len = trailer_len,
234 .len = header_len + trailer_len,
235 .entries = .{},
236 .cross_entry_relocs = .{},
237 .cross_unit_relocs = .{},
238 .cross_section_relocs = .{},
239 .external_relocs = .{},
240 };
241 if (sec.last.unwrap()) |last_unit| {
242 const last_unit_ptr = sec.getUnit(last_unit);
243 last_unit_ptr.next = unit.toOptional();
244 unit_ptr.off = last_unit_ptr.off + sec.padToIdeal(last_unit_ptr.len);
245 }
246 if (sec.first == .none)
247 sec.first = unit.toOptional();
248 sec.last = unit.toOptional();
249 try sec.resize(dwarf, unit_ptr.off + sec.padToIdeal(unit_ptr.len));
250 return unit;
929251 }
930252
931 pub fn setPrologueEnd(self: *NavState) error{OutOfMemory}!void {
932 try self.dbg_line.append(DW.LNS.set_prologue_end);
253 fn unlinkUnit(sec: *Section, unit: Unit.Index) void {
254 const unit_ptr = sec.getUnit(unit);
255 if (unit_ptr.prev.unwrap()) |prev_unit| sec.getUnit(prev_unit).next = unit_ptr.next;
256 if (unit_ptr.next.unwrap()) |next_unit| sec.getUnit(next_unit).prev = unit_ptr.prev;
257 if (sec.first.unwrap().? == unit) sec.first = unit_ptr.next;
258 if (sec.last.unwrap().? == unit) sec.last = unit_ptr.prev;
933259 }
934260
935 pub fn setEpilogueBegin(self: *NavState) error{OutOfMemory}!void {
936 try self.dbg_line.append(DW.LNS.set_epilogue_begin);
261 fn popUnit(sec: *Section) void {
262 const unit: Unit.Index = @enumFromInt(sec.units.items.len - 1);
263 sec.unlinkUnit(unit);
264 _ = sec.units.pop();
937265 }
938266
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;
267 fn addEntry(sec: *Section, unit: Unit.Index, dwarf: *Dwarf) UpdateError!Entry.Index {
268 return sec.getUnit(unit).addEntry(sec, dwarf);
269 }
942270
943 try self.dbg_line.ensureUnusedCapacity((1 + 4) + (1 + 5));
271 fn getUnit(sec: *Section, unit: Unit.Index) *Unit {
272 return &sec.units.items[@intFromEnum(unit)];
273 }
944274
945 const old_func_info = zcu.funcInfo(self.dbg_line_func);
946 const new_func_info = zcu.funcInfo(func);
275 fn replaceEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
276 const unit_ptr = sec.getUnit(unit);
277 try unit_ptr.getEntry(entry).replace(unit_ptr, sec, dwarf, contents);
278 }
947279
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);
280 fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {
281 if (dwarf.bin_file.cast(.elf)) |elf_file| {
282 try elf_file.growNonAllocSection(sec.index, len, @intCast(sec.alignment.toByteUnits().?), true);
283 const shdr = &elf_file.shdrs.items[sec.index];
284 sec.off = shdr.sh_offset;
285 sec.len = shdr.sh_size;
286 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
287 const header = if (macho_file.d_sym) |*d_sym| header: {
288 try d_sym.growSection(@intCast(sec.index), len, true, macho_file);
289 break :header &d_sym.sections.items[sec.index];
290 } else header: {
291 try macho_file.growSection(@intCast(sec.index), len);
292 break :header &macho_file.sections.items(.header)[sec.index];
293 };
294 sec.off = header.offset;
295 sec.len = header.size;
953296 }
297 }
954298
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);
299 fn trim(sec: *Section, dwarf: *Dwarf) void {
300 const len = sec.getUnit(sec.first.unwrap() orelse return).off;
301 if (len == 0) return;
302 for (sec.units.items) |*unit| unit.off -= len;
303 sec.off += len;
304 sec.len -= len;
305 if (dwarf.bin_file.cast(.elf)) |elf_file| {
306 const shdr = &elf_file.shdrs.items[sec.index];
307 shdr.sh_offset = sec.off;
308 shdr.sh_size = sec.len;
309 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
310 const header = if (macho_file.d_sym) |*d_sym|
311 &d_sym.sections.items[sec.index]
312 else
313 &macho_file.sections.items(.header)[sec.index];
314 header.offset = @intCast(sec.off);
315 header.size = sec.len;
960316 }
961
962 self.dbg_line_func = func;
963317 }
964};
965318
966pub const AbbrevEntry = struct {
967 atom_index: Atom.Index,
968 type: Type,
969 offset: u32,
970};
319 fn resolveRelocs(sec: *Section, dwarf: *Dwarf) RelocError!void {
320 for (sec.units.items) |*unit| try unit.resolveRelocs(sec, dwarf);
321 }
971322
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,
323 fn padToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) {
324 return if (sec.pad_to_ideal) Dwarf.padToIdeal(actual_size) else actual_size;
325 }
979326};
980327
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};
328/// A unit within a `Section` containing a sequence of `Entry`s.
329const Unit = struct {
330 prev: Index.Optional,
331 next: Index.Optional,
332 first: Entry.Index.Optional,
333 last: Entry.Index.Optional,
334 /// offset within containing section
335 off: u32,
336 header_len: u32,
337 trailer_len: u32,
338 /// data length in bytes
339 len: u32,
340 entries: std.ArrayListUnmanaged(Entry),
341 cross_entry_relocs: std.ArrayListUnmanaged(CrossEntryReloc),
342 cross_unit_relocs: std.ArrayListUnmanaged(CrossUnitReloc),
343 cross_section_relocs: std.ArrayListUnmanaged(CrossSectionReloc),
344 external_relocs: std.ArrayListUnmanaged(ExternalReloc),
345
346 const Index = enum(u32) {
347 main,
348 _,
349
350 const Optional = enum(u32) {
351 none = std.math.maxInt(u32),
352 _,
353
354 fn unwrap(uio: Optional) ?Index {
355 return if (uio != .none) @enumFromInt(@intFromEnum(uio)) else null;
356 }
357 };
992358
993pub const PtrWidth = enum { p32, p64 };
359 fn toOptional(ui: Index) Optional {
360 return @enumFromInt(@intFromEnum(ui));
361 }
362 };
994363
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};
364 fn deinit(unit: *Unit, gpa: std.mem.Allocator) void {
365 unit.entries.deinit(gpa);
366 unit.cross_entry_relocs.deinit(gpa);
367 unit.cross_unit_relocs.deinit(gpa);
368 unit.cross_section_relocs.deinit(gpa);
369 unit.external_relocs.deinit(gpa);
370 unit.* = undefined;
371 }
1014372
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;
373 fn addEntry(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!Entry.Index {
374 const entry: Entry.Index = @enumFromInt(unit.entries.items.len);
375 const entry_ptr = try unit.entries.addOne(dwarf.gpa);
376 entry_ptr.* = .{
377 .prev = unit.last,
378 .next = .none,
379 .off = 0,
380 .len = 0,
381 };
382 if (unit.last.unwrap()) |last_entry| {
383 const last_entry_ptr = unit.getEntry(last_entry);
384 last_entry_ptr.next = entry.toOptional();
385 entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);
386 }
387 if (unit.first == .none)
388 unit.first = entry.toOptional();
389 unit.last = entry.toOptional();
390 return entry;
391 }
1021392
1022const min_nop_size = 2;
393 fn getEntry(unit: *Unit, entry: Entry.Index) *Entry {
394 return &unit.entries.items[@intFromEnum(entry)];
395 }
1023396
1024/// When allocating, the ideal_capacity is calculated by
1025/// actual_capacity + (actual_capacity / ideal_factor)
1026const ideal_factor = 3;
397 fn resize(unit_ptr: *Unit, sec: *Section, dwarf: *Dwarf, extra_header_len: u32, len: u32) UpdateError!void {
398 const end = if (unit_ptr.next.unwrap()) |next_unit|
399 sec.getUnit(next_unit).off
400 else
401 sec.len;
402 if (extra_header_len > 0 or unit_ptr.off + len > end) {
403 unit_ptr.len = @min(unit_ptr.len, len);
404 var new_off = unit_ptr.off;
405 if (unit_ptr.next.unwrap()) |next_unit| {
406 const next_unit_ptr = sec.getUnit(next_unit);
407 if (unit_ptr.prev.unwrap()) |prev_unit|
408 sec.getUnit(prev_unit).next = unit_ptr.next
409 else
410 sec.first = unit_ptr.next;
411 const unit = next_unit_ptr.prev;
412 next_unit_ptr.prev = unit_ptr.prev;
413 const last_unit_ptr = sec.getUnit(sec.last.unwrap().?);
414 last_unit_ptr.next = unit;
415 unit_ptr.prev = sec.last;
416 unit_ptr.next = .none;
417 new_off = last_unit_ptr.off + sec.padToIdeal(last_unit_ptr.len);
418 sec.last = unit;
419 sec.dirty = true;
420 } else if (extra_header_len > 0) {
421 // `copyRangeAll` in `move` does not support overlapping ranges
422 // so make sure new location is disjoint from current location.
423 new_off += unit_ptr.len -| extra_header_len;
424 }
425 try sec.resize(dwarf, new_off + len);
426 try unit_ptr.move(sec, dwarf, new_off + extra_header_len);
427 unit_ptr.off -= extra_header_len;
428 unit_ptr.header_len += extra_header_len;
429 sec.trim(dwarf);
430 }
431 unit_ptr.len = len;
432 }
1027433
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}
434 fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {
435 if (unit.off == new_off) return;
436 if (try dwarf.getFile().?.copyRangeAll(
437 sec.off + unit.off,
438 dwarf.getFile().?,
439 sec.off + new_off,
440 unit.len,
441 ) != unit.len) return error.InputOutput;
442 unit.off = new_off;
443 }
1062444
1063pub fn deinit(self: *Dwarf) void {
1064 const gpa = self.allocator;
445 fn resizeHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void {
446 if (unit.header_len == len) return;
447 const available_len = if (unit.prev.unwrap()) |prev_unit| prev_excess: {
448 const prev_unit_ptr = sec.getUnit(prev_unit);
449 break :prev_excess unit.off - prev_unit_ptr.off - prev_unit_ptr.len;
450 } else 0;
451 if (available_len + unit.header_len < len)
452 try unit.resize(sec, dwarf, len - unit.header_len, unit.len - unit.header_len + len);
453 if (unit.header_len > len) {
454 const excess_header_len = unit.header_len - len;
455 unit.off += excess_header_len;
456 unit.header_len -= excess_header_len;
457 unit.len -= excess_header_len;
458 } else if (unit.header_len < len) {
459 const needed_header_len = len - unit.header_len;
460 unit.off -= needed_header_len;
461 unit.header_len += needed_header_len;
462 unit.len += needed_header_len;
463 }
464 assert(unit.header_len == len);
465 sec.trim(dwarf);
466 }
1065467
1066 self.src_fn_free_list.deinit(gpa);
1067 self.src_fns.deinit(gpa);
1068 self.src_fn_navs.deinit(gpa);
468 fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
469 assert(contents.len == unit.header_len);
470 try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off);
471 }
1069472
1070 self.di_atom_free_list.deinit(gpa);
1071 self.di_atoms.deinit(gpa);
1072 self.di_atom_navs.deinit(gpa);
473 fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
474 const start = unit.off + unit.header_len + if (unit.last.unwrap()) |last_entry| end: {
475 const last_entry_ptr = unit.getEntry(last_entry);
476 break :end last_entry_ptr.off + last_entry_ptr.len;
477 } else 0;
478 const end = if (unit.next.unwrap()) |next_unit|
479 sec.getUnit(next_unit).off
480 else
481 sec.len;
482 const trailer_len: usize = @intCast(end - start);
483 assert(trailer_len >= unit.trailer_len);
484 var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, trailer_len);
485 defer trailer.deinit();
486 const fill_byte: u8 = if (sec == &dwarf.debug_aranges.section) fill: {
487 trailer.appendNTimesAssumeCapacity(0, @intFromEnum(dwarf.address_size) * 2);
488 break :fill 0;
489 } else if (sec == &dwarf.debug_info.section) fill: {
490 assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1);
491 trailer.appendNTimesAssumeCapacity(@intFromEnum(AbbrevCode.null), 2);
492 break :fill @intFromEnum(AbbrevCode.null);
493 } else if (sec == &dwarf.debug_line.section) fill: {
494 unit.len -= unit.trailer_len;
495 const extra_len: u32 = @intCast((trailer_len - DebugLine.trailer_bytes) & 1);
496 unit.trailer_len = DebugLine.trailer_bytes + extra_len;
497 unit.len += unit.trailer_len;
498
499 // prevent end sequence from emitting an invalid file index
500 trailer.appendAssumeCapacity(DW.LNS.set_file);
501 uleb128(trailer.fixedWriter(), 0) catch unreachable;
502
503 trailer.appendAssumeCapacity(DW.LNS.extended_op);
504 std.leb.writeUnsignedExtended(trailer.addManyAsSliceAssumeCapacity(uleb128Bytes(1) + extra_len), 1);
505 trailer.appendAssumeCapacity(DW.LNE.end_sequence);
506 break :fill DW.LNS.extended_op;
507 } else if (sec == &dwarf.debug_rnglists.section) fill: {
508 trailer.appendAssumeCapacity(DW.RLE.end_of_list);
509 break :fill DW.RLE.end_of_list;
510 } else unreachable;
511 assert(trailer.items.len == unit.trailer_len);
512 trailer.appendNTimesAssumeCapacity(fill_byte, trailer_len - trailer.items.len);
513 assert(trailer.items.len == trailer_len);
514 try dwarf.getFile().?.pwriteAll(trailer.items, sec.off + start);
515 }
1073516
1074 self.strtab.deinit(gpa);
1075 self.di_files.deinit(gpa);
1076 self.global_abbrev_relocs.deinit(gpa);
1077}
517 fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {
518 for (unit.cross_entry_relocs.items) |reloc| {
519 try dwarf.resolveReloc(
520 sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry|
521 unit.header_len + unit.getEntry(source_entry).off
522 else
523 0) + reloc.source_off,
524 unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off,
525 dwarf.sectionOffsetBytes(),
526 );
527 }
528 for (unit.cross_unit_relocs.items) |reloc| {
529 const target_unit = sec.getUnit(reloc.target_unit);
530 try dwarf.resolveReloc(
531 sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry|
532 unit.header_len + unit.getEntry(source_entry).off
533 else
534 0) + reloc.source_off,
535 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
536 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off
537 else
538 0) + reloc.target_off,
539 dwarf.sectionOffsetBytes(),
540 );
541 }
542 for (unit.cross_section_relocs.items) |reloc| {
543 const target_sec = switch (reloc.target_sec) {
544 inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section,
545 };
546 const target_unit = target_sec.getUnit(reloc.target_unit);
547 try dwarf.resolveReloc(
548 sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry|
549 unit.header_len + unit.getEntry(source_entry).off
550 else
551 0) + reloc.source_off,
552 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
553 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off
554 else
555 0) + reloc.target_off,
556 dwarf.sectionOffsetBytes(),
557 );
558 }
559 if (dwarf.bin_file.cast(.elf)) |elf_file| {
560 const zo = elf_file.zigObjectPtr().?;
561 for (unit.external_relocs.items) |reloc| {
562 const symbol = zo.symbol(reloc.target_sym);
563 try dwarf.resolveReloc(
564 sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off,
565 @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) -
566 if (symbol.flags.is_tls) elf_file.dtpAddress() else 0),
567 @intFromEnum(dwarf.address_size),
568 );
569 }
570 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
571 const zo = macho_file.getZigObject().?;
572 for (unit.external_relocs.items) |reloc| {
573 const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
574 try dwarf.resolveReloc(
575 sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off,
576 ref.getSymbol(macho_file).?.getAddress(.{}, macho_file),
577 @intFromEnum(dwarf.address_size),
578 );
579 }
580 }
581 }
1078582
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();
583 const CrossEntryReloc = struct {
584 source_entry: Entry.Index.Optional = .none,
585 source_off: u32 = 0,
586 target_entry: Entry.Index,
587 target_off: u32 = 0,
588 };
589 const CrossUnitReloc = struct {
590 source_entry: Entry.Index.Optional = .none,
591 source_off: u32 = 0,
592 target_unit: Unit.Index,
593 target_entry: Entry.Index.Optional = .none,
594 target_off: u32 = 0,
595 };
596 const CrossSectionReloc = struct {
597 source_entry: Entry.Index.Optional = .none,
598 source_off: u32 = 0,
599 target_sec: Section.Index,
600 target_unit: Unit.Index,
601 target_entry: Entry.Index.Optional = .none,
602 target_off: u32 = 0,
603 };
604 const ExternalReloc = struct {
605 source_entry: Entry.Index,
606 source_off: u32 = 0,
607 target_sym: u32,
608 target_off: u64 = 0,
609 };
610};
1084611
1085 const nav = pt.zcu.intern_pool.getNav(nav_index);
1086 log.debug("initNavState {}", .{nav.fqn.fmt(&pt.zcu.intern_pool)});
612/// An indivisible entry within a `Unit` containing section-specific data.
613const Entry = struct {
614 prev: Index.Optional,
615 next: Index.Optional,
616 /// offset from end of containing unit header
617 off: u32,
618 /// data length in bytes
619 len: u32,
1087620
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;
621 const Index = enum(u32) {
622 _,
1105623
1106 const di_atom_index = try self.getOrCreateAtomForNav(.di_atom, nav_index);
624 const Optional = enum(u32) {
625 none = std.math.maxInt(u32),
626 _,
1107627
1108 const nav_val = Value.fromInterned(nav.status.resolved.val);
628 fn unwrap(eio: Optional) ?Index {
629 return if (eio != .none) @enumFromInt(@intFromEnum(eio)) else null;
630 }
631 };
1109632
1110 switch (nav_val.typeOf(pt.zcu).zigTypeTag(pt.zcu)) {
1111 .Fn => {
1112 _ = try self.getOrCreateAtomForNav(.src_fn, nav_index);
633 fn toOptional(ei: Index) Optional {
634 return @enumFromInt(@intFromEnum(ei));
635 }
636 };
1113637
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);
638 fn pad(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
639 const start = entry.off + entry.len;
640 const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;
641 if (sec == &dwarf.debug_info.section) {
642 var buf: [
643 @max(
644 uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)),
645 uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) + uleb128Bytes(std.math.maxInt(u32)),
646 )
647 ]u8 = undefined;
648 var fbs = std.io.fixedBufferStream(&buf);
649 switch (len) {
650 0 => {},
651 1 => uleb128(fbs.writer(), @intFromEnum(AbbrevCode.pad_1)) catch unreachable,
652 else => {
653 uleb128(fbs.writer(), @intFromEnum(AbbrevCode.pad_n)) catch unreachable;
654 const abbrev_code_bytes = fbs.pos;
655 var block_len_bytes: u5 = 1;
656 while (true) switch (std.math.order(len - abbrev_code_bytes - block_len_bytes, @as(u32, 1) << 7 * block_len_bytes)) {
657 .lt => break uleb128(fbs.writer(), len - abbrev_code_bytes - block_len_bytes) catch unreachable,
658 .eq => {
659 // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
660 block_len_bytes += 1;
661 std.leb.writeUnsignedExtended(buf[fbs.pos..][0..block_len_bytes], len - abbrev_code_bytes - block_len_bytes);
662 fbs.pos += block_len_bytes;
663 break;
664 },
665 .gt => block_len_bytes += 1,
666 };
667 assert(fbs.pos == abbrev_code_bytes + block_len_bytes);
668 },
669 }
670 assert(fbs.pos <= len);
671 try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start);
672 } else if (sec == &dwarf.debug_line.section) {
673 const buf = try dwarf.gpa.alloc(u8, len);
674 defer dwarf.gpa.free(buf);
675 @memset(buf, DW.LNS.const_add_pc);
676 try dwarf.getFile().?.pwriteAll(buf, sec.off + unit.off + unit.header_len + start);
677 } else assert(!sec.pad_to_ideal and len == 0);
678 }
1117679
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,
680 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
681 const end = if (entry_ptr.next.unwrap()) |next_entry|
682 unit.getEntry(next_entry).off
683 else
684 unit.len -| (unit.header_len + unit.trailer_len);
685 if (entry_ptr.off + contents.len > end) {
686 if (entry_ptr.next.unwrap()) |next_entry| {
687 if (entry_ptr.prev.unwrap()) |prev_entry| {
688 const prev_entry_ptr = unit.getEntry(prev_entry);
689 prev_entry_ptr.next = entry_ptr.next;
690 try prev_entry_ptr.pad(unit, sec, dwarf);
691 } else unit.first = entry_ptr.next;
692 const next_entry_ptr = unit.getEntry(next_entry);
693 const entry = next_entry_ptr.prev;
694 next_entry_ptr.prev = entry_ptr.prev;
695 const last_entry_ptr = unit.getEntry(unit.last.unwrap().?);
696 last_entry_ptr.next = entry;
697 entry_ptr.prev = unit.last;
698 entry_ptr.next = .none;
699 entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);
700 unit.last = entry;
701 }
702 try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padToIdeal(contents.len) + unit.trailer_len));
703 }
704 entry_ptr.len = @intCast(contents.len);
705 {
706 var prev_entry_ptr = entry_ptr;
707 while (prev_entry_ptr.prev.unwrap()) |prev_entry| {
708 prev_entry_ptr = unit.getEntry(prev_entry);
709 if (prev_entry_ptr.len == 0) continue;
710 try prev_entry_ptr.pad(unit, sec, dwarf);
711 break;
712 }
713 }
714 try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off);
715 try entry_ptr.pad(unit, sec, dwarf);
716 if (false) {
717 const buf = try dwarf.gpa.alloc(u8, sec.len);
718 defer dwarf.gpa.free(buf);
719 _ = try dwarf.getFile().?.preadAll(buf, sec.off);
720 log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{
721 @intFromEnum(sec.first),
722 @intFromEnum(sec.last),
723 sec.off,
724 sec.len,
1124725 });
1125 const line: u28 = @intCast(pt.zcu.navSrcLine(nav_index) + func.lbrace_line);
726 for (sec.units.items) |*unit_ptr| {
727 log.info(" Unit{{ .prev = {}, .next = {}, .first = {}, .last = {}, .off = 0x{x}, .header_len = 0x{x}, .trailer_len = 0x{x}, .len = 0x{x} }}", .{
728 @intFromEnum(unit_ptr.prev),
729 @intFromEnum(unit_ptr.next),
730 @intFromEnum(unit_ptr.first),
731 @intFromEnum(unit_ptr.last),
732 unit_ptr.off,
733 unit_ptr.header_len,
734 unit_ptr.trailer_len,
735 unit_ptr.len,
736 });
737 for (unit_ptr.entries.items) |*entry| {
738 log.info(" Entry{{ .prev = {}, .next = {}, .off = 0x{x}, .len = 0x{x} }}", .{
739 @intFromEnum(entry.prev),
740 @intFromEnum(entry.next),
741 entry.off,
742 entry.len,
743 });
744 }
745 }
746 std.debug.dumpHex(buf);
747 }
748 }
1126749
1127 dbg_line_buffer.appendSliceAssumeCapacity(&.{
1128 DW.LNS.extended_op,
1129 ptr_width_bytes + 1,
1130 DW.LNE.set_address,
750 fn assertNonEmpty(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) *Entry {
751 if (entry.len > 0) return entry;
752 if (std.debug.runtime_safety) {
753 log.err("missing {} from {s}", .{
754 @as(Entry.Index, @enumFromInt(entry - unit.entries.items.ptr)),
755 std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file|
756 elf_file.shstrtab.items[elf_file.shdrs.items[sec.index].sh_name..]
757 else if (dwarf.bin_file.cast(.macho)) |macho_file|
758 if (macho_file.d_sym) |*d_sym|
759 &d_sym.sections.items[sec.index].segname
760 else
761 &macho_file.sections.items(.header)[sec.index].segname
762 else
763 "?", 0),
1131764 });
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
765 const zcu = dwarf.bin_file.comp.module.?;
766 const ip = &zcu.intern_pool;
767 for (dwarf.types.keys(), dwarf.types.values()) |ty, other_entry| {
768 const ty_unit: Unit.Index = if (Type.fromInterned(ty).typeDeclInst(zcu)) |inst_index|
769 dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFull(ip).file).mod) catch unreachable
770 else
771 .main;
772 if (sec.getUnit(ty_unit) == unit and unit.getEntry(other_entry) == entry)
773 log.err("missing Type({}({d}))", .{
774 Type.fromInterned(ty).fmt(.{ .tid = .main, .zcu = zcu }),
775 @intFromEnum(ty),
776 });
1178777 }
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 },
778 for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| {
779 const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFull(ip).file).mod) catch unreachable;
780 if (sec.getUnit(nav_unit) == unit and unit.getEntry(other_entry) == entry)
781 log.err("missing Nav({}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) });
782 }
783 }
784 @panic("missing dwarf relocation target");
1189785 }
786};
1190787
1191 return nav_state;
1192}
788pub const Loc = union(enum) {
789 empty,
790 addr: union(enum) { sym: u32 },
791 constu: u64,
792 consts: i64,
793 plus: Bin,
794 reg: u32,
795 breg: u32,
796 push_object_address,
797 form_tls_address: *const Loc,
798 implicit_value: []const u8,
799 stack_value: *const Loc,
800 wasm_ext: union(enum) {
801 local: u32,
802 global: u32,
803 operand_stack: u32,
804 },
1193805
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();
806 pub const Bin = struct { *const Loc, *const Loc };
1211807
1212 var dbg_line_buffer = &nav_state.dbg_line;
1213 var dbg_info_buffer = &nav_state.dbg_info;
808 fn getConst(loc: Loc, comptime Int: type) ?Int {
809 return switch (loc) {
810 .constu => |constu| std.math.cast(Int, constu),
811 .consts => |consts| std.math.cast(Int, consts),
812 else => null,
813 };
814 }
1214815
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());
816 fn getBaseReg(loc: Loc) ?u32 {
817 return switch (loc) {
818 .breg => |breg| breg,
819 else => null,
820 };
821 }
1219822
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 }
823 fn writeReg(reg: u32, op0: u8, opx: u8, writer: anytype) @TypeOf(writer).Error!void {
824 if (std.math.cast(u5, reg)) |small_reg| {
825 try writer.writeByte(op0 + small_reg);
826 } else {
827 try writer.writeByte(opx);
828 try uleb128(writer, reg);
829 }
830 }
1252831
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);
832 fn write(loc: Loc, wip: anytype) UpdateError!void {
833 const writer = wip.infoWriter();
834 switch (loc) {
835 .empty => unreachable,
836 .addr => |addr| {
837 try writer.writeByte(DW.OP.addr);
838 switch (addr) {
839 .sym => |sym_index| try wip.addrSym(sym_index),
1315840 }
841 },
842 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
843 try writer.writeByte(@as(u8, DW.OP.lit0) + lit);
844 } else if (std.math.cast(u8, constu)) |const1u| {
845 try writer.writeAll(&.{ DW.OP.const1u, const1u });
846 } else if (std.math.cast(u16, constu)) |const2u| {
847 try writer.writeByte(DW.OP.const2u);
848 try writer.writeInt(u16, const2u, wip.dwarf.endian);
849 } else if (std.math.cast(u21, constu)) |const3u| {
850 try writer.writeByte(DW.OP.constu);
851 try uleb128(writer, const3u);
852 } else if (std.math.cast(u32, constu)) |const4u| {
853 try writer.writeByte(DW.OP.const4u);
854 try writer.writeInt(u32, const4u, wip.dwarf.endian);
855 } else if (std.math.cast(u49, constu)) |const7u| {
856 try writer.writeByte(DW.OP.constu);
857 try uleb128(writer, const7u);
1316858 } 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 );
859 try writer.writeByte(DW.OP.const8u);
860 try writer.writeInt(u64, constu, wip.dwarf.endian);
861 },
862 .consts => |consts| if (std.math.cast(i8, consts)) |const1s| {
863 try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) });
864 } else if (std.math.cast(i16, consts)) |const2s| {
865 try writer.writeByte(DW.OP.const2s);
866 try writer.writeInt(i16, const2s, wip.dwarf.endian);
867 } else if (std.math.cast(i21, consts)) |const3s| {
868 try writer.writeByte(DW.OP.consts);
869 try sleb128(writer, const3s);
870 } else if (std.math.cast(i32, consts)) |const4s| {
871 try writer.writeByte(DW.OP.const4s);
872 try writer.writeInt(i32, const4s, wip.dwarf.endian);
873 } else if (std.math.cast(i49, consts)) |const7s| {
874 try writer.writeByte(DW.OP.consts);
875 try sleb128(writer, const7s);
876 } else {
877 try writer.writeByte(DW.OP.const8s);
878 try writer.writeInt(i64, consts, wip.dwarf.endian);
879 },
880 .plus => |plus| done: {
881 if (plus[0].getConst(u0)) |_| {
882 try plus[1].write(wip);
883 break :done;
884 }
885 if (plus[1].getConst(u0)) |_| {
886 try plus[0].write(wip);
887 break :done;
888 }
889 if (plus[0].getBaseReg()) |breg| {
890 if (plus[1].getConst(i65)) |offset| {
891 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
892 try sleb128(writer, offset);
893 break :done;
894 }
895 }
896 if (plus[1].getBaseReg()) |breg| {
897 if (plus[0].getConst(i65)) |offset| {
898 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
899 try sleb128(writer, offset);
900 break :done;
901 }
902 }
903 if (plus[0].getConst(u64)) |uconst| {
904 try plus[1].write(wip);
905 try writer.writeByte(DW.OP.plus_uconst);
906 try uleb128(writer, uconst);
907 break :done;
908 }
909 if (plus[1].getConst(u64)) |uconst| {
910 try plus[0].write(wip);
911 try writer.writeByte(DW.OP.plus_uconst);
912 try uleb128(writer, uconst);
913 break :done;
1376914 }
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);
915 try plus[0].write(wip);
916 try plus[1].write(wip);
917 try writer.writeByte(DW.OP.plus);
918 },
919 .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer),
920 .breg => |breg| {
921 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
922 try sleb128(writer, 0);
923 },
924 .push_object_address => try writer.writeByte(DW.OP.push_object_address),
925 .form_tls_address => |addr| {
926 try addr.write(wip);
927 try writer.writeByte(DW.OP.form_tls_address);
928 },
929 .implicit_value => |value| {
930 try writer.writeByte(DW.OP.implicit_value);
931 try uleb128(writer, value.len);
932 try writer.writeAll(value);
933 },
934 .stack_value => |value| {
935 try value.write(wip);
936 try writer.writeByte(DW.OP.stack_value);
937 },
938 .wasm_ext => |wasm_ext| {
939 try writer.writeByte(DW.OP.WASM_location);
940 switch (wasm_ext) {
941 .local => |local| {
942 try writer.writeByte(DW.OP.WASM_local);
943 try uleb128(writer, local);
944 },
945 .global => |global| if (std.math.cast(u21, global)) |global_u21| {
946 try writer.writeByte(DW.OP.WASM_global);
947 try uleb128(writer, global_u21);
948 } else {
949 try writer.writeByte(DW.OP.WASM_global_u32);
950 try writer.writeInt(u32, global, wip.dwarf.endian);
951 },
952 .operand_stack => |operand_stack| {
953 try writer.writeByte(DW.OP.WASM_operand_stack);
954 try uleb128(writer, operand_stack);
955 },
956 }
957 },
1422958 }
1423959 }
960};
1424961
1425 try self.updateNavDebugInfoAllocation(di_atom_index, @intCast(dbg_info_buffer.items.len));
962pub const WipNav = struct {
963 dwarf: *Dwarf,
964 pt: Zcu.PerThread,
965 unit: Unit.Index,
966 entry: Entry.Index,
967 any_children: bool,
968 func: InternPool.Index,
969 func_high_reloc: u32,
970 debug_info: std.ArrayListUnmanaged(u8),
971 debug_line: std.ArrayListUnmanaged(u8),
972 debug_loclists: std.ArrayListUnmanaged(u8),
973 pending_types: std.ArrayListUnmanaged(InternPool.Index),
974
975 pub fn deinit(wip_nav: *WipNav) void {
976 const gpa = wip_nav.dwarf.gpa;
977 wip_nav.debug_info.deinit(gpa);
978 wip_nav.debug_line.deinit(gpa);
979 wip_nav.debug_loclists.deinit(gpa);
980 wip_nav.pending_types.deinit(gpa);
981 }
1426982
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 }
983 pub fn infoWriter(wip_nav: *WipNav) std.ArrayListUnmanaged(u8).Writer {
984 return wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
1464985 }
1465986
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;
987 pub const VarTag = enum { local_arg, local_var };
988 pub fn genVarDebugInfo(
989 wip_nav: *WipNav,
990 tag: VarTag,
991 name: []const u8,
992 ty: Type,
993 loc: Loc,
994 ) UpdateError!void {
995 wip_nav.any_children = true;
996 assert(wip_nav.func != .none);
997 const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
998 try uleb128(diw, @intFromEnum(switch (tag) {
999 inline else => |ct_tag| @field(AbbrevCode, @tagName(ct_tag)),
1000 }));
1001 try wip_nav.strp(name);
1002 try wip_nav.refType(ty);
1003 try wip_nav.exprloc(loc);
14851004 }
14861005
1487 try self.writeNavDebugInfo(di_atom_index, dbg_info_buffer.items);
1488}
1006 pub fn advancePCAndLine(
1007 wip_nav: *WipNav,
1008 delta_line: i33,
1009 delta_pc: u64,
1010 ) error{OutOfMemory}!void {
1011 const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
14891012
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;
1013 const header = wip_nav.dwarf.debug_line.header;
1014 assert(header.maximum_operations_per_instruction == 1);
1015 const delta_op: u64 = 0;
15581016
1559 atom.off = @intCast(padToIdeal(self.dbgInfoHeaderBytes()));
1560 }
1561}
1017 const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or
1018 delta_line - header.line_base >= header.line_range)
1019 remaining: {
1020 assert(delta_line != 0);
1021 try dlw.writeByte(DW.LNS.advance_line);
1022 try sleb128(dlw, delta_line);
1023 break :remaining 0;
1024 } else delta_line);
15621025
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}
1026 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
1027 header.maximum_operations_per_instruction + delta_op;
1028 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
1029 const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: {
1030 try dlw.writeByte(DW.LNS.advance_pc);
1031 try uleb128(dlw, op_advance);
1032 break :remaining 0;
1033 } else if (op_advance >= max_op_advance) remaining: {
1034 try dlw.writeByte(DW.LNS.const_add_pc);
1035 break :remaining op_advance - max_op_advance;
1036 } else op_advance);
16601037
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,
1038 if (remaining_delta_line == 0 and remaining_op_advance == 0)
1039 try dlw.writeByte(DW.LNS.copy)
1040 else
1041 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +
1042 (header.line_range * remaining_op_advance) + header.opcode_base));
17081043 }
1709}
17101044
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 }
1045 pub fn setColumn(wip_nav: *WipNav, column: u32) error{OutOfMemory}!void {
1046 const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
1047 try dlw.writeByte(DW.LNS.set_column);
1048 try uleb128(dlw, column + 1);
17391049 }
17401050
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);
1051 pub fn setPrologueEnd(wip_nav: *WipNav) error{OutOfMemory}!void {
1052 const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
1053 try dlw.writeByte(DW.LNS.set_prologue_end);
1054 }
17451055
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;
1752 }
1056 pub fn setEpilogueBegin(wip_nav: *WipNav) error{OutOfMemory}!void {
1057 const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
1058 try dlw.writeByte(DW.LNS.set_epilogue_begin);
1059 }
17531060
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;
1759 }
1061 pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void {
1062 const zcu = wip_nav.pt.zcu;
1063 const dwarf = wip_nav.dwarf;
1064 if (wip_nav.func == func) return;
17601065
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;
1066 const new_func_info = zcu.funcInfo(func);
1067 const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav);
1068 const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod);
1069 const dlw = wip_nav.debug_line.writer(dwarf.gpa);
1070 if (dwarf.incremental()) {
1071 const new_nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, new_func_info.owner_nav);
1072 errdefer _ = dwarf.navs.pop();
1073 if (!new_nav_gop.found_existing) new_nav_gop.value_ptr.* = try dwarf.addCommonEntry(new_unit);
1074
1075 try dlw.writeByte(DW.LNS.extended_op);
1076 try uleb128(dlw, 1 + dwarf.sectionOffsetBytes());
1077 try dlw.writeByte(DW.LNE.ZIG_set_decl);
1078 try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{
1079 .source_entry = wip_nav.entry.toOptional(),
1080 .source_off = @intCast(wip_nav.debug_line.items.len),
1081 .target_sec = .debug_info,
1082 .target_unit = new_unit,
1083 .target_entry = new_nav_gop.value_ptr.toOptional(),
1084 });
1085 try dlw.writeByteNTimes(0, dwarf.sectionOffsetBytes());
1086 return;
17651087 }
1766 }
1767}
17681088
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);
1912 } 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);
1089 const old_func_info = zcu.funcInfo(wip_nav.func);
1090 const old_file = zcu.navFileScopeIndex(old_func_info.owner_nav);
1091 if (old_file != new_file) {
1092 const new_file_gop = try dwarf.getUnitFiles(new_unit).getOrPut(dwarf.gpa, new_file);
1093 try dlw.writeByte(DW.LNS.set_file);
1094 try uleb128(dlw, new_file_gop.index);
19191095 }
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}
19271096
1928fn dbgInfoHeaderBytes(self: *Dwarf) usize {
1929 _ = self;
1930 return 120;
1931}
1932
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;
1937
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();
1097 const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav);
1098 const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav);
1099 if (new_src_line != old_src_line) {
1100 try dlw.writeByte(DW.LNS.advance_line);
1101 try sleb128(dlw, new_src_line - old_src_line);
1102 }
19431103
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 };
1104 wip_nav.func = func;
1105 }
19511106
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);
1107 fn infoSectionOffset(wip_nav: *WipNav, sec: Section.Index, unit: Unit.Index, entry: Entry.Index, off: u32) UpdateError!void {
1108 const dwarf = wip_nav.dwarf;
1109 const gpa = dwarf.gpa;
1110 if (sec != .debug_info) {
1111 try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_section_relocs.append(gpa, .{
1112 .source_entry = wip_nav.entry.toOptional(),
1113 .source_off = @intCast(wip_nav.debug_info.items.len),
1114 .target_sec = sec,
1115 .target_unit = unit,
1116 .target_entry = entry.toOptional(),
1117 .target_off = off,
1118 });
1119 } else if (unit != wip_nav.unit) {
1120 try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_unit_relocs.append(gpa, .{
1121 .source_entry = wip_nav.entry.toOptional(),
1122 .source_off = @intCast(wip_nav.debug_info.items.len),
1123 .target_unit = unit,
1124 .target_entry = entry.toOptional(),
1125 .target_off = off,
1126 });
20021127 } 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);
1128 try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.append(gpa, .{
1129 .source_entry = wip_nav.entry.toOptional(),
1130 .source_off = @intCast(wip_nav.debug_info.items.len),
1131 .target_entry = entry,
1132 .target_off = off,
1133 });
20071134 }
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}
2014
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}
2033
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),
1135 try wip_nav.debug_info.appendNTimes(gpa, 0, dwarf.sectionOffsetBytes());
20411136 }
2042}
20431137
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),
1138 fn strp(wip_nav: *WipNav, str: []const u8) UpdateError!void {
1139 try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0);
20511140 }
2052}
20531141
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;
2097 }
1142 fn addrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void {
1143 const dwarf = wip_nav.dwarf;
1144 try dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{
1145 .source_entry = wip_nav.entry,
1146 .source_off = @intCast(wip_nav.debug_info.items.len),
1147 .target_sym = sym_index,
1148 });
1149 try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, @intFromEnum(dwarf.address_size));
20981150 }
20991151
2100 vecs[vec_index] = .{
2101 .base = buf.ptr,
2102 .len = buf.len,
2103 };
2104 if (buf.len > 0) vec_index += 1;
2105
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;
2123 }
2124 if (padding_left > 0) {
2125 vecs[vec_index] = .{
2126 .base = &page_of_nops,
2127 .len = padding_left,
2128 };
2129 vec_index += 1;
2130 }
1152 fn exprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
1153 if (loc == .empty) return;
1154 var wip: struct {
1155 const Info = std.io.CountingWriter(std.io.NullWriter);
1156 dwarf: *Dwarf,
1157 debug_info: Info,
1158 fn infoWriter(wip: *@This()) Info.Writer {
1159 return wip.debug_info.writer();
1160 }
1161 fn addrSym(wip: *@This(), _: u32) error{}!void {
1162 wip.debug_info.bytes_written += @intFromEnum(wip.dwarf.address_size);
1163 }
1164 } = .{
1165 .dwarf = wip_nav.dwarf,
1166 .debug_info = std.io.countingWriter(std.io.null_writer),
1167 };
1168 try loc.write(&wip);
1169 try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), wip.debug_info.bytes_written);
1170 try loc.write(wip_nav);
21311171 }
2132 try file.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
2133}
2134
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 }
21531172
2154 while (padding_left > 0) : (padding_left -= 1) {
2155 buf[offset - padding_left] = DW.LNS.negate_stmt;
2156 }
1173 fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } {
1174 const zcu = wip_nav.pt.zcu;
1175 const ip = &zcu.intern_pool;
1176 const maybe_inst_index = ty.typeDeclInst(zcu);
1177 const unit = if (maybe_inst_index) |inst_index|
1178 try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFull(ip).file).mod)
1179 else
1180 .main;
1181 const gop = try wip_nav.dwarf.types.getOrPut(wip_nav.dwarf.gpa, ty.toIntern());
1182 if (gop.found_existing) return .{ unit, gop.value_ptr.* };
1183 const entry = try wip_nav.dwarf.addCommonEntry(unit);
1184 gop.value_ptr.* = entry;
1185 if (maybe_inst_index == null) try wip_nav.pending_types.append(wip_nav.dwarf.gpa, ty.toIntern());
1186 return .{ unit, entry };
21571187 }
21581188
2159 @memcpy(buf[offset..][0..content.len], content);
2160
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 }
2167
2168 while (padding_left > 0) : (padding_left -= 1) {
2169 buf[offset + content.len + padding_left] = DW.LNS.negate_stmt;
2170 }
1189 fn refType(wip_nav: *WipNav, ty: Type) UpdateError!void {
1190 const unit, const entry = try wip_nav.getTypeEntry(ty);
1191 try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
21711192 }
2172}
21731193
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 }
1194 fn refForward(wip_nav: *WipNav) std.mem.Allocator.Error!u32 {
1195 const dwarf = wip_nav.dwarf;
1196 const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs;
1197 const reloc_index: u32 = @intCast(cross_entry_relocs.items.len);
1198 try cross_entry_relocs.append(dwarf.gpa, .{
1199 .source_entry = wip_nav.entry.toOptional(),
1200 .source_off = @intCast(wip_nav.debug_info.items.len),
1201 .target_entry = undefined,
1202 .target_off = undefined,
1203 });
1204 try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, dwarf.sectionOffsetBytes());
1205 return reloc_index;
22071206 }
22081207
2209 vecs[vec_index] = .{
2210 .base = buf.ptr,
2211 .len = buf.len,
2212 };
2213 if (buf.len > 0) vec_index += 1;
2214
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 }
1208 fn finishForward(wip_nav: *WipNav, reloc_index: u32) void {
1209 const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.items[reloc_index];
1210 reloc.target_entry = wip_nav.entry;
1211 reloc.target_off = @intCast(wip_nav.debug_info.items.len);
22321212 }
22331213
2234 if (trailing_zero) {
2235 var zbuf = [1]u8{0};
2236 vecs[vec_index] = .{
2237 .base = &zbuf,
2238 .len = zbuf.len,
1214 fn enumConstValue(
1215 wip_nav: *WipNav,
1216 loaded_enum: InternPool.LoadedEnumType,
1217 abbrev_code: std.enums.EnumFieldStruct(std.builtin.Signedness, AbbrevCode, null),
1218 field_index: usize,
1219 ) std.mem.Allocator.Error!void {
1220 const zcu = wip_nav.pt.zcu;
1221 const ip = &zcu.intern_pool;
1222 const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
1223 const signedness = switch (loaded_enum.tag_ty) {
1224 .comptime_int_type => .signed,
1225 else => Type.fromInterned(loaded_enum.tag_ty).intInfo(zcu).signedness,
22391226 };
2240 vec_index += 1;
1227 try uleb128(diw, @intFromEnum(switch (signedness) {
1228 inline .signed, .unsigned => |ct_signedness| @field(abbrev_code, @tagName(ct_signedness)),
1229 }));
1230 if (loaded_enum.values.len > 0) switch (ip.indexToKey(loaded_enum.values.get(ip)[field_index]).int.storage) {
1231 .u64 => |value| switch (signedness) {
1232 .signed => try sleb128(diw, value),
1233 .unsigned => try uleb128(diw, value),
1234 },
1235 .i64 => |value| switch (signedness) {
1236 .signed => try sleb128(diw, value),
1237 .unsigned => unreachable,
1238 },
1239 .big_int => |big_int| {
1240 const bits = big_int.bitCountTwosCompForSignedness(signedness);
1241 try wip_nav.debug_info.ensureUnusedCapacity(wip_nav.dwarf.gpa, std.math.divCeil(usize, bits, 7) catch unreachable);
1242 var bit: usize = 0;
1243 var carry: u1 = 1;
1244 while (bit < bits) : (bit += 7) {
1245 const limb_bits = @typeInfo(std.math.big.Limb).Int.bits;
1246 const limb_index = bit / limb_bits;
1247 const limb_shift: std.math.Log2Int(std.math.big.Limb) = @intCast(bit % limb_bits);
1248 const low_abs_part: u7 = @truncate(big_int.limbs[limb_index] >> limb_shift);
1249 const abs_part = if (limb_shift > limb_bits - 7) abs_part: {
1250 const next_limb: std.math.big.Limb = if (limb_index + 1 < big_int.limbs.len)
1251 big_int.limbs[limb_index + 1]
1252 else if (big_int.positive) 0 else std.math.maxInt(std.math.big.Limb);
1253 const high_abs_part: u7 = @truncate(next_limb << -%limb_shift);
1254 break :abs_part high_abs_part | low_abs_part;
1255 } else low_abs_part;
1256 const twos_comp_part = if (big_int.positive) abs_part else twos_comp_part: {
1257 const twos_comp_part, carry = @addWithOverflow(~abs_part, carry);
1258 break :twos_comp_part twos_comp_part;
1259 };
1260 wip_nav.debug_info.appendAssumeCapacity(@as(u8, if (bit + 7 < bits) 0x80 else 0x00) | twos_comp_part);
1261 }
1262 },
1263 .lazy_align, .lazy_size => unreachable,
1264 } else switch (signedness) {
1265 .signed => try sleb128(diw, field_index),
1266 .unsigned => try uleb128(diw, field_index),
1267 }
22411268 }
22421269
2243 try file.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
2244}
2245
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;
1270 fn flush(wip_nav: *WipNav) UpdateError!void {
1271 while (wip_nav.pending_types.popOrNull()) |ty| try wip_nav.dwarf.updateType(wip_nav.pt, ty, &wip_nav.pending_types);
22651272 }
2266}
1273};
22671274
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;
1275/// When allocating, the ideal_capacity is calculated by
1276/// actual_capacity + (actual_capacity / ideal_factor)
1277const ideal_factor = 3;
1278
1279fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
1280 return actual_size +| (actual_size / ideal_factor);
23421281}
23431282
2344pub fn writeDbgLineHeader(self: *Dwarf) !void {
2345 const comp = self.bin_file.comp;
2346 const gpa = self.allocator;
1283pub fn init(lf: *link.File, format: DW.Format) Dwarf {
1284 const comp = lf.comp;
1285 const gpa = comp.gpa;
23471286 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,
1287 return .{
1288 .gpa = gpa,
1289 .bin_file = lf,
1290 .format = format,
1291 .address_size = switch (target.ptrBitWidth()) {
1292 0...32 => .@"32",
1293 33...64 => .@"64",
1294 else => unreachable,
1295 },
1296 .endian = target.cpu.arch.endian(),
1297
1298 .mods = .{},
1299 .types = .{},
1300 .navs = .{},
1301
1302 .debug_abbrev = .{ .section = Section.init },
1303 .debug_aranges = .{ .section = Section.init },
1304 .debug_info = .{ .section = Section.init },
1305 .debug_line = .{
1306 .header = switch (target.cpu.arch) {
1307 .x86_64, .aarch64 => .{
1308 .minimum_instruction_length = 1,
1309 .maximum_operations_per_instruction = 1,
1310 .default_is_stmt = true,
1311 .line_base = -5,
1312 .line_range = 14,
1313 .opcode_base = DW.LNS.set_isa + 1,
1314 },
1315 else => .{
1316 .minimum_instruction_length = 1,
1317 .maximum_operations_per_instruction = 1,
1318 .default_is_stmt = true,
1319 .line_base = 0,
1320 .line_range = 1,
1321 .opcode_base = DW.LNS.set_isa + 1,
1322 },
1323 },
1324 .section = Section.init,
1325 },
1326 .debug_line_str = StringSection.init,
1327 .debug_loclists = .{ .section = Section.init },
1328 .debug_rnglists = .{ .section = Section.init },
1329 .debug_str = StringSection.init,
23521330 };
1331}
23531332
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
2430
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),
1333pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
1334 if (dwarf.bin_file.cast(.elf)) |elf_file| {
1335 for ([_]*Section{
1336 &dwarf.debug_abbrev.section,
1337 &dwarf.debug_aranges.section,
1338 &dwarf.debug_info.section,
1339 &dwarf.debug_line.section,
1340 &dwarf.debug_line_str.section,
1341 &dwarf.debug_loclists.section,
1342 &dwarf.debug_rnglists.section,
1343 &dwarf.debug_str.section,
1344 }, [_]u32{
1345 elf_file.debug_abbrev_section_index.?,
1346 elf_file.debug_aranges_section_index.?,
1347 elf_file.debug_info_section_index.?,
1348 elf_file.debug_line_section_index.?,
1349 elf_file.debug_line_str_section_index.?,
1350 elf_file.debug_loclists_section_index.?,
1351 elf_file.debug_rnglists_section_index.?,
1352 elf_file.debug_str_section_index.?,
1353 }) |sec, section_index| {
1354 const shdr = &elf_file.shdrs.items[section_index];
1355 sec.index = section_index;
1356 sec.off = shdr.sh_offset;
1357 sec.len = shdr.sh_size;
1358 }
1359 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
1360 if (macho_file.d_sym) |*d_sym| {
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 }, [_]u8{
1371 d_sym.debug_abbrev_section_index.?,
1372 d_sym.debug_aranges_section_index.?,
1373 d_sym.debug_info_section_index.?,
1374 d_sym.debug_line_section_index.?,
1375 d_sym.debug_line_str_section_index.?,
1376 d_sym.debug_loclists_section_index.?,
1377 d_sym.debug_rnglists_section_index.?,
1378 d_sym.debug_str_section_index.?,
1379 }) |sec, sect_index| {
1380 const header = &d_sym.sections.items[sect_index];
1381 sec.index = sect_index;
1382 sec.off = header.offset;
1383 sec.len = header.size;
1384 }
1385 } else {
1386 for ([_]*Section{
1387 &dwarf.debug_abbrev.section,
1388 &dwarf.debug_aranges.section,
1389 &dwarf.debug_info.section,
1390 &dwarf.debug_line.section,
1391 &dwarf.debug_line_str.section,
1392 &dwarf.debug_loclists.section,
1393 &dwarf.debug_rnglists.section,
1394 &dwarf.debug_str.section,
1395 }, [_]u8{
1396 macho_file.debug_abbrev_sect_index.?,
1397 macho_file.debug_aranges_sect_index.?,
1398 macho_file.debug_info_sect_index.?,
1399 macho_file.debug_line_sect_index.?,
1400 macho_file.debug_line_str_sect_index.?,
1401 macho_file.debug_loclists_sect_index.?,
1402 macho_file.debug_rnglists_sect_index.?,
1403 macho_file.debug_str_sect_index.?,
1404 }) |sec, sect_index| {
1405 const header = &macho_file.sections.items(.header)[sect_index];
1406 sec.index = sect_index;
1407 sec.off = header.offset;
1408 sec.len = header.size;
1409 }
1410 }
24351411 }
1412}
24361413
2437 assert(needed_bytes == di_buf.items.len);
2438
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;
1414pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
1415 dwarf.reloadSectionMetadata();
24421416
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);
1417 dwarf.debug_abbrev.section.pad_to_ideal = false;
1418 assert(try dwarf.debug_abbrev.section.addUnit(0, 0, dwarf) == DebugAbbrev.unit);
1419 errdefer dwarf.debug_abbrev.section.popUnit();
1420 assert(try dwarf.debug_abbrev.section.addEntry(DebugAbbrev.unit, dwarf) == DebugAbbrev.entry);
24471421
2448 var src_fn_index = first_fn_index;
1422 dwarf.debug_aranges.section.pad_to_ideal = false;
1423 dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size) * 2);
24491424
2450 const buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - first_fn.off);
2451 defer gpa.free(buffer);
1425 dwarf.debug_line_str.section.pad_to_ideal = false;
1426 assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
1427 errdefer dwarf.debug_line_str.section.popUnit();
24521428
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;
1429 dwarf.debug_str.section.pad_to_ideal = false;
1430 assert(try dwarf.debug_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
1431 errdefer dwarf.debug_str.section.popUnit();
24581432
2459 const amt = try elf_file.base.file.?.preadAll(buffer, file_pos);
2460 if (amt != buffer.len) return error.InputOutput;
1433 dwarf.debug_loclists.section.pad_to_ideal = false;
24611434
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;
1435 dwarf.debug_rnglists.section.pad_to_ideal = false;
1436}
24691437
2470 const amt = try macho_file.base.file.?.preadAll(buffer, file_pos);
2471 if (amt != buffer.len) return error.InputOutput;
1438pub fn deinit(dwarf: *Dwarf) void {
1439 const gpa = dwarf.gpa;
1440 for (dwarf.mods.values()) |*mod_info| mod_info.files.deinit(gpa);
1441 dwarf.mods.deinit(gpa);
1442 dwarf.types.deinit(gpa);
1443 dwarf.navs.deinit(gpa);
1444 dwarf.debug_abbrev.section.deinit(gpa);
1445 dwarf.debug_aranges.section.deinit(gpa);
1446 dwarf.debug_info.section.deinit(gpa);
1447 dwarf.debug_line.section.deinit(gpa);
1448 dwarf.debug_line_str.deinit(gpa);
1449 dwarf.debug_loclists.section.deinit(gpa);
1450 dwarf.debug_rnglists.section.deinit(gpa);
1451 dwarf.debug_str.deinit(gpa);
1452 dwarf.* = undefined;
1453}
24721454
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;
1455fn getUnit(dwarf: *Dwarf, mod: *Module) UpdateError!Unit.Index {
1456 const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod);
1457 const unit: Unit.Index = @enumFromInt(mod_gop.index);
1458 if (!mod_gop.found_existing) {
1459 errdefer _ = dwarf.mods.pop();
1460 mod_gop.value_ptr.* = .{
1461 .files = .{},
1462 };
1463 assert(try dwarf.debug_aranges.section.addUnit(
1464 DebugAranges.headerBytes(dwarf),
1465 DebugAranges.trailerBytes(dwarf),
1466 dwarf,
1467 ) == unit);
1468 errdefer dwarf.debug_aranges.section.popUnit();
1469 assert(try dwarf.debug_info.section.addUnit(
1470 DebugInfo.headerBytes(dwarf),
1471 DebugInfo.trailer_bytes,
1472 dwarf,
1473 ) == unit);
1474 errdefer dwarf.debug_info.section.popUnit();
1475 assert(try dwarf.debug_line.section.addUnit(
1476 DebugLine.headerBytes(dwarf, 25),
1477 DebugLine.trailer_bytes,
1478 dwarf,
1479 ) == unit);
1480 errdefer dwarf.debug_line.section.popUnit();
1481 assert(try dwarf.debug_loclists.section.addUnit(
1482 DebugLocLists.headerBytes(dwarf),
1483 DebugLocLists.trailer_bytes,
1484 dwarf,
1485 ) == unit);
1486 errdefer dwarf.debug_loclists.section.popUnit();
1487 assert(try dwarf.debug_rnglists.section.addUnit(
1488 DebugRngLists.headerBytes(dwarf),
1489 DebugRngLists.trailer_bytes,
1490 dwarf,
1491 ) == unit);
1492 errdefer dwarf.debug_rnglists.section.popUnit();
1493 }
1494 return unit;
1495}
24801496
2481 const amt = try d_sym.file.preadAll(buffer, file_pos);
2482 if (amt != buffer.len) return error.InputOutput;
1497fn getUnitFiles(dwarf: *Dwarf, unit: Unit.Index) *Files {
1498 return &dwarf.mods.values()[@intFromEnum(unit)].files;
1499}
24831500
2484 try d_sym.file.pwriteAll(buffer, file_pos + delta);
2485 }
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;
1501pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, sym_index: u32) UpdateError!?WipNav {
1502 const zcu = pt.zcu;
1503 const ip = &zcu.intern_pool;
24961504
2497 while (true) {
2498 const src_fn = self.getAtomPtr(.src_fn, src_fn_index);
2499 src_fn.off += delta;
1505 const nav = ip.getNav(nav_index);
1506 log.debug("initWipNav({})", .{nav.fqn.fmt(ip)});
1507
1508 const inst_info = nav.srcInst(ip).resolveFull(ip);
1509 const file = zcu.fileByIndex(inst_info.file);
1510
1511 const unit = try dwarf.getUnit(file.mod);
1512 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
1513 errdefer _ = dwarf.navs.pop();
1514 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
1515 const nav_val = zcu.navValue(nav_index);
1516 var wip_nav: WipNav = .{
1517 .dwarf = dwarf,
1518 .pt = pt,
1519 .unit = unit,
1520 .entry = nav_gop.value_ptr.*,
1521 .any_children = false,
1522 .func = .none,
1523 .func_high_reloc = undefined,
1524 .debug_info = .{},
1525 .debug_line = .{},
1526 .debug_loclists = .{},
1527 .pending_types = .{},
1528 };
1529 errdefer wip_nav.deinit();
25001530
2501 if (src_fn.next_index) |next_index| {
2502 src_fn_index = next_index;
2503 } else break;
2504 }
2505 }
2506
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);
1531 switch (ip.indexToKey(nav_val.toIntern())) {
1532 else => {
1533 assert(file.zir_loaded);
1534 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
1535 assert(decl_inst.tag == .declaration);
1536 const tree = try file.getTree(dwarf.gpa);
1537 const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
1538 assert(loc.line == zcu.navSrcLine(nav_index));
1539
1540 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
1541 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index).data;
1542 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
1543 break :parent .{
1544 parent_namespace_ptr.owner_type,
1545 switch (decl_extra.name) {
1546 .@"comptime",
1547 .@"usingnamespace",
1548 .unnamed_test,
1549 .decltest,
1550 => DW.ACCESS.private,
1551 _ => if (decl_extra.name.isNamedTest(file.zir))
1552 DW.ACCESS.private
1553 else if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
1554 DW.ACCESS.public
1555 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
1556 DW.ACCESS.private
1557 else
1558 unreachable,
1559 },
1560 };
1561 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
1562
1563 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1564 try uleb128(diw, @intFromEnum(AbbrevCode.decl_var));
1565 try wip_nav.refType(Type.fromInterned(parent_type));
1566 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1567 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1568 try uleb128(diw, loc.column + 1);
1569 try diw.writeByte(accessibility);
1570 try wip_nav.strp(nav.name.toSlice(ip));
1571 try wip_nav.strp(nav.fqn.toSlice(ip));
1572 const ty = nav_val.typeOf(zcu);
1573 const ty_reloc_index = try wip_nav.refForward();
1574 try wip_nav.exprloc(.{ .addr = .{ .sym = sym_index } });
1575 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
1576 ty.abiAlignment(pt).toByteUnits().?);
1577 const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() });
1578 try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index|
1579 zcu.all_exports.items[export_index..][0..1]
1580 else if (zcu.multi_exports.get(func_unit)) |export_range|
1581 zcu.all_exports.items[export_range.index..][0..export_range.len]
1582 else
1583 &.{}) |@"export"|
1584 {
1585 if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true;
1586 } else false));
1587 wip_nav.finishForward(ty_reloc_index);
1588 try uleb128(diw, @intFromEnum(AbbrevCode.is_const));
1589 try wip_nav.refType(ty);
25121590 },
2513 .dwarf64 => {
2514 mem.writeInt(u64, di_buf.items[4..][0..8], init_len, target_endian);
1591 .variable => |variable| {
1592 assert(file.zir_loaded);
1593 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
1594 assert(decl_inst.tag == .declaration);
1595 const tree = try file.getTree(dwarf.gpa);
1596 const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
1597 assert(loc.line == zcu.navSrcLine(nav_index));
1598
1599 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
1600 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index).data;
1601 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
1602 break :parent .{
1603 parent_namespace_ptr.owner_type,
1604 switch (decl_extra.name) {
1605 .@"comptime",
1606 .@"usingnamespace",
1607 .unnamed_test,
1608 .decltest,
1609 => DW.ACCESS.private,
1610 _ => if (decl_extra.name.isNamedTest(file.zir))
1611 DW.ACCESS.private
1612 else if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
1613 DW.ACCESS.public
1614 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
1615 DW.ACCESS.private
1616 else
1617 unreachable,
1618 },
1619 };
1620 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
1621
1622 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1623 try uleb128(diw, @intFromEnum(AbbrevCode.decl_var));
1624 try wip_nav.refType(Type.fromInterned(parent_type));
1625 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1626 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1627 try uleb128(diw, loc.column + 1);
1628 try diw.writeByte(accessibility);
1629 try wip_nav.strp(nav.name.toSlice(ip));
1630 try wip_nav.strp(nav.fqn.toSlice(ip));
1631 const ty = Type.fromInterned(variable.ty);
1632 try wip_nav.refType(ty);
1633 const addr: Loc = .{ .addr = .{ .sym = sym_index } };
1634 try wip_nav.exprloc(if (variable.is_threadlocal) .{ .form_tls_address = &addr } else addr);
1635 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
1636 ty.abiAlignment(pt).toByteUnits().?);
1637 const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() });
1638 try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index|
1639 zcu.all_exports.items[export_index..][0..1]
1640 else if (zcu.multi_exports.get(func_unit)) |export_range|
1641 zcu.all_exports.items[export_range.index..][0..export_range.len]
1642 else
1643 &.{}) |@"export"|
1644 {
1645 if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true;
1646 } else false));
25151647 },
2516 }
1648 .func => |func| {
1649 assert(file.zir_loaded);
1650 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
1651 assert(decl_inst.tag == .declaration);
1652 const tree = try file.getTree(dwarf.gpa);
1653 const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
1654 assert(loc.line == zcu.navSrcLine(nav_index));
1655
1656 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
1657 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index).data;
1658 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
1659 break :parent .{
1660 parent_namespace_ptr.owner_type,
1661 switch (decl_extra.name) {
1662 .@"comptime",
1663 .@"usingnamespace",
1664 .unnamed_test,
1665 .decltest,
1666 => DW.ACCESS.private,
1667 _ => if (decl_extra.name.isNamedTest(file.zir))
1668 DW.ACCESS.private
1669 else if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
1670 DW.ACCESS.public
1671 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
1672 DW.ACCESS.private
1673 else
1674 unreachable,
1675 },
1676 };
1677 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
1678
1679 const func_type = ip.indexToKey(func.ty).func_type;
1680 wip_nav.func = nav_val.toIntern();
1681
1682 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1683 try uleb128(diw, @intFromEnum(AbbrevCode.decl_func));
1684 try wip_nav.refType(Type.fromInterned(parent_type));
1685 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1686 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1687 try uleb128(diw, loc.column + 1);
1688 try diw.writeByte(accessibility);
1689 try wip_nav.strp(nav.name.toSlice(ip));
1690 try wip_nav.strp(nav.fqn.toSlice(ip));
1691 try wip_nav.refType(Type.fromInterned(func_type.return_type));
1692 const external_relocs = &dwarf.debug_info.section.getUnit(unit).external_relocs;
1693 try external_relocs.append(dwarf.gpa, .{
1694 .source_entry = wip_nav.entry,
1695 .source_off = @intCast(wip_nav.debug_info.items.len),
1696 .target_sym = sym_index,
1697 });
1698 try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
1699 wip_nav.func_high_reloc = @intCast(external_relocs.items.len);
1700 try external_relocs.append(dwarf.gpa, .{
1701 .source_entry = wip_nav.entry,
1702 .source_off = @intCast(wip_nav.debug_info.items.len),
1703 .target_sym = sym_index,
1704 });
1705 try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
1706 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
1707 target_info.defaultFunctionAlignment(file.mod.resolved_target.result).toByteUnits().?);
1708 const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() });
1709 try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index|
1710 zcu.all_exports.items[export_index..][0..1]
1711 else if (zcu.multi_exports.get(func_unit)) |export_range|
1712 zcu.all_exports.items[export_range.index..][0..export_range.len]
1713 else
1714 &.{}) |@"export"|
1715 {
1716 if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true;
1717 } else false));
1718 try diw.writeByte(@intFromBool(func_type.return_type == .noreturn_type));
1719
1720 const dlw = wip_nav.debug_line.writer(dwarf.gpa);
1721 try dlw.writeByte(DW.LNS.extended_op);
1722 if (dwarf.incremental()) {
1723 try uleb128(dlw, 1 + dwarf.sectionOffsetBytes());
1724 try dlw.writeByte(DW.LNE.ZIG_set_decl);
1725 try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{
1726 .source_entry = wip_nav.entry.toOptional(),
1727 .source_off = @intCast(wip_nav.debug_line.items.len),
1728 .target_sec = .debug_info,
1729 .target_unit = wip_nav.unit,
1730 .target_entry = wip_nav.entry.toOptional(),
1731 });
1732 try dlw.writeByteNTimes(0, dwarf.sectionOffsetBytes());
25171733
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}
1734 try dlw.writeByte(DW.LNS.set_column);
1735 try uleb128(dlw, func.lbrace_column + 1);
25411736
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}
1737 try wip_nav.advancePCAndLine(func.lbrace_line, 0);
1738 } else {
1739 try uleb128(dlw, 1 + @intFromEnum(dwarf.address_size));
1740 try dlw.writeByte(DW.LNE.set_address);
1741 try dwarf.debug_line.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{
1742 .source_entry = wip_nav.entry,
1743 .source_off = @intCast(wip_nav.debug_line.items.len),
1744 .target_sym = sym_index,
1745 });
1746 try dlw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
25471747
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}
1748 const file_gop = try dwarf.getUnitFiles(unit).getOrPut(dwarf.gpa, inst_info.file);
1749 try dlw.writeByte(DW.LNS.set_file);
1750 try uleb128(dlw, file_gop.index);
25531751
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}
1752 try dlw.writeByte(DW.LNS.set_column);
1753 try uleb128(dlw, func.lbrace_column + 1);
25591754
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;
1755 try wip_nav.advancePCAndLine(@intCast(loc.line + func.lbrace_line), 0);
1756 }
1757 },
1758 }
1759 return wip_nav;
25641760}
25651761
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 };
2572}
1762pub fn finishWipNav(
1763 dwarf: *Dwarf,
1764 pt: Zcu.PerThread,
1765 nav_index: InternPool.Nav.Index,
1766 sym: struct { index: u32, addr: u64, size: u64 },
1767 wip_nav: *WipNav,
1768) UpdateError!void {
1769 const zcu = pt.zcu;
1770 const ip = &zcu.intern_pool;
1771 const nav = ip.getNav(nav_index);
1772 log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)});
1773
1774 if (wip_nav.func != .none) {
1775 dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size;
1776 if (wip_nav.any_children) {
1777 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1778 try uleb128(diw, @intFromEnum(AbbrevCode.null));
1779 } else std.leb.writeUnsignedFixed(
1780 AbbrevCode.decl_bytes,
1781 wip_nav.debug_info.items[0..AbbrevCode.decl_bytes],
1782 @intFromEnum(AbbrevCode.decl_func_empty),
1783 );
25731784
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
1785 var aranges_entry = [1]u8{0} ** (8 + 8);
1786 try dwarf.debug_aranges.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{
1787 .source_entry = wip_nav.entry,
1788 .target_sym = sym.index,
1789 });
1790 dwarf.writeInt(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0);
1791 dwarf.writeInt(aranges_entry[@intFromEnum(dwarf.address_size)..][0..@intFromEnum(dwarf.address_size)], sym.size);
1792
1793 @memset(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0);
1794 try dwarf.debug_aranges.section.replaceEntry(
1795 wip_nav.unit,
1796 wip_nav.entry,
1797 dwarf,
1798 aranges_entry[0 .. @intFromEnum(dwarf.address_size) * 2],
1799 );
25851800
2586 for (dirs) |dir| { // include dirs
2587 size += dir.len + 1;
1801 try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).external_relocs.appendSlice(dwarf.gpa, &.{
1802 .{
1803 .source_entry = wip_nav.entry,
1804 .source_off = 1,
1805 .target_sym = sym.index,
1806 },
1807 .{
1808 .source_entry = wip_nav.entry,
1809 .source_off = 1 + @intFromEnum(dwarf.address_size),
1810 .target_sym = sym.index,
1811 .target_off = sym.size,
1812 },
1813 });
1814 try dwarf.debug_rnglists.section.replaceEntry(
1815 wip_nav.unit,
1816 wip_nav.entry,
1817 dwarf,
1818 ([1]u8{DW.RLE.start_end} ++ [1]u8{0} ** (8 + 8))[0 .. 1 + @intFromEnum(dwarf.address_size) + @intFromEnum(dwarf.address_size)],
1819 );
25881820 }
2589 size += 1; // include dirs sentinel
25901821
2591 for (files) |file| { // file names
2592 size += file.len + 1 + 1 + 1 + 1;
1822 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
1823 if (wip_nav.debug_line.items.len > 0) {
1824 if (!dwarf.incremental()) {
1825 const dlw = wip_nav.debug_line.writer(dwarf.gpa);
1826 try dlw.writeByte(DW.LNS.extended_op);
1827 try uleb128(dlw, 1);
1828 try dlw.writeByte(DW.LNE.end_sequence);
1829 }
1830 try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.items);
25931831 }
2594 size += 1; // file names sentinel
1832 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items);
25951833
2596 return @intCast(size);
1834 try wip_nav.flush();
25971835}
25981836
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}
1837pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateError!void {
1838 const zcu = pt.zcu;
1839 const ip = &zcu.intern_pool;
1840 const nav_val = zcu.navValue(nav_index);
26041841
2605fn getRelocDbgFileIndex(self: Dwarf) usize {
2606 return self.getRelocDbgLineOff() + 5;
2607}
1842 const nav = ip.getNav(nav_index);
1843 log.debug("updateComptimeNav({})", .{nav.fqn.fmt(ip)});
1844
1845 const inst_info = nav.srcInst(ip).resolveFull(ip);
1846 const file = zcu.fileByIndex(inst_info.file);
1847 assert(file.zir_loaded);
1848 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
1849 assert(decl_inst.tag == .declaration);
1850 const tree = try file.getTree(dwarf.gpa);
1851 const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
1852 assert(loc.line == zcu.navSrcLine(nav_index));
1853
1854 const unit = try dwarf.getUnit(file.mod);
1855 var wip_nav: WipNav = .{
1856 .dwarf = dwarf,
1857 .pt = pt,
1858 .unit = unit,
1859 .entry = undefined,
1860 .any_children = false,
1861 .func = .none,
1862 .func_high_reloc = undefined,
1863 .debug_info = .{},
1864 .debug_line = .{},
1865 .debug_loclists = .{},
1866 .pending_types = .{},
1867 };
1868 defer wip_nav.deinit();
1869
1870 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
1871 errdefer _ = dwarf.navs.pop();
1872 switch (ip.indexToKey(nav_val.toIntern())) {
1873 .struct_type => done: {
1874 const loaded_struct = ip.loadStructType(nav_val.toIntern());
1875
1876 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
1877 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
1878 break :parent .{
1879 parent_namespace_ptr.owner_type,
1880 if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
1881 DW.ACCESS.public
1882 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
1883 DW.ACCESS.private
1884 else
1885 unreachable,
1886 };
1887 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
1888
1889 decl_struct: {
1890 if (loaded_struct.zir_index == .none) break :decl_struct;
1891
1892 const value_inst = value_inst: {
1893 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index);
1894 const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
1895 const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
1896 if (break_inst.tag != .break_inline) break :value_inst null;
1897 assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
1898 var value_inst = break_inst.data.@"break".operand.toIndex();
1899 while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
1900 else => break,
1901 .as_node => value_inst = file.zir.extraData(
1902 Zir.Inst.As,
1903 file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
1904 ).data.operand.toIndex(),
1905 };
1906 break :value_inst value_inst;
1907 };
1908 const type_inst_info = loaded_struct.zir_index.unwrap().?.resolveFull(ip);
1909 if (type_inst_info.inst != value_inst) break :decl_struct;
26081910
2609fn getRelocDbgInfoSubprogramHighPC(self: Dwarf) u32 {
2610 return dbg_info_low_pc_reloc_index + self.ptrWidthBytes();
2611}
1911 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
1912 if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
1913 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
1914 type_gop.value_ptr.* = nav_gop.value_ptr.*;
1915 }
1916 wip_nav.entry = nav_gop.value_ptr.*;
1917 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1918
1919 switch (loaded_struct.layout) {
1920 .auto, .@"extern" => {
1921 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0)
1922 .decl_namespace_struct
1923 else
1924 .decl_struct)));
1925 try wip_nav.refType(Type.fromInterned(parent_type));
1926 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1927 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1928 try uleb128(diw, loc.column + 1);
1929 try diw.writeByte(accessibility);
1930 try wip_nav.strp(nav.name.toSlice(ip));
1931 if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
1932 try uleb128(diw, nav_val.toType().abiSize(pt));
1933 try uleb128(diw, nav_val.toType().abiAlignment(pt).toByteUnits().?);
1934 for (0..loaded_struct.field_types.len) |field_index| {
1935 const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
1936 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
1937 if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
1938 const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
1939 defer dwarf.gpa.free(field_name);
1940 try wip_nav.strp(field_name);
1941 }
1942 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1943 try wip_nav.refType(field_type);
1944 if (!is_comptime) {
1945 try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
1946 try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
1947 field_type.abiAlignment(pt).toByteUnits().?);
1948 }
1949 }
1950 try uleb128(diw, @intFromEnum(AbbrevCode.null));
1951 }
1952 },
1953 .@"packed" => {
1954 try uleb128(diw, @intFromEnum(AbbrevCode.decl_packed_struct));
1955 try wip_nav.refType(Type.fromInterned(parent_type));
1956 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1957 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1958 try uleb128(diw, loc.column + 1);
1959 try diw.writeByte(accessibility);
1960 try wip_nav.strp(nav.name.toSlice(ip));
1961 try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
1962 var field_bit_offset: u16 = 0;
1963 for (0..loaded_struct.field_types.len) |field_index| {
1964 try uleb128(diw, @intFromEnum(@as(AbbrevCode, .packed_struct_field)));
1965 try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip));
1966 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1967 try wip_nav.refType(field_type);
1968 try uleb128(diw, field_bit_offset);
1969 field_bit_offset += @intCast(field_type.bitSize(pt));
1970 }
1971 try uleb128(diw, @intFromEnum(AbbrevCode.null));
1972 },
1973 }
1974 break :done;
1975 }
26121976
2613fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
2614 return actual_size +| (actual_size / ideal_factor);
2615}
1977 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
1978 wip_nav.entry = nav_gop.value_ptr.*;
1979 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1980 try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
1981 try wip_nav.refType(Type.fromInterned(parent_type));
1982 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1983 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1984 try uleb128(diw, loc.column + 1);
1985 try diw.writeByte(accessibility);
1986 try wip_nav.strp(nav.name.toSlice(ip));
1987 try wip_nav.refType(nav_val.toType());
1988 },
1989 .enum_type => done: {
1990 const loaded_enum = ip.loadEnumType(nav_val.toIntern());
1991
1992 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
1993 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
1994 break :parent .{
1995 parent_namespace_ptr.owner_type,
1996 if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
1997 DW.ACCESS.public
1998 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
1999 DW.ACCESS.private
2000 else
2001 unreachable,
2002 };
2003 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
2004
2005 decl_enum: {
2006 if (loaded_enum.zir_index == .none) break :decl_enum;
2007
2008 const value_inst = value_inst: {
2009 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index);
2010 const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
2011 const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
2012 if (break_inst.tag != .break_inline) break :value_inst null;
2013 assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
2014 var value_inst = break_inst.data.@"break".operand.toIndex();
2015 while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
2016 else => break,
2017 .as_node => value_inst = file.zir.extraData(
2018 Zir.Inst.As,
2019 file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
2020 ).data.operand.toIndex(),
2021 };
2022 break :value_inst value_inst;
2023 };
2024 const type_inst_info = loaded_enum.zir_index.unwrap().?.resolveFull(ip);
2025 if (type_inst_info.inst != value_inst) break :decl_enum;
26162026
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;
2027 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
2028 if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
2029 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2030 type_gop.value_ptr.* = nav_gop.value_ptr.*;
2031 }
2032 wip_nav.entry = nav_gop.value_ptr.*;
2033 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2034 try uleb128(diw, @intFromEnum(AbbrevCode.decl_enum));
2035 try wip_nav.refType(Type.fromInterned(parent_type));
2036 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2037 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2038 try uleb128(diw, loc.column + 1);
2039 try diw.writeByte(accessibility);
2040 try wip_nav.strp(nav.name.toSlice(ip));
2041 try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
2042 for (0..loaded_enum.names.len) |field_index| {
2043 try wip_nav.enumConstValue(loaded_enum, .{
2044 .signed = .signed_enum_field,
2045 .unsigned = .unsigned_enum_field,
2046 }, field_index);
2047 try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
2048 }
2049 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2050 break :done;
2051 }
26202052
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 );
2053 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2054 wip_nav.entry = nav_gop.value_ptr.*;
2055 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2056 try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
2057 try wip_nav.refType(Type.fromInterned(parent_type));
2058 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2059 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2060 try uleb128(diw, loc.column + 1);
2061 try diw.writeByte(accessibility);
2062 try wip_nav.strp(nav.name.toSlice(ip));
2063 try wip_nav.refType(nav_val.toType());
2064 },
2065 .union_type => done: {
2066 const loaded_union = ip.loadUnionType(nav_val.toIntern());
2067
2068 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2069 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2070 break :parent .{
2071 parent_namespace_ptr.owner_type,
2072 if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
2073 DW.ACCESS.public
2074 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
2075 DW.ACCESS.private
2076 else
2077 unreachable,
2078 };
2079 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
2080
2081 decl_union: {
2082 const value_inst = value_inst: {
2083 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index);
2084 const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
2085 const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
2086 if (break_inst.tag != .break_inline) break :value_inst null;
2087 assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
2088 var value_inst = break_inst.data.@"break".operand.toIndex();
2089 while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
2090 else => break,
2091 .as_node => value_inst = file.zir.extraData(
2092 Zir.Inst.As,
2093 file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
2094 ).data.operand.toIndex(),
2095 };
2096 break :value_inst value_inst;
2097 };
2098 const type_inst_info = loaded_union.zir_index.resolveFull(ip);
2099 if (type_inst_info.inst != value_inst) break :decl_union;
26352100
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;
2101 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
2102 if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
2103 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2104 type_gop.value_ptr.* = nav_gop.value_ptr.*;
2105 }
2106 wip_nav.entry = nav_gop.value_ptr.*;
2107 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2108 try uleb128(diw, @intFromEnum(AbbrevCode.decl_union));
2109 try wip_nav.refType(Type.fromInterned(parent_type));
2110 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2111 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2112 try uleb128(diw, loc.column + 1);
2113 try diw.writeByte(accessibility);
2114 try wip_nav.strp(nav.name.toSlice(ip));
2115 const union_layout = pt.getUnionLayout(loaded_union);
2116 try uleb128(diw, union_layout.abi_size);
2117 try uleb128(diw, union_layout.abi_align.toByteUnits().?);
2118 const loaded_tag = loaded_union.loadTagType(ip);
2119 if (loaded_union.hasTag(ip)) {
2120 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
2121 try wip_nav.infoSectionOffset(
2122 .debug_info,
2123 wip_nav.unit,
2124 wip_nav.entry,
2125 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2126 );
2127 {
2128 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2129 try wip_nav.strp("tag");
2130 try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty));
2131 try uleb128(diw, union_layout.tagOffset());
2132
2133 for (0..loaded_union.field_types.len) |field_index| {
2134 try wip_nav.enumConstValue(loaded_tag, .{
2135 .signed = .signed_tagged_union_field,
2136 .unsigned = .unsigned_tagged_union_field,
2137 }, field_index);
2138 {
2139 try uleb128(diw, @intFromEnum(AbbrevCode.struct_field));
2140 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
2141 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
2142 try wip_nav.refType(field_type);
2143 try uleb128(diw, union_layout.payloadOffset());
2144 try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
2145 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(pt).toByteUnits().?);
2146 }
2147 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2148 }
2149 }
2150 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2151
2152 if (ip.indexToKey(loaded_union.enum_tag_ty).enum_type == .generated_tag)
2153 try wip_nav.pending_types.append(dwarf.gpa, loaded_union.enum_tag_ty);
2154 } else for (0..loaded_union.field_types.len) |field_index| {
2155 try uleb128(diw, @intFromEnum(AbbrevCode.untagged_union_field));
2156 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
2157 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
2158 try wip_nav.refType(field_type);
2159 try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
2160 field_type.abiAlignment(pt).toByteUnits().?);
2161 }
2162 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2163 break :done;
26532164 }
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;
2659
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);
2165
2166 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2167 wip_nav.entry = nav_gop.value_ptr.*;
2168 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2169 try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
2170 try wip_nav.refType(Type.fromInterned(parent_type));
2171 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2172 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2173 try uleb128(diw, loc.column + 1);
2174 try diw.writeByte(accessibility);
2175 try wip_nav.strp(nav.name.toSlice(ip));
2176 try wip_nav.refType(nav_val.toType());
2177 },
2178 .opaque_type => done: {
2179 const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
2180
2181 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2182 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2183 break :parent .{
2184 parent_namespace_ptr.owner_type,
2185 if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
2186 DW.ACCESS.public
2187 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
2188 DW.ACCESS.private
2189 else
2190 unreachable,
2191 };
2192 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
2193
2194 decl_opaque: {
2195 const value_inst = value_inst: {
2196 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index);
2197 const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
2198 const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
2199 if (break_inst.tag != .break_inline) break :value_inst null;
2200 assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
2201 var value_inst = break_inst.data.@"break".operand.toIndex();
2202 while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
2203 else => break,
2204 .as_node => value_inst = file.zir.extraData(
2205 Zir.Inst.As,
2206 file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
2207 ).data.operand.toIndex(),
2208 };
2209 break :value_inst value_inst;
2210 };
2211 const type_inst_info = loaded_opaque.zir_index.resolveFull(ip);
2212 if (type_inst_info.inst != value_inst) break :decl_opaque;
2213
2214 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
2215 if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
2216 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2217 type_gop.value_ptr.* = nav_gop.value_ptr.*;
26732218 }
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;
2679 }
2219 wip_nav.entry = nav_gop.value_ptr.*;
2220 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2221 try uleb128(diw, @intFromEnum(AbbrevCode.decl_namespace_struct));
2222 try wip_nav.refType(Type.fromInterned(parent_type));
2223 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2224 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2225 try uleb128(diw, loc.column + 1);
2226 try diw.writeByte(accessibility);
2227 try wip_nav.strp(nav.name.toSlice(ip));
2228 try diw.writeByte(@intFromBool(false));
2229 break :done;
2230 }
2231
2232 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2233 wip_nav.entry = nav_gop.value_ptr.*;
2234 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2235 try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
2236 try wip_nav.refType(Type.fromInterned(parent_type));
2237 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2238 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2239 try uleb128(diw, loc.column + 1);
2240 try diw.writeByte(accessibility);
2241 try wip_nav.strp(nav.name.toSlice(ip));
2242 try wip_nav.refType(nav_val.toType());
2243 },
2244 else => {
2245 _ = dwarf.navs.pop();
2246 return;
2247 },
26802248 }
2249 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2250 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items);
2251 try wip_nav.flush();
26812252}
26822253
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.?);
2254fn updateType(
2255 dwarf: *Dwarf,
2256 pt: Zcu.PerThread,
2257 type_index: InternPool.Index,
2258 pending_types: *std.ArrayListUnmanaged(InternPool.Index),
2259) UpdateError!void {
2260 const zcu = pt.zcu;
2261 const ip = &zcu.intern_pool;
2262 const ty = Type.fromInterned(type_index);
2263 switch (type_index) {
2264 .generic_poison_type => log.debug("updateType({s})", .{"anytype"}),
2265 else => log.debug("updateType({})", .{ty.fmt(pt)}),
2266 }
2267
2268 var wip_nav: WipNav = .{
2269 .dwarf = dwarf,
2270 .pt = pt,
2271 .unit = .main,
2272 .entry = dwarf.types.get(type_index).?,
2273 .any_children = false,
2274 .func = .none,
2275 .func_high_reloc = undefined,
2276 .debug_info = .{},
2277 .debug_line = .{},
2278 .debug_loclists = .{},
2279 .pending_types = pending_types.*,
2280 };
2281 defer {
2282 pending_types.* = wip_nav.pending_types;
2283 wip_nav.pending_types = .{};
2284 wip_nav.deinit();
2285 }
2286 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2287 const name = switch (type_index) {
2288 .generic_poison_type => "",
2289 else => try std.fmt.allocPrint(dwarf.gpa, "{}", .{ty.fmt(pt)}),
2290 };
2291 defer dwarf.gpa.free(name);
2292
2293 switch (ip.indexToKey(type_index)) {
2294 .int_type => |int_type| {
2295 try uleb128(diw, @intFromEnum(AbbrevCode.numeric_type));
2296 try wip_nav.strp(name);
2297 try diw.writeByte(switch (int_type.signedness) {
2298 inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)),
2299 });
2300 try uleb128(diw, int_type.bits);
2301 try uleb128(diw, ty.abiSize(pt));
2302 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2303 },
2304 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
2305 .One, .Many, .C => {
2306 const ptr_child_type = Type.fromInterned(ptr_type.child);
2307 try uleb128(diw, @intFromEnum(AbbrevCode.ptr_type));
2308 try wip_nav.strp(name);
2309 try diw.writeByte(@intFromBool(ptr_type.flags.is_allowzero));
2310 try uleb128(diw, ptr_type.flags.alignment.toByteUnits() orelse
2311 ptr_child_type.abiAlignment(pt).toByteUnits().?);
2312 try diw.writeByte(@intFromEnum(ptr_type.flags.address_space));
2313 if (ptr_type.flags.is_const or ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
2314 .debug_info,
2315 wip_nav.unit,
2316 wip_nav.entry,
2317 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2318 ) else try wip_nav.refType(ptr_child_type);
2319 if (ptr_type.flags.is_const) {
2320 try uleb128(diw, @intFromEnum(AbbrevCode.is_const));
2321 if (ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
2322 .debug_info,
2323 wip_nav.unit,
2324 wip_nav.entry,
2325 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2326 ) else try wip_nav.refType(ptr_child_type);
2327 }
2328 if (ptr_type.flags.is_volatile) {
2329 try uleb128(diw, @intFromEnum(AbbrevCode.is_volatile));
2330 try wip_nav.refType(ptr_child_type);
2331 }
2332 },
2333 .Slice => {
2334 try uleb128(diw, @intFromEnum(AbbrevCode.struct_type));
2335 try wip_nav.strp(name);
2336 try uleb128(diw, ty.abiSize(pt));
2337 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2338 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2339 try wip_nav.strp("ptr");
2340 const ptr_field_type = ty.slicePtrFieldType(zcu);
2341 try wip_nav.refType(ptr_field_type);
2342 try uleb128(diw, 0);
2343 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2344 try wip_nav.strp("len");
2345 const len_field_type = Type.usize;
2346 try wip_nav.refType(len_field_type);
2347 try uleb128(diw, len_field_type.abiAlignment(pt).forward(ptr_field_type.abiSize(pt)));
2348 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2349 },
2350 },
2351 inline .array_type, .vector_type => |array_type, ty_tag| {
2352 try uleb128(diw, @intFromEnum(AbbrevCode.array_type));
2353 try wip_nav.strp(name);
2354 try wip_nav.refType(Type.fromInterned(array_type.child));
2355 try diw.writeByte(@intFromBool(ty_tag == .vector_type));
2356 try uleb128(diw, @intFromEnum(AbbrevCode.array_index));
2357 try wip_nav.refType(Type.usize);
2358 try uleb128(diw, array_type.len);
2359 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2360 },
2361 .opt_type => |opt_child_type_index| {
2362 const opt_child_type = Type.fromInterned(opt_child_type_index);
2363 try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
2364 try wip_nav.strp(name);
2365 try uleb128(diw, ty.abiSize(pt));
2366 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2367 if (opt_child_type.isNoReturn(zcu)) {
2368 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2369 try wip_nav.strp("null");
2370 try wip_nav.refType(Type.null);
2371 try uleb128(diw, 0);
26922372 } else {
2693 const d_sym = macho_file.getDebugSymbols().?;
2694 d_sym.markDirty(d_sym.debug_line_section_index.?, macho_file);
2373 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
2374 try wip_nav.infoSectionOffset(
2375 .debug_info,
2376 wip_nav.unit,
2377 wip_nav.entry,
2378 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2379 );
2380 {
2381 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2382 try wip_nav.strp("has_value");
2383 const repr: enum { unpacked, error_set, pointer } = switch (opt_child_type_index) {
2384 .anyerror_type => .error_set,
2385 else => switch (ip.indexToKey(opt_child_type_index)) {
2386 else => .unpacked,
2387 .error_set_type, .inferred_error_set_type => .error_set,
2388 .ptr_type => |ptr_type| if (ptr_type.flags.is_allowzero) .unpacked else .pointer,
2389 },
2390 };
2391 switch (repr) {
2392 .unpacked => {
2393 try wip_nav.refType(Type.bool);
2394 try uleb128(diw, if (opt_child_type.hasRuntimeBits(pt))
2395 opt_child_type.abiSize(pt)
2396 else
2397 0);
2398 },
2399 .error_set => {
2400 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
2401 .signedness = .unsigned,
2402 .bits = pt.zcu.errorSetBits(),
2403 } })));
2404 try uleb128(diw, 0);
2405 },
2406 .pointer => {
2407 try wip_nav.refType(Type.usize);
2408 try uleb128(diw, 0);
2409 },
2410 }
2411
2412 try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_tagged_union_field));
2413 try uleb128(diw, 0);
2414 {
2415 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2416 try wip_nav.strp("null");
2417 try wip_nav.refType(Type.null);
2418 try uleb128(diw, 0);
2419 }
2420 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2421
2422 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union_default_field));
2423 {
2424 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2425 try wip_nav.strp("?");
2426 try wip_nav.refType(opt_child_type);
2427 try uleb128(diw, 0);
2428 }
2429 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2430 }
2431 try uleb128(diw, @intFromEnum(AbbrevCode.null));
26952432 }
2696 } else if (self.bin_file.cast(.wasm)) |_| {} else unreachable;
2433 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2434 },
2435 .anyframe_type => unreachable,
2436 .error_union_type => |error_union_type| {
2437 const error_union_error_set_type = Type.fromInterned(error_union_type.error_set_type);
2438 const error_union_payload_type = Type.fromInterned(error_union_type.payload_type);
2439 const error_union_error_set_offset = codegen.errUnionErrorOffset(error_union_payload_type, pt);
2440 const error_union_payload_offset = codegen.errUnionPayloadOffset(error_union_payload_type, pt);
2441
2442 try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
2443 try wip_nav.strp(name);
2444 try uleb128(diw, ty.abiSize(pt));
2445 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2446 {
2447 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
2448 try wip_nav.infoSectionOffset(
2449 .debug_info,
2450 wip_nav.unit,
2451 wip_nav.entry,
2452 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2453 );
2454 {
2455 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2456 try wip_nav.strp("is_error");
2457 const is_error_field_type = Type.fromInterned(try pt.intern(.{
2458 .opt_type = error_union_type.error_set_type,
2459 }));
2460 try wip_nav.refType(is_error_field_type);
2461 try uleb128(diw, error_union_error_set_offset);
2462
2463 try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_tagged_union_field));
2464 try uleb128(diw, 0);
2465 {
2466 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2467 try wip_nav.strp("value");
2468 try wip_nav.refType(error_union_payload_type);
2469 try uleb128(diw, error_union_payload_offset);
2470 }
2471 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2472
2473 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union_default_field));
2474 {
2475 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2476 try wip_nav.strp("error");
2477 try wip_nav.refType(error_union_error_set_type);
2478 try uleb128(diw, error_union_error_set_offset);
2479 }
2480 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2481 }
2482 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2483 }
2484 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2485 },
2486 .simple_type => |simple_type| switch (simple_type) {
2487 .f16,
2488 .f32,
2489 .f64,
2490 .f80,
2491 .f128,
2492 .usize,
2493 .isize,
2494 .c_char,
2495 .c_short,
2496 .c_ushort,
2497 .c_int,
2498 .c_uint,
2499 .c_long,
2500 .c_ulong,
2501 .c_longlong,
2502 .c_ulonglong,
2503 .c_longdouble,
2504 .bool,
2505 => {
2506 try uleb128(diw, @intFromEnum(AbbrevCode.numeric_type));
2507 try wip_nav.strp(name);
2508 try diw.writeByte(if (type_index == .bool_type)
2509 DW.ATE.boolean
2510 else if (ty.isRuntimeFloat())
2511 DW.ATE.float
2512 else if (ty.isSignedInt(zcu))
2513 DW.ATE.signed
2514 else if (ty.isUnsignedInt(zcu))
2515 DW.ATE.unsigned
2516 else
2517 unreachable);
2518 try uleb128(diw, ty.bitSize(pt));
2519 try uleb128(diw, ty.abiSize(pt));
2520 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2521 },
2522 .anyopaque,
2523 .void,
2524 .type,
2525 .comptime_int,
2526 .comptime_float,
2527 .noreturn,
2528 .null,
2529 .undefined,
2530 .enum_literal,
2531 .generic_poison,
2532 => {
2533 try uleb128(diw, @intFromEnum(AbbrevCode.void_type));
2534 try wip_nav.strp(if (type_index == .generic_poison_type) "anytype" else name);
2535 },
2536 .anyerror => return, // delay until flush
2537 .atomic_order,
2538 .atomic_rmw_op,
2539 .calling_convention,
2540 .address_space,
2541 .float_mode,
2542 .reduce_op,
2543 .call_modifier,
2544 .prefetch_options,
2545 .export_options,
2546 .extern_options,
2547 .type_info,
2548 .adhoc_inferred_error_set,
2549 => unreachable,
2550 },
2551 .struct_type,
2552 .union_type,
2553 .opaque_type,
2554 => unreachable,
2555 .anon_struct_type => |anon_struct_type| {
2556 try uleb128(diw, @intFromEnum(AbbrevCode.struct_type));
2557 try wip_nav.strp(name);
2558 try uleb128(diw, ty.abiSize(pt));
2559 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2560 var field_byte_offset: u64 = 0;
2561 for (0..anon_struct_type.types.len) |field_index| {
2562 const comptime_value = anon_struct_type.values.get(ip)[field_index];
2563 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (comptime_value != .none) .struct_field_comptime else .struct_field)));
2564 if (anon_struct_type.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
2565 const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
2566 defer dwarf.gpa.free(field_name);
2567 try wip_nav.strp(field_name);
2568 }
2569 const field_type = Type.fromInterned(anon_struct_type.types.get(ip)[field_index]);
2570 try wip_nav.refType(field_type);
2571 if (comptime_value == .none) {
2572 const field_align = field_type.abiAlignment(pt);
2573 field_byte_offset = field_align.forward(field_byte_offset);
2574 try uleb128(diw, field_byte_offset);
2575 try uleb128(diw, field_type.abiAlignment(pt).toByteUnits().?);
2576 field_byte_offset += field_type.abiSize(pt);
2577 }
2578 }
2579 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2580 },
2581 .enum_type => {
2582 const loaded_enum = ip.loadEnumType(type_index);
2583 try uleb128(diw, @intFromEnum(AbbrevCode.enum_type));
2584 try wip_nav.strp(name);
2585 try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
2586 for (0..loaded_enum.names.len) |field_index| {
2587 try wip_nav.enumConstValue(loaded_enum, .{
2588 .signed = .signed_enum_field,
2589 .unsigned = .unsigned_enum_field,
2590 }, field_index);
2591 try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
2592 }
2593 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2594 },
2595 .func_type => |func_type| {
2596 const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
2597 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_nullary) .nullary_func_type else .func_type)));
2598 try wip_nav.strp(name);
2599 try diw.writeByte(@intFromEnum(@as(DW.CC, switch (func_type.cc) {
2600 .Unspecified, .C => .normal,
2601 .Naked, .Async, .Inline => .nocall,
2602 .Interrupt, .Signal => .nocall,
2603 .Stdcall => .BORLAND_stdcall,
2604 .Fastcall => .BORLAND_fastcall,
2605 .Vectorcall => .LLVM_vectorcall,
2606 .Thiscall => .BORLAND_thiscall,
2607 .APCS => .nocall,
2608 .AAPCS => .LLVM_AAPCS,
2609 .AAPCSVFP => .LLVM_AAPCS_VFP,
2610 .SysV => .LLVM_X86_64SysV,
2611 .Win64 => .LLVM_Win64,
2612 .Kernel, .Fragment, .Vertex => .nocall,
2613 })));
2614 try wip_nav.refType(Type.fromInterned(func_type.return_type));
2615 if (!is_nullary) {
2616 for (0..func_type.param_types.len) |param_index| {
2617 try uleb128(diw, @intFromEnum(AbbrevCode.func_type_param));
2618 try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index]));
2619 }
2620 if (func_type.is_var_args) try uleb128(diw, @intFromEnum(AbbrevCode.is_var_args));
2621 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2622 }
2623 },
2624 .error_set_type => |error_set_type| {
2625 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (error_set_type.names.len > 0) .enum_type else .empty_enum_type)));
2626 try wip_nav.strp(name);
2627 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
2628 .signedness = .unsigned,
2629 .bits = pt.zcu.errorSetBits(),
2630 } })));
2631 for (0..error_set_type.names.len) |field_index| {
2632 const field_name = error_set_type.names.get(ip)[field_index];
2633 try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_enum_field));
2634 try uleb128(diw, ip.getErrorValueIfExists(field_name).?);
2635 try wip_nav.strp(field_name.toSlice(ip));
2636 }
2637 if (error_set_type.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
2638 },
2639 .inferred_error_set_type => |func| {
2640 try uleb128(diw, @intFromEnum(AbbrevCode.inferred_error_set_type));
2641 try wip_nav.strp(name);
2642 try wip_nav.refType(Type.fromInterned(ip.funcIesResolvedUnordered(func)));
2643 },
2644
2645 // values, not types
2646 .undef,
2647 .simple_value,
2648 .variable,
2649 .@"extern",
2650 .func,
2651 .int,
2652 .err,
2653 .error_union,
2654 .enum_literal,
2655 .enum_tag,
2656 .empty_enum_value,
2657 .float,
2658 .ptr,
2659 .slice,
2660 .opt,
2661 .aggregate,
2662 .un,
2663 // memoization, not types
2664 .memoized_call,
2665 => unreachable,
26972666 }
2698 return @intCast(gop.index + 1);
2667 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
26992668}
27002669
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;
2670pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternPool.Index) UpdateError!void {
2671 const zcu = pt.zcu;
2672 const ip = &zcu.intern_pool;
2673 const ty = Type.fromInterned(type_index);
2674 log.debug("updateContainerType({}({d}))", .{ ty.fmt(pt), @intFromEnum(type_index) });
2675
2676 const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip);
2677 const file = zcu.fileByIndex(inst_info.file);
2678 if (inst_info.inst == .main_struct_inst) {
2679 const unit = try dwarf.getUnit(file.mod);
2680 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
2681 if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2682 var wip_nav: WipNav = .{
2683 .dwarf = dwarf,
2684 .pt = pt,
2685 .unit = unit,
2686 .entry = type_gop.value_ptr.*,
2687 .any_children = false,
2688 .func = .none,
2689 .func_high_reloc = undefined,
2690 .debug_info = .{},
2691 .debug_line = .{},
2692 .debug_loclists = .{},
2693 .pending_types = .{},
2694 };
2695 defer wip_nav.deinit();
2696
2697 const loaded_struct = ip.loadStructType(type_index);
2698
2699 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2700 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0) .namespace_file else .file)));
2701 const file_gop = try dwarf.getUnitFiles(unit).getOrPut(dwarf.gpa, inst_info.file);
2702 try uleb128(diw, file_gop.index);
2703 try wip_nav.strp(loaded_struct.name.toSlice(ip));
2704 if (loaded_struct.field_types.len > 0) {
2705 try uleb128(diw, ty.abiSize(pt));
2706 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2707 for (0..loaded_struct.field_types.len) |field_index| {
2708 const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
2709 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
2710 if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
2711 const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
2712 defer dwarf.gpa.free(field_name);
2713 try wip_nav.strp(field_name);
2714 }
2715 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
2716 try wip_nav.refType(field_type);
2717 if (!is_comptime) {
2718 try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
2719 try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
2720 field_type.abiAlignment(pt).toByteUnits().?);
2721 }
2722 }
2723 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2724 }
27252725
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);
2726 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2727 try wip_nav.flush();
2728 } else {
2729 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
2730 assert(decl_inst.tag == .extended);
2731 if (switch (decl_inst.data.extended.opcode) {
2732 .struct_decl => @as(Zir.Inst.StructDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
2733 .enum_decl => @as(Zir.Inst.EnumDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
2734 .union_decl => @as(Zir.Inst.UnionDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
2735 .opaque_decl => @as(Zir.Inst.OpaqueDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
2736 .reify => @as(Zir.Inst.NameStrategy, @enumFromInt(decl_inst.data.extended.small)),
2737 else => unreachable,
2738 } == .parent) return;
2739
2740 const unit = try dwarf.getUnit(file.mod);
2741 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
2742 if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2743 var wip_nav: WipNav = .{
2744 .dwarf = dwarf,
2745 .pt = pt,
2746 .unit = unit,
2747 .entry = type_gop.value_ptr.*,
2748 .any_children = false,
2749 .func = .none,
2750 .func_high_reloc = undefined,
2751 .debug_info = .{},
2752 .debug_line = .{},
2753 .debug_loclists = .{},
2754 .pending_types = .{},
27292755 };
2756 defer wip_nav.deinit();
2757 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2758 const name = try std.fmt.allocPrint(dwarf.gpa, "{}", .{ty.fmt(pt)});
2759 defer dwarf.gpa.free(name);
2760
2761 switch (ip.indexToKey(type_index)) {
2762 .struct_type => {
2763 const loaded_struct = ip.loadStructType(type_index);
2764 switch (loaded_struct.layout) {
2765 .auto, .@"extern" => {
2766 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0)
2767 .namespace_struct_type
2768 else
2769 .struct_type)));
2770 try wip_nav.strp(name);
2771 if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
2772 try uleb128(diw, ty.abiSize(pt));
2773 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2774 for (0..loaded_struct.field_types.len) |field_index| {
2775 const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
2776 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
2777 if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
2778 const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
2779 defer dwarf.gpa.free(field_name);
2780 try wip_nav.strp(field_name);
2781 }
2782 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
2783 try wip_nav.refType(field_type);
2784 if (!is_comptime) {
2785 try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
2786 try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
2787 field_type.abiAlignment(pt).toByteUnits().?);
2788 }
2789 }
2790 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2791 }
2792 },
2793 .@"packed" => {
2794 try uleb128(diw, @intFromEnum(AbbrevCode.packed_struct_type));
2795 try wip_nav.strp(name);
2796 try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
2797 var field_bit_offset: u16 = 0;
2798 for (0..loaded_struct.field_types.len) |field_index| {
2799 try uleb128(diw, @intFromEnum(@as(AbbrevCode, .packed_struct_field)));
2800 try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip));
2801 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
2802 try wip_nav.refType(field_type);
2803 try uleb128(diw, field_bit_offset);
2804 field_bit_offset += @intCast(field_type.bitSize(pt));
2805 }
2806 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2807 },
2808 }
2809 },
2810 .enum_type => {
2811 const loaded_enum = ip.loadEnumType(type_index);
2812 try uleb128(diw, @intFromEnum(AbbrevCode.enum_type));
2813 try wip_nav.strp(name);
2814 try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
2815 for (0..loaded_enum.names.len) |field_index| {
2816 try wip_nav.enumConstValue(loaded_enum, .{
2817 .signed = .signed_enum_field,
2818 .unsigned = .unsigned_enum_field,
2819 }, field_index);
2820 try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
2821 }
2822 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2823 },
2824 .union_type => {
2825 const loaded_union = ip.loadUnionType(type_index);
2826 try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
2827 try wip_nav.strp(name);
2828 const union_layout = pt.getUnionLayout(loaded_union);
2829 try uleb128(diw, union_layout.abi_size);
2830 try uleb128(diw, union_layout.abi_align.toByteUnits().?);
2831 const loaded_tag = loaded_union.loadTagType(ip);
2832 if (loaded_union.hasTag(ip)) {
2833 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
2834 try wip_nav.infoSectionOffset(
2835 .debug_info,
2836 wip_nav.unit,
2837 wip_nav.entry,
2838 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2839 );
2840 {
2841 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2842 try wip_nav.strp("tag");
2843 try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty));
2844 try uleb128(diw, union_layout.tagOffset());
2845
2846 for (0..loaded_union.field_types.len) |field_index| {
2847 try wip_nav.enumConstValue(loaded_tag, .{
2848 .signed = .signed_tagged_union_field,
2849 .unsigned = .unsigned_tagged_union_field,
2850 }, field_index);
2851 {
2852 try uleb128(diw, @intFromEnum(AbbrevCode.struct_field));
2853 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
2854 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
2855 try wip_nav.refType(field_type);
2856 try uleb128(diw, union_layout.payloadOffset());
2857 try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
2858 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(pt).toByteUnits().?);
2859 }
2860 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2861 }
2862 }
2863 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2864
2865 if (ip.indexToKey(loaded_union.enum_tag_ty).enum_type == .generated_tag)
2866 try wip_nav.pending_types.append(dwarf.gpa, loaded_union.enum_tag_ty);
2867 } else for (0..loaded_union.field_types.len) |field_index| {
2868 try uleb128(diw, @intFromEnum(AbbrevCode.untagged_union_field));
2869 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
2870 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
2871 try wip_nav.refType(field_type);
2872 try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
2873 field_type.abiAlignment(pt).toByteUnits().?);
2874 }
2875 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2876 },
2877 .opaque_type => {
2878 try uleb128(diw, @intFromEnum(AbbrevCode.namespace_struct_type));
2879 try wip_nav.strp(name);
2880 try diw.writeByte(@intFromBool(true));
2881 },
2882 else => unreachable,
2883 }
2884 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2885 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items);
2886 try wip_nav.flush();
2887 }
2888}
2889
2890pub fn updateNavLineNumber(dwarf: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.Index) UpdateError!void {
2891 const ip = &zcu.intern_pool;
2892
2893 const zir_index = ip.getCau(ip.getNav(nav_index).analysis_owner.unwrap() orelse return).zir_index;
2894 const inst_info = zir_index.resolveFull(ip);
2895 assert(inst_info.inst != .main_struct_inst);
2896 const file = zcu.fileByIndex(inst_info.file);
2897
2898 const inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
2899 assert(inst.tag == .declaration);
2900 const line = file.zir.extraData(Zir.Inst.Declaration, inst.data.declaration.payload_index).data.src_line;
2901 var line_buf: [4]u8 = undefined;
2902 std.mem.writeInt(u32, &line_buf, line, dwarf.endian);
2903
2904 const unit = dwarf.debug_line.section.getUnit(dwarf.mods.get(file.mod).?);
2905 const entry = unit.getEntry(dwarf.navs.get(nav_index).?);
2906 try dwarf.getFile().?.pwriteAll(&line, dwarf.debug_line.section.off + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf));
2907}
2908
2909pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void {
2910 _ = dwarf;
2911 _ = nav_index;
2912}
27302913
2731 files_dir_indexes.appendAssumeCapacity(dir_index);
2732 files.appendAssumeCapacity(sub_file_path);
2914pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
2915 const ip = &pt.zcu.intern_pool;
2916 if (dwarf.types.get(.anyerror_type)) |entry| {
2917 var wip_nav: WipNav = .{
2918 .dwarf = dwarf,
2919 .pt = pt,
2920 .unit = .main,
2921 .entry = entry,
2922 .any_children = false,
2923 .func = .none,
2924 .func_high_reloc = undefined,
2925 .debug_info = .{},
2926 .debug_line = .{},
2927 .debug_loclists = .{},
2928 .pending_types = .{},
2929 };
2930 defer wip_nav.deinit();
2931 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2932 const global_error_set_names = ip.global_error_set.getNamesFromMainThread();
2933 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (global_error_set_names.len > 0) .enum_type else .empty_enum_type)));
2934 try wip_nav.strp("anyerror");
2935 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
2936 .signedness = .unsigned,
2937 .bits = pt.zcu.errorSetBits(),
2938 } })));
2939 for (global_error_set_names, 1..) |name, value| {
2940 try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_enum_field));
2941 try uleb128(diw, value);
2942 try wip_nav.strp(name.toSlice(ip));
2943 }
2944 if (global_error_set_names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
2945 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
27332946 }
27342947
2735 return .{
2736 .dirs = dirs.keys(),
2737 .files = files.items,
2738 .files_dirs_indexes = files_dir_indexes.items,
2739 };
2948 const cwd = try std.process.getCwdAlloc(dwarf.gpa);
2949 defer dwarf.gpa.free(cwd);
2950
2951 var header = std.ArrayList(u8).init(dwarf.gpa);
2952 defer header.deinit();
2953 if (dwarf.debug_abbrev.section.dirty) {
2954 for (1.., &AbbrevCode.abbrevs) |code, *abbrev| {
2955 try uleb128(header.writer(), code);
2956 try uleb128(header.writer(), @intFromEnum(abbrev.tag));
2957 try header.append(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no);
2958 for (abbrev.attrs) |*attr| {
2959 try uleb128(header.writer(), @intFromEnum(attr[0]));
2960 try uleb128(header.writer(), @intFromEnum(attr[1]));
2961 }
2962 try header.appendSlice(&.{ 0, 0 });
2963 }
2964 try header.append(@intFromEnum(AbbrevCode.null));
2965 try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, DebugAbbrev.entry, dwarf, header.items);
2966 dwarf.debug_abbrev.section.dirty = false;
2967 }
2968 if (dwarf.debug_aranges.section.dirty) {
2969 for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| {
2970 const unit: Unit.Index = @enumFromInt(unit_index);
2971 try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 1);
2972 header.clearRetainingCapacity();
2973 try header.ensureTotalCapacity(unit_ptr.header_len);
2974 const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
2975 dwarf.debug_aranges.section.getUnit(next_unit).off
2976 else
2977 dwarf.debug_aranges.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
2978 switch (dwarf.format) {
2979 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
2980 .@"64" => {
2981 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
2982 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
2983 },
2984 }
2985 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 2, dwarf.endian);
2986 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
2987 .source_off = @intCast(header.items.len),
2988 .target_sec = .debug_info,
2989 .target_unit = unit,
2990 });
2991 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
2992 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
2993 header.appendNTimesAssumeCapacity(0, unit_ptr.header_len - header.items.len);
2994 try unit_ptr.replaceHeader(&dwarf.debug_aranges.section, dwarf, header.items);
2995 try unit_ptr.writeTrailer(&dwarf.debug_aranges.section, dwarf);
2996 }
2997 dwarf.debug_aranges.section.dirty = false;
2998 }
2999 if (dwarf.debug_info.section.dirty) {
3000 for (dwarf.mods.keys(), dwarf.debug_info.section.units.items, 0..) |mod, *unit_ptr, unit_index| {
3001 const unit: Unit.Index = @enumFromInt(unit_index);
3002 try unit_ptr.cross_unit_relocs.ensureUnusedCapacity(dwarf.gpa, 1);
3003 try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 7);
3004 header.clearRetainingCapacity();
3005 try header.ensureTotalCapacity(unit_ptr.header_len);
3006 const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
3007 dwarf.debug_info.section.getUnit(next_unit).off
3008 else
3009 dwarf.debug_info.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
3010 switch (dwarf.format) {
3011 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3012 .@"64" => {
3013 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3014 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3015 },
3016 }
3017 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
3018 header.appendSliceAssumeCapacity(&.{ DW.UT.compile, @intFromEnum(dwarf.address_size) });
3019 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3020 .source_off = @intCast(header.items.len),
3021 .target_sec = .debug_abbrev,
3022 .target_unit = DebugAbbrev.unit,
3023 .target_entry = DebugAbbrev.entry.toOptional(),
3024 });
3025 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3026 const compile_unit_off: u32 = @intCast(header.items.len);
3027 uleb128(header.fixedWriter(), @intFromEnum(AbbrevCode.compile_unit)) catch unreachable;
3028 header.appendAssumeCapacity(DW.LANG.Zig);
3029 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3030 .source_off = @intCast(header.items.len),
3031 .target_sec = .debug_line_str,
3032 .target_unit = StringSection.unit,
3033 .target_entry = (try dwarf.debug_line_str.addString(dwarf, "zig " ++ @import("build_options").version)).toOptional(),
3034 });
3035 {
3036 const mod_root_path = try std.fs.path.resolve(dwarf.gpa, &.{
3037 cwd,
3038 mod.root.root_dir.path orelse "",
3039 mod.root.sub_path,
3040 });
3041 defer dwarf.gpa.free(mod_root_path);
3042 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3043 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3044 .source_off = @intCast(header.items.len),
3045 .target_sec = .debug_line_str,
3046 .target_unit = StringSection.unit,
3047 .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod_root_path)).toOptional(),
3048 });
3049 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3050 }
3051 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3052 .source_off = @intCast(header.items.len),
3053 .target_sec = .debug_line_str,
3054 .target_unit = StringSection.unit,
3055 .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod.root_src_path)).toOptional(),
3056 });
3057 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3058 unit_ptr.cross_unit_relocs.appendAssumeCapacity(.{
3059 .source_off = @intCast(header.items.len),
3060 .target_unit = .main,
3061 .target_off = compile_unit_off,
3062 });
3063 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3064 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3065 .source_off = @intCast(header.items.len),
3066 .target_sec = .debug_line,
3067 .target_unit = unit,
3068 });
3069 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3070 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3071 .source_off = @intCast(header.items.len),
3072 .target_sec = .debug_rnglists,
3073 .target_unit = unit,
3074 .target_off = DebugRngLists.baseOffset(dwarf),
3075 });
3076 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3077 uleb128(header.fixedWriter(), 0) catch unreachable;
3078 uleb128(header.fixedWriter(), @intFromEnum(AbbrevCode.module)) catch unreachable;
3079 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3080 .source_off = @intCast(header.items.len),
3081 .target_sec = .debug_str,
3082 .target_unit = StringSection.unit,
3083 .target_entry = (try dwarf.debug_str.addString(dwarf, mod.fully_qualified_name)).toOptional(),
3084 });
3085 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3086 uleb128(header.fixedWriter(), 0) catch unreachable;
3087 try unit_ptr.replaceHeader(&dwarf.debug_info.section, dwarf, header.items);
3088 try unit_ptr.writeTrailer(&dwarf.debug_info.section, dwarf);
3089 }
3090 dwarf.debug_info.section.dirty = false;
3091 }
3092 if (dwarf.debug_str.section.dirty) {
3093 const contents = dwarf.debug_str.contents.items;
3094 try dwarf.debug_str.section.resize(dwarf, contents.len);
3095 try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_str.section.off);
3096 dwarf.debug_str.section.dirty = false;
3097 }
3098 if (dwarf.debug_line.section.dirty) {
3099 for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit|
3100 try unit.resizeHeader(&dwarf.debug_line.section, dwarf, DebugLine.headerBytes(dwarf, @intCast(mod_info.files.count())));
3101 for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod, mod_info, *unit| {
3102 try unit.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 2 * (1 + mod_info.files.count()));
3103 header.clearRetainingCapacity();
3104 try header.ensureTotalCapacity(unit.header_len);
3105 const unit_len = (if (unit.next.unwrap()) |next_unit|
3106 dwarf.debug_line.section.getUnit(next_unit).off
3107 else
3108 dwarf.debug_line.section.len) - unit.off - dwarf.unitLengthBytes();
3109 switch (dwarf.format) {
3110 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3111 .@"64" => {
3112 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3113 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3114 },
3115 }
3116 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
3117 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
3118 switch (dwarf.format) {
3119 inline .@"32", .@"64" => |format| std.mem.writeInt(
3120 SectionOffset(format),
3121 header.addManyAsArrayAssumeCapacity(@sizeOf(SectionOffset(format))),
3122 @intCast(unit.header_len - header.items.len),
3123 dwarf.endian,
3124 ),
3125 }
3126 const StandardOpcode = DeclValEnum(DW.LNS);
3127 header.appendSliceAssumeCapacity(&[_]u8{
3128 dwarf.debug_line.header.minimum_instruction_length,
3129 dwarf.debug_line.header.maximum_operations_per_instruction,
3130 @intFromBool(dwarf.debug_line.header.default_is_stmt),
3131 @bitCast(dwarf.debug_line.header.line_base),
3132 dwarf.debug_line.header.line_range,
3133 dwarf.debug_line.header.opcode_base,
3134 });
3135 header.appendSliceAssumeCapacity(std.enums.EnumArray(StandardOpcode, u8).init(.{
3136 .extended_op = undefined,
3137 .copy = 0,
3138 .advance_pc = 1,
3139 .advance_line = 1,
3140 .set_file = 1,
3141 .set_column = 1,
3142 .negate_stmt = 0,
3143 .set_basic_block = 0,
3144 .const_add_pc = 0,
3145 .fixed_advance_pc = 1,
3146 .set_prologue_end = 0,
3147 .set_epilogue_begin = 0,
3148 .set_isa = 1,
3149 }).values[1..dwarf.debug_line.header.opcode_base]);
3150 header.appendAssumeCapacity(1);
3151 uleb128(header.fixedWriter(), DW.LNCT.path) catch unreachable;
3152 uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable;
3153 uleb128(header.fixedWriter(), 1) catch unreachable;
3154 {
3155 const mod_root_path = try std.fs.path.resolve(dwarf.gpa, &.{
3156 cwd,
3157 mod.root.root_dir.path orelse "",
3158 mod.root.sub_path,
3159 });
3160 defer dwarf.gpa.free(mod_root_path);
3161 unit.cross_section_relocs.appendAssumeCapacity(.{
3162 .source_off = @intCast(header.items.len),
3163 .target_sec = .debug_line_str,
3164 .target_unit = StringSection.unit,
3165 .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod_root_path)).toOptional(),
3166 });
3167 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3168 }
3169 header.appendAssumeCapacity(2);
3170 uleb128(header.fixedWriter(), DW.LNCT.path) catch unreachable;
3171 uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable;
3172 uleb128(header.fixedWriter(), DW.LNCT.LLVM_source) catch unreachable;
3173 uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable;
3174 uleb128(header.fixedWriter(), mod_info.files.count()) catch unreachable;
3175 for (mod_info.files.keys()) |file_index| {
3176 const file = pt.zcu.fileByIndex(file_index);
3177 unit.cross_section_relocs.appendAssumeCapacity(.{
3178 .source_off = @intCast(header.items.len),
3179 .target_sec = .debug_line_str,
3180 .target_unit = StringSection.unit,
3181 .target_entry = (try dwarf.debug_line_str.addString(dwarf, file.sub_file_path)).toOptional(),
3182 });
3183 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3184 unit.cross_section_relocs.appendAssumeCapacity(.{
3185 .source_off = @intCast(header.items.len),
3186 .target_sec = .debug_line_str,
3187 .target_unit = StringSection.unit,
3188 .target_entry = (try dwarf.debug_line_str.addString(
3189 dwarf,
3190 if (file.mod.builtin_file == file) file.source else "",
3191 )).toOptional(),
3192 });
3193 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3194 }
3195 try unit.replaceHeader(&dwarf.debug_line.section, dwarf, header.items);
3196 try unit.writeTrailer(&dwarf.debug_line.section, dwarf);
3197 }
3198 dwarf.debug_line.section.dirty = false;
3199 }
3200 if (dwarf.debug_line_str.section.dirty) {
3201 const contents = dwarf.debug_line_str.contents.items;
3202 try dwarf.debug_line_str.section.resize(dwarf, contents.len);
3203 try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off);
3204 dwarf.debug_line_str.section.dirty = false;
3205 }
3206 if (dwarf.debug_rnglists.section.dirty) {
3207 for (dwarf.debug_rnglists.section.units.items) |*unit| {
3208 header.clearRetainingCapacity();
3209 try header.ensureTotalCapacity(unit.header_len);
3210 const unit_len = (if (unit.next.unwrap()) |next_unit|
3211 dwarf.debug_rnglists.section.getUnit(next_unit).off
3212 else
3213 dwarf.debug_rnglists.section.len) - unit.off - dwarf.unitLengthBytes();
3214 switch (dwarf.format) {
3215 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3216 .@"64" => {
3217 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3218 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3219 },
3220 }
3221 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
3222 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
3223 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), 1, dwarf.endian);
3224 switch (dwarf.format) {
3225 inline .@"32", .@"64" => |format| std.mem.writeInt(
3226 SectionOffset(format),
3227 header.addManyAsArrayAssumeCapacity(@sizeOf(SectionOffset(format))),
3228 @sizeOf(SectionOffset(format)),
3229 dwarf.endian,
3230 ),
3231 }
3232 try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header.items);
3233 try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf);
3234 }
3235 dwarf.debug_rnglists.section.dirty = false;
3236 }
27403237}
27413238
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);
3239pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void {
3240 for ([_]*Section{
3241 &dwarf.debug_abbrev.section,
3242 &dwarf.debug_aranges.section,
3243 &dwarf.debug_info.section,
3244 &dwarf.debug_line.section,
3245 &dwarf.debug_line_str.section,
3246 &dwarf.debug_loclists.section,
3247 &dwarf.debug_rnglists.section,
3248 &dwarf.debug_str.section,
3249 }) |sec| try sec.resolveRelocs(dwarf);
27493250}
27503251
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);
3252fn DeclValEnum(comptime T: type) type {
3253 const decls = @typeInfo(T).Struct.decls;
3254 @setEvalBranchQuota(7 * decls.len);
3255 var fields: [decls.len]std.builtin.Type.EnumField = undefined;
3256 var fields_len = 0;
3257 var min_value: ?comptime_int = null;
3258 var max_value: ?comptime_int = null;
3259 for (decls) |decl| {
3260 if (std.mem.startsWith(u8, decl.name, "HP_") or std.mem.endsWith(u8, decl.name, "_user")) continue;
3261 const value = @field(T, decl.name);
3262 fields[fields_len] = .{ .name = decl.name, .value = value };
3263 fields_len += 1;
3264 if (min_value == null or min_value.? > value) min_value = value;
3265 if (max_value == null or max_value.? < value) max_value = value;
3266 }
3267 return @Type(.{ .Enum = .{
3268 .tag_type = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0),
3269 .fields = fields[0..fields_len],
3270 .decls = &.{},
3271 .is_exhaustive = true,
3272 } });
27943273}
27953274
2796const Kind = enum { src_fn, di_atom };
3275const AbbrevCode = enum(u8) {
3276 null,
3277 // padding codes must be one byte uleb128 values to function
3278 pad_1,
3279 pad_n,
3280 // decl codes are assumed to all have the same uleb128 length
3281 decl_alias,
3282 decl_enum,
3283 decl_namespace_struct,
3284 decl_struct,
3285 decl_packed_struct,
3286 decl_union,
3287 decl_var,
3288 decl_func,
3289 decl_func_empty,
3290 // the rest are unrestricted
3291 compile_unit,
3292 module,
3293 namespace_file,
3294 file,
3295 signed_enum_field,
3296 unsigned_enum_field,
3297 generated_field,
3298 struct_field,
3299 struct_field_comptime,
3300 packed_struct_field,
3301 untagged_union_field,
3302 tagged_union,
3303 signed_tagged_union_field,
3304 unsigned_tagged_union_field,
3305 tagged_union_default_field,
3306 void_type,
3307 numeric_type,
3308 inferred_error_set_type,
3309 ptr_type,
3310 is_const,
3311 is_volatile,
3312 array_type,
3313 array_index,
3314 nullary_func_type,
3315 func_type,
3316 func_type_param,
3317 is_var_args,
3318 enum_type,
3319 empty_enum_type,
3320 namespace_struct_type,
3321 struct_type,
3322 packed_struct_type,
3323 union_type,
3324 local_arg,
3325 local_var,
27973326
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 }
3327 const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_func_empty));
3328
3329 const Attr = struct {
3330 DeclValEnum(DW.AT),
3331 DeclValEnum(DW.FORM),
28123332 };
2813 const atom = self.getAtomPtr(kind, index);
2814 atom.* = .{
2815 .off = 0,
2816 .len = 0,
2817 .prev_index = null,
2818 .next_index = null,
3333 const decl_abbrev_common_attrs = &[_]Attr{
3334 .{ .ZIG_parent, .ref_addr },
3335 .{ .decl_line, .data4 },
3336 .{ .decl_column, .udata },
3337 .{ .accessibility, .data1 },
3338 .{ .name, .strp },
28193339 };
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.*;
3340 const abbrevs = std.EnumArray(AbbrevCode, struct {
3341 tag: DeclValEnum(DW.TAG),
3342 children: bool = false,
3343 attrs: []const Attr = &.{},
3344 }).init(.{
3345 .pad_1 = .{
3346 .tag = .ZIG_padding,
28313347 },
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.*;
3348 .pad_n = .{
3349 .tag = .ZIG_padding,
3350 .attrs = &.{
3351 .{ .ZIG_padding, .block },
3352 },
3353 },
3354 .decl_alias = .{
3355 .tag = .imported_declaration,
3356 .attrs = decl_abbrev_common_attrs ++ .{
3357 .{ .import, .ref_addr },
3358 },
3359 },
3360 .decl_enum = .{
3361 .tag = .enumeration_type,
3362 .children = true,
3363 .attrs = decl_abbrev_common_attrs ++ .{
3364 .{ .type, .ref_addr },
3365 },
3366 },
3367 .decl_namespace_struct = .{
3368 .tag = .structure_type,
3369 .attrs = decl_abbrev_common_attrs ++ .{
3370 .{ .declaration, .flag },
3371 },
3372 },
3373 .decl_struct = .{
3374 .tag = .structure_type,
3375 .children = true,
3376 .attrs = decl_abbrev_common_attrs ++ .{
3377 .{ .byte_size, .udata },
3378 .{ .alignment, .udata },
3379 },
3380 },
3381 .decl_packed_struct = .{
3382 .tag = .structure_type,
3383 .children = true,
3384 .attrs = decl_abbrev_common_attrs ++ .{
3385 .{ .type, .ref_addr },
3386 },
3387 },
3388 .decl_union = .{
3389 .tag = .union_type,
3390 .children = true,
3391 .attrs = decl_abbrev_common_attrs ++ .{
3392 .{ .byte_size, .udata },
3393 .{ .alignment, .udata },
3394 },
3395 },
3396 .decl_var = .{
3397 .tag = .variable,
3398 .attrs = decl_abbrev_common_attrs ++ .{
3399 .{ .linkage_name, .strp },
3400 .{ .type, .ref_addr },
3401 .{ .location, .exprloc },
3402 .{ .alignment, .udata },
3403 .{ .external, .flag },
3404 },
3405 },
3406 .decl_func = .{
3407 .tag = .subprogram,
3408 .children = true,
3409 .attrs = decl_abbrev_common_attrs ++ .{
3410 .{ .linkage_name, .strp },
3411 .{ .type, .ref_addr },
3412 .{ .low_pc, .addr },
3413 .{ .high_pc, .addr },
3414 .{ .alignment, .udata },
3415 .{ .external, .flag },
3416 .{ .noreturn, .flag },
3417 },
28383418 },
3419 .decl_func_empty = .{
3420 .tag = .subprogram,
3421 .attrs = decl_abbrev_common_attrs ++ .{
3422 .{ .linkage_name, .strp },
3423 .{ .type, .ref_addr },
3424 .{ .low_pc, .addr },
3425 .{ .high_pc, .addr },
3426 .{ .alignment, .udata },
3427 .{ .external, .flag },
3428 .{ .noreturn, .flag },
3429 },
3430 },
3431 .compile_unit = .{
3432 .tag = .compile_unit,
3433 .children = true,
3434 .attrs = &.{
3435 .{ .language, .data1 },
3436 .{ .producer, .line_strp },
3437 .{ .comp_dir, .line_strp },
3438 .{ .name, .line_strp },
3439 .{ .base_types, .ref_addr },
3440 .{ .stmt_list, .sec_offset },
3441 .{ .rnglists_base, .sec_offset },
3442 .{ .ranges, .rnglistx },
3443 },
3444 },
3445 .module = .{
3446 .tag = .module,
3447 .children = true,
3448 .attrs = &.{
3449 .{ .name, .strp },
3450 .{ .ranges, .rnglistx },
3451 },
3452 },
3453 .namespace_file = .{
3454 .tag = .structure_type,
3455 .attrs = &.{
3456 .{ .decl_file, .udata },
3457 .{ .name, .strp },
3458 },
3459 },
3460 .file = .{
3461 .tag = .structure_type,
3462 .children = true,
3463 .attrs = &.{
3464 .{ .decl_file, .udata },
3465 .{ .name, .strp },
3466 .{ .byte_size, .udata },
3467 .{ .alignment, .udata },
3468 },
3469 },
3470 .signed_enum_field = .{
3471 .tag = .enumerator,
3472 .attrs = &.{
3473 .{ .const_value, .sdata },
3474 .{ .name, .strp },
3475 },
3476 },
3477 .unsigned_enum_field = .{
3478 .tag = .enumerator,
3479 .attrs = &.{
3480 .{ .const_value, .udata },
3481 .{ .name, .strp },
3482 },
3483 },
3484 .generated_field = .{
3485 .tag = .member,
3486 .attrs = &.{
3487 .{ .name, .strp },
3488 .{ .type, .ref_addr },
3489 .{ .data_member_location, .udata },
3490 .{ .artificial, .flag_present },
3491 },
3492 },
3493 .struct_field = .{
3494 .tag = .member,
3495 .attrs = &.{
3496 .{ .name, .strp },
3497 .{ .type, .ref_addr },
3498 .{ .data_member_location, .udata },
3499 .{ .alignment, .udata },
3500 },
3501 },
3502 .struct_field_comptime = .{
3503 .tag = .member,
3504 .attrs = &.{
3505 .{ .name, .strp },
3506 .{ .type, .ref_addr },
3507 .{ .const_expr, .flag_present },
3508 },
3509 },
3510 .packed_struct_field = .{
3511 .tag = .member,
3512 .attrs = &.{
3513 .{ .name, .strp },
3514 .{ .type, .ref_addr },
3515 .{ .data_bit_offset, .udata },
3516 },
3517 },
3518 .untagged_union_field = .{
3519 .tag = .member,
3520 .attrs = &.{
3521 .{ .name, .strp },
3522 .{ .type, .ref_addr },
3523 .{ .alignment, .udata },
3524 },
3525 },
3526 .tagged_union = .{
3527 .tag = .variant_part,
3528 .children = true,
3529 .attrs = &.{
3530 .{ .discr, .ref_addr },
3531 },
3532 },
3533 .signed_tagged_union_field = .{
3534 .tag = .variant,
3535 .children = true,
3536 .attrs = &.{
3537 .{ .discr_value, .sdata },
3538 },
3539 },
3540 .unsigned_tagged_union_field = .{
3541 .tag = .variant,
3542 .children = true,
3543 .attrs = &.{
3544 .{ .discr_value, .udata },
3545 },
3546 },
3547 .tagged_union_default_field = .{
3548 .tag = .variant,
3549 .children = true,
3550 .attrs = &.{},
3551 },
3552 .void_type = .{
3553 .tag = .unspecified_type,
3554 .attrs = &.{
3555 .{ .name, .strp },
3556 },
3557 },
3558 .numeric_type = .{
3559 .tag = .base_type,
3560 .attrs = &.{
3561 .{ .name, .strp },
3562 .{ .encoding, .data1 },
3563 .{ .bit_size, .udata },
3564 .{ .byte_size, .udata },
3565 .{ .alignment, .udata },
3566 },
3567 },
3568 .inferred_error_set_type = .{
3569 .tag = .typedef,
3570 .attrs = &.{
3571 .{ .name, .strp },
3572 .{ .type, .ref_addr },
3573 },
3574 },
3575 .ptr_type = .{
3576 .tag = .pointer_type,
3577 .attrs = &.{
3578 .{ .name, .strp },
3579 .{ .ZIG_is_allowzero, .flag },
3580 .{ .alignment, .udata },
3581 .{ .address_class, .data1 },
3582 .{ .type, .ref_addr },
3583 },
3584 },
3585 .is_const = .{
3586 .tag = .const_type,
3587 .attrs = &.{
3588 .{ .type, .ref_addr },
3589 },
3590 },
3591 .is_volatile = .{
3592 .tag = .volatile_type,
3593 .attrs = &.{
3594 .{ .type, .ref_addr },
3595 },
3596 },
3597 .array_type = .{
3598 .tag = .array_type,
3599 .children = true,
3600 .attrs = &.{
3601 .{ .name, .strp },
3602 .{ .type, .ref_addr },
3603 .{ .GNU_vector, .flag },
3604 },
3605 },
3606 .array_index = .{
3607 .tag = .subrange_type,
3608 .attrs = &.{
3609 .{ .type, .ref_addr },
3610 .{ .count, .udata },
3611 },
3612 },
3613 .nullary_func_type = .{
3614 .tag = .subroutine_type,
3615 .attrs = &.{
3616 .{ .name, .strp },
3617 .{ .calling_convention, .data1 },
3618 .{ .type, .ref_addr },
3619 },
3620 },
3621 .func_type = .{
3622 .tag = .subroutine_type,
3623 .children = true,
3624 .attrs = &.{
3625 .{ .name, .strp },
3626 .{ .calling_convention, .data1 },
3627 .{ .type, .ref_addr },
3628 },
3629 },
3630 .func_type_param = .{
3631 .tag = .formal_parameter,
3632 .attrs = &.{
3633 .{ .type, .ref_addr },
3634 },
3635 },
3636 .is_var_args = .{
3637 .tag = .unspecified_parameters,
3638 },
3639 .enum_type = .{
3640 .tag = .enumeration_type,
3641 .children = true,
3642 .attrs = &.{
3643 .{ .name, .strp },
3644 .{ .type, .ref_addr },
3645 },
3646 },
3647 .empty_enum_type = .{
3648 .tag = .enumeration_type,
3649 .attrs = &.{
3650 .{ .name, .strp },
3651 .{ .type, .ref_addr },
3652 },
3653 },
3654 .namespace_struct_type = .{
3655 .tag = .structure_type,
3656 .attrs = &.{
3657 .{ .name, .strp },
3658 .{ .declaration, .flag },
3659 },
3660 },
3661 .struct_type = .{
3662 .tag = .structure_type,
3663 .children = true,
3664 .attrs = &.{
3665 .{ .name, .strp },
3666 .{ .byte_size, .udata },
3667 .{ .alignment, .udata },
3668 },
3669 },
3670 .packed_struct_type = .{
3671 .tag = .structure_type,
3672 .children = true,
3673 .attrs = &.{
3674 .{ .name, .strp },
3675 .{ .type, .ref_addr },
3676 },
3677 },
3678 .union_type = .{
3679 .tag = .union_type,
3680 .children = true,
3681 .attrs = &.{
3682 .{ .name, .strp },
3683 .{ .byte_size, .udata },
3684 .{ .alignment, .udata },
3685 },
3686 },
3687 .local_arg = .{
3688 .tag = .formal_parameter,
3689 .attrs = &.{
3690 .{ .name, .strp },
3691 .{ .type, .ref_addr },
3692 .{ .location, .exprloc },
3693 },
3694 },
3695 .local_var = .{
3696 .tag = .variable,
3697 .attrs = &.{
3698 .{ .name, .strp },
3699 .{ .type, .ref_addr },
3700 .{ .location, .exprloc },
3701 },
3702 },
3703 .null = undefined,
3704 }).values[1..].*;
3705};
3706
3707fn getFile(dwarf: *Dwarf) ?std.fs.File {
3708 if (dwarf.bin_file.cast(.macho)) |macho_file| if (macho_file.d_sym) |*d_sym| return d_sym.file;
3709 return dwarf.bin_file.file;
3710}
3711
3712fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {
3713 const entry = try dwarf.debug_aranges.section.addEntry(unit, dwarf);
3714 assert(try dwarf.debug_info.section.addEntry(unit, dwarf) == entry);
3715 assert(try dwarf.debug_line.section.addEntry(unit, dwarf) == entry);
3716 assert(try dwarf.debug_loclists.section.addEntry(unit, dwarf) == entry);
3717 assert(try dwarf.debug_rnglists.section.addEntry(unit, dwarf) == entry);
3718 return entry;
3719}
3720
3721fn writeInt(dwarf: *Dwarf, buf: []u8, int: u64) void {
3722 switch (buf.len) {
3723 inline 0...8 => |len| std.mem.writeInt(@Type(.{ .Int = .{
3724 .signedness = .unsigned,
3725 .bits = len * 8,
3726 } }), buf[0..len], @intCast(int), dwarf.endian),
3727 else => unreachable,
28393728 }
28403729}
28413730
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 };
3731fn resolveReloc(dwarf: *Dwarf, source: u64, target: u64, size: u32) RelocError!void {
3732 var buf: [8]u8 = undefined;
3733 dwarf.writeInt(buf[0..size], target);
3734 try dwarf.getFile().?.pwriteAll(buf[0..size], source);
28473735}
28483736
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],
3737fn unitLengthBytes(dwarf: *Dwarf) u32 {
3738 return switch (dwarf.format) {
3739 .@"32" => 4,
3740 .@"64" => 4 + 8,
28533741 };
28543742}
28553743
2856pub const Format = enum {
2857 dwarf32,
2858 dwarf64,
2859};
3744fn sectionOffsetBytes(dwarf: *Dwarf) u32 {
3745 return switch (dwarf.format) {
3746 .@"32" => 4,
3747 .@"64" => 8,
3748 };
3749}
28603750
2861const Dwarf = @This();
3751fn SectionOffset(comptime format: DW.Format) type {
3752 return switch (format) {
3753 .@"32" => u32,
3754 .@"64" => u64,
3755 };
3756}
28623757
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;
3758fn uleb128Bytes(value: anytype) u32 {
3759 var cw = std.io.countingWriter(std.io.null_writer);
3760 try uleb128(cw.writer(), value);
3761 return @intCast(cw.bytes_written);
3762}
28703763
2871const link = @import("../link.zig");
2872const trace = @import("../tracy.zig").trace;
3764/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
3765const force_incremental = false;
3766inline fn incremental(dwarf: Dwarf) bool {
3767 return force_incremental or dwarf.bin_file.comp.incremental;
3768}
28733769
2874const Allocator = mem.Allocator;
28753770const 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");
3771const Dwarf = @This();
28813772const InternPool = @import("../InternPool.zig");
2882const StringTable = @import("StringTable.zig");
3773const Module = @import("../Package.zig").Module;
28833774const Type = @import("../Type.zig");
2884const Value = @import("../Value.zig");
3775const Zcu = @import("../Zcu.zig");
3776const Zir = std.zig.Zir;
3777const assert = std.debug.assert;
3778const codegen = @import("../codegen.zig");
3779const link = @import("../link.zig");
3780const log = std.log.scoped(.dwarf);
3781const sleb128 = std.leb.writeIleb128;
3782const std = @import("std");
3783const target_info = @import("../target.zig");
3784const 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+438
......@@ -0,0 +1,438 @@
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
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 },
182 );
183 db.addLldbTest(
184 "storage",
185 target,
186 &.{
187 .{
188 .path = "storage.zig",
189 .source =
190 \\const global_const: u64 = 0x19e50dc8d6002077;
191 \\var global_var: u64 = 0xcc423cec08622e32;
192 \\threadlocal var global_threadlocal1: u64 = 0xb4d643528c042121;
193 \\threadlocal var global_threadlocal2: u64 = 0x43faea1cf5ad7a22;
194 \\fn testStorage(
195 \\ param1: u64,
196 \\ param2: u64,
197 \\ param3: u64,
198 \\ param4: u64,
199 \\ param5: u64,
200 \\ param6: u64,
201 \\ param7: u64,
202 \\ param8: u64,
203 \\) callconv(.C) void {
204 \\ const local_comptime_val: u64 = global_const *% global_const;
205 \\ const local_comptime_ptr: struct { u64 } = .{ local_comptime_val *% local_comptime_val };
206 \\ const local_const: u64 = global_var ^ global_threadlocal1 ^ global_threadlocal2 ^
207 \\ param1 ^ param2 ^ param3 ^ param4 ^ param5 ^ param6 ^ param7 ^ param8;
208 \\ var local_var: u64 = local_comptime_ptr[0] ^ local_const;
209 \\ local_var = local_var;
210 \\}
211 \\pub fn main() void {
212 \\ testStorage(
213 \\ 0x6a607e08125c7e00,
214 \\ 0x98944cb2a45a8b51,
215 \\ 0xa320cf10601ee6fb,
216 \\ 0x691ed3535bad3274,
217 \\ 0x63690e6867a5799f,
218 \\ 0x8e163f0ec76067f2,
219 \\ 0xf9a252c455fb4c06,
220 \\ 0xc88533722601e481,
221 \\ );
222 \\}
223 \\
224 ,
225 },
226 },
227 \\breakpoint set --file storage.zig --source-pattern-regexp 'local_var = local_var;'
228 \\process launch
229 \\target variable --show-types --format hex global_const global_var global_threadlocal1 global_threadlocal2
230 \\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
231 \\breakpoint delete --force
232 ,
233 &.{
234 \\(lldb) target variable --show-types --format hex global_const global_var global_threadlocal1 global_threadlocal2
235 \\(u64) global_const = 0x19e50dc8d6002077
236 \\(u64) global_var = 0xcc423cec08622e32
237 \\(u64) global_threadlocal1 = 0xb4d643528c042121
238 \\(u64) global_threadlocal2 = 0x43faea1cf5ad7a22
239 \\(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
240 \\(u64) param1 = 0x6a607e08125c7e00
241 \\(u64) param2 = 0x98944cb2a45a8b51
242 \\(u64) param3 = 0xa320cf10601ee6fb
243 \\(u64) param4 = 0x691ed3535bad3274
244 \\(u64) param5 = 0x63690e6867a5799f
245 \\(u64) param6 = 0x8e163f0ec76067f2
246 \\(u64) param7 = 0xf9a252c455fb4c06
247 \\(u64) param8 = 0xc88533722601e481
248 \\(u64) local_comptime_val = 0x69490636f81df751
249 \\(u64) local_comptime_ptr.0 = 0x82e834dae74767a1
250 \\(u64) local_const = 0xdffceb8b2f41e205
251 \\(u64) local_var = 0x5d14df51c80685a4
252 },
253 );
254 db.addLldbTest(
255 "slices",
256 target,
257 &.{
258 .{
259 .path = "slices.zig",
260 .source =
261 \\pub fn main() void {
262 \\ {
263 \\ var array: [4]u32 = .{ 1, 2, 4, 8 };
264 \\ const slice: []u32 = &array;
265 \\ _ = slice;
266 \\ }
267 \\}
268 \\
269 ,
270 },
271 },
272 \\breakpoint set --file slices.zig --source-pattern-regexp '_ = slice;'
273 \\process launch
274 \\frame variable --show-types array slice
275 \\breakpoint delete --force
276 ,
277 &.{
278 \\(lldb) frame variable --show-types array slice
279 \\([4]u32) array = {
280 \\ (u32) [0] = 1
281 \\ (u32) [1] = 2
282 \\ (u32) [2] = 4
283 \\ (u32) [3] = 8
284 \\}
285 \\([]u32) slice = {
286 \\ (u32) [0] = 1
287 \\ (u32) [1] = 2
288 \\ (u32) [2] = 4
289 \\ (u32) [3] = 8
290 \\}
291 },
292 );
293 db.addLldbTest(
294 "optionals",
295 target,
296 &.{
297 .{
298 .path = "optionals.zig",
299 .source =
300 \\pub fn main() void {
301 \\ {
302 \\ var null_u32: ?u32 = null;
303 \\ var maybe_u32: ?u32 = null;
304 \\ var nonnull_u32: ?u32 = 456;
305 \\ maybe_u32 = 123;
306 \\ _ = .{ &null_u32, &nonnull_u32 };
307 \\ }
308 \\}
309 \\
310 ,
311 },
312 },
313 \\breakpoint set --file optionals.zig --source-pattern-regexp 'maybe_u32 = 123;'
314 \\process launch
315 \\frame variable null_u32 maybe_u32 nonnull_u32
316 \\breakpoint delete --force
317 \\
318 \\breakpoint set --file optionals.zig --source-pattern-regexp '_ = .{ &null_u32, &nonnull_u32 };'
319 \\process continue
320 \\frame variable --show-types null_u32 maybe_u32 nonnull_u32
321 \\breakpoint delete --force
322 ,
323 &.{
324 \\(lldb) frame variable null_u32 maybe_u32 nonnull_u32
325 \\(?u32) null_u32 = null
326 \\(?u32) maybe_u32 = null
327 \\(?u32) nonnull_u32 = (nonnull_u32.? = 456)
328 ,
329 \\(lldb) frame variable --show-types null_u32 maybe_u32 nonnull_u32
330 \\(?u32) null_u32 = null
331 \\(?u32) maybe_u32 = {
332 \\ (u32) maybe_u32.? = 123
333 \\}
334 \\(?u32) nonnull_u32 = {
335 \\ (u32) nonnull_u32.? = 456
336 \\}
337 },
338 );
339}
340
341const File = struct { path: []const u8, source: []const u8 };
342
343fn addGdbTest(
344 db: *Debugger,
345 name: []const u8,
346 target: Target,
347 files: []const File,
348 commands: []const u8,
349 expected_output: []const []const u8,
350) void {
351 db.addTest(
352 name,
353 target,
354 files,
355 &.{
356 db.options.gdb orelse return,
357 "--batch",
358 "--command",
359 },
360 commands,
361 &.{
362 "--args",
363 },
364 expected_output,
365 );
366}
367
368fn addLldbTest(
369 db: *Debugger,
370 name: []const u8,
371 target: Target,
372 files: []const File,
373 commands: []const u8,
374 expected_output: []const []const u8,
375) void {
376 db.addTest(
377 name,
378 target,
379 files,
380 &.{
381 db.options.lldb orelse return,
382 "--batch",
383 "--source",
384 },
385 commands,
386 &.{
387 "--",
388 },
389 expected_output,
390 );
391}
392
393/// After a failure while running a script, the debugger starts accepting commands from stdin, and
394/// because it is empty, the debugger exits normally with status 0. Choose a non-zero status to
395/// return from the debugger script instead to detect it running to completion and indicate success.
396const success = 99;
397
398fn addTest(
399 db: *Debugger,
400 name: []const u8,
401 target: Target,
402 files: []const File,
403 db_argv1: []const []const u8,
404 commands: []const u8,
405 db_argv2: []const []const u8,
406 expected_output: []const []const u8,
407) void {
408 for (db.options.test_filters) |test_filter| {
409 if (std.mem.indexOf(u8, name, test_filter)) |_| return;
410 }
411 const files_wf = db.b.addWriteFiles();
412 const exe = db.b.addExecutable(.{
413 .name = name,
414 .target = target.resolved,
415 .root_source_file = files_wf.add(files[0].path, files[0].source),
416 .optimize = target.optimize_mode,
417 .link_libc = target.link_libc,
418 .single_threaded = target.single_threaded,
419 .pic = target.pic,
420 .strip = false,
421 .use_llvm = false,
422 .use_lld = false,
423 });
424 for (files[1..]) |file| _ = files_wf.add(file.path, file.source);
425 const commands_wf = db.b.addWriteFiles();
426 const run = std.Build.Step.Run.create(db.b, db.b.fmt("run {s} {s}", .{ name, target.test_name_suffix }));
427 run.addArgs(db_argv1);
428 run.addFileArg(commands_wf.add(db.b.fmt("{s}.cmd", .{name}), db.b.fmt("{s}\n\nquit {d}\n", .{ commands, success })));
429 run.addArgs(db_argv2);
430 run.addArtifactArg(exe);
431 for (expected_output) |expected| run.addCheck(.{ .expect_stdout_match = db.b.fmt("{s}\n", .{expected}) });
432 run.addCheck(.{ .expect_term = .{ .Exited = success } });
433 run.setStdIn(.{ .bytes = "" });
434 db.root_step.dependOn(&run.step);
435}
436
437const Debugger = @This();
438const 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}