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

Merge pull request #21078 from jacobly0/new-dwarf

Dwarf: rework self-hosted debug info from scratch

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

build.zig+9
...@@ -549,6 +549,15 @@ pub fn build(b: *std.Build) !void {...@@ -549,6 +549,15 @@ pub fn build(b: *std.Build) !void {
549 test_step.dependOn(tests.addStackTraceTests(b, test_filters, optimization_modes));549 test_step.dependOn(tests.addStackTraceTests(b, test_filters, optimization_modes));
550 test_step.dependOn(tests.addCliTests(b));550 test_step.dependOn(tests.addCliTests(b));
551 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filters, optimization_modes));551 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
553 try addWasiUpdateStep(b, version);562 try addWasiUpdateStep(b, version);
554563
ci/x86_64-linux-debug.sh+1
...@@ -64,6 +64,7 @@ stage3-debug/bin/zig build \...@@ -64,6 +64,7 @@ stage3-debug/bin/zig build \
6464
65stage3-debug/bin/zig build test docs \65stage3-debug/bin/zig build test docs \
66 --maxrss 21000000000 \66 --maxrss 21000000000 \
67 -Dlldb=$HOME/deps/lldb-zig/Debug/bin/lldb \
67 -fqemu \68 -fqemu \
68 -fwasmtime \69 -fwasmtime \
69 -Dstatic-llvm \70 -Dstatic-llvm \
ci/x86_64-linux-release.sh+1
...@@ -64,6 +64,7 @@ stage3-release/bin/zig build \...@@ -64,6 +64,7 @@ stage3-release/bin/zig build \
6464
65stage3-release/bin/zig build test docs \65stage3-release/bin/zig build test docs \
66 --maxrss 21000000000 \66 --maxrss 21000000000 \
67 -Dlldb=$HOME/deps/lldb-zig/Release/bin/lldb \
67 -fqemu \68 -fqemu \
68 -fwasmtime \69 -fwasmtime \
69 -Dstatic-llvm \70 -Dstatic-llvm \
lib/std/array_list.zig+18
...@@ -359,6 +359,24 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -359,6 +359,24 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
359 return m.len;359 return m.len;
360 }360 }
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
362 /// Append a value to the list `n` times.380 /// Append a value to the list `n` times.
363 /// Allocates more memory as necessary.381 /// Allocates more memory as necessary.
364 /// Invalidates element pointers if additional memory is needed.382 /// Invalidates element pointers if additional memory is needed.
lib/std/debug.zig+3
...@@ -1360,6 +1360,9 @@ test "manage resources correctly" {...@@ -1360,6 +1360,9 @@ test "manage resources correctly" {
1360 return error.SkipZigTest;1360 return error.SkipZigTest;
1361 }1361 }
13621362
1363 // self-hosted debug info is still too buggy
1364 if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest;
1365
1363 const writer = std.io.null_writer;1366 const writer = std.io.null_writer;
1364 var di = try SelfInfo.open(testing.allocator);1367 var di = try SelfInfo.open(testing.allocator);
1365 defer di.deinit();1368 defer di.deinit();
lib/std/dwarf.zig+36
...@@ -95,6 +95,9 @@ pub const LNE = struct {...@@ -95,6 +95,9 @@ pub const LNE = struct {
95 pub const set_discriminator = 0x04;95 pub const set_discriminator = 0x04;
96 pub const lo_user = 0x80;96 pub const lo_user = 0x80;
97 pub const hi_user = 0xff;97 pub const hi_user = 0xff;
98
99 // Zig extensions
100 pub const ZIG_set_decl = 0xec;
98};101};
99102
100pub const UT = struct {103pub const UT = struct {
...@@ -118,6 +121,8 @@ pub const LNCT = struct {...@@ -118,6 +121,8 @@ pub const LNCT = struct {
118121
119 pub const lo_user = 0x2000;122 pub const lo_user = 0x2000;
120 pub const hi_user = 0x3fff;123 pub const hi_user = 0x3fff;
124
125 pub const LLVM_source = 0x2001;
121};126};
122127
123pub const RLE = struct {128pub const RLE = struct {
...@@ -142,6 +147,37 @@ pub const CC = enum(u8) {...@@ -142,6 +147,37 @@ pub const CC = enum(u8) {
142 GNU_renesas_sh = 0x40,147 GNU_renesas_sh = 0x40,
143 GNU_borland_fastcall_i386 = 0x41,148 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
145 pub const lo_user = 0x40;175 pub const lo_user = 0x40;
146 pub const hi_user = 0xff;176 pub const hi_user = 0xff;
147};177};
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;...@@ -218,6 +218,15 @@ pub const VMS_rtnbeg_pd_address = 0x2201;
218// See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type .218// See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type .
219pub const use_GNAT_descriptive_type = 0x2301;219pub const use_GNAT_descriptive_type = 0x2301;
220pub const GNAT_descriptive_type = 0x2302;220pub 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
221// UPC extension.230// UPC extension.
222pub const upc_threads_scaled = 0x3210;231pub const upc_threads_scaled = 0x3210;
223// PGI (STMicroelectronics) extensions.232// PGI (STMicroelectronics) extensions.
lib/std/dwarf/LANG.zig+24
...@@ -35,6 +35,30 @@ pub const Fortran03 = 0x0022;...@@ -35,6 +35,30 @@ pub const Fortran03 = 0x0022;
35pub const Fortran08 = 0x0023;35pub const Fortran08 = 0x0023;
36pub const RenderScript = 0x0024;36pub const RenderScript = 0x0024;
37pub const BLISS = 0x0025;37pub 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
39pub const lo_user = 0x8000;63pub const lo_user = 0x8000;
40pub const hi_user = 0xffff;64pub const hi_user = 0xffff;
lib/std/io.zig+1-1
...@@ -419,7 +419,7 @@ pub const tty = @import("io/tty.zig");...@@ -419,7 +419,7 @@ pub const tty = @import("io/tty.zig");
419/// A Writer that doesn't write to anything.419/// A Writer that doesn't write to anything.
420pub const null_writer: NullWriter = .{ .context = {} };420pub const null_writer: NullWriter = .{ .context = {} };
421421
422const NullWriter = Writer(void, error{}, dummyWrite);422pub const NullWriter = Writer(void, error{}, dummyWrite);
423fn dummyWrite(context: void, data: []const u8) error{}!usize {423fn dummyWrite(context: void, data: []const u8) error{}!usize {
424 _ = context;424 _ = context;
425 return data.len;425 return data.len;
lib/std/leb128.zig+35-20
...@@ -36,10 +36,14 @@ pub fn readUleb128(comptime T: type, reader: anytype) !T {...@@ -36,10 +36,14 @@ pub fn readUleb128(comptime T: type, reader: anytype) !T {
36pub const readULEB128 = readUleb128;36pub const readULEB128 = readUleb128;
3737
38/// Write a single unsigned integer as unsigned LEB128 to the given writer.38/// Write a single unsigned integer as unsigned LEB128 to the given writer.
39pub fn writeUleb128(writer: anytype, uint_value: anytype) !void {39pub fn writeUleb128(writer: anytype, arg: anytype) !void {
40 const T = @TypeOf(uint_value);40 const Arg = @TypeOf(arg);
41 const U = if (@typeInfo(T).Int.bits < 8) u8 else T;41 const Int = switch (Arg) {
42 var value: U = @intCast(uint_value);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
44 while (true) {48 while (true) {
45 const byte: u8 = @truncate(value & 0x7f);49 const byte: u8 = @truncate(value & 0x7f);
...@@ -118,16 +122,19 @@ pub fn readIleb128(comptime T: type, reader: anytype) !T {...@@ -118,16 +122,19 @@ pub fn readIleb128(comptime T: type, reader: anytype) !T {
118pub const readILEB128 = readIleb128;122pub const readILEB128 = readIleb128;
119123
120/// Write a single signed integer as signed LEB128 to the given writer.124/// Write a single signed integer as signed LEB128 to the given writer.
121pub fn writeIleb128(writer: anytype, int_value: anytype) !void {125pub fn writeIleb128(writer: anytype, arg: anytype) !void {
122 const T = @TypeOf(int_value);126 const Arg = @TypeOf(arg);
123 const S = if (@typeInfo(T).Int.bits < 8) i8 else T;127 const Int = switch (Arg) {
124 const U = std.meta.Int(.unsigned, @typeInfo(S).Int.bits);128 comptime_int => std.math.IntFittingRange(-arg - 1, arg),
125129 else => Arg,
126 var value: S = @intCast(int_value);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
128 while (true) {135 while (true) {
129 const uvalue: U = @bitCast(value);136 const unsigned: Unsigned = @bitCast(value);
130 const byte: u8 = @truncate(uvalue);137 const byte: u8 = @truncate(unsigned);
131 value >>= 6;138 value >>= 6;
132 if (value == -1 or value == 0) {139 if (value == -1 or value == 0) {
133 try writer.writeByte(byte & 0x7F);140 try writer.writeByte(byte & 0x7F);
...@@ -147,17 +154,25 @@ pub fn writeIleb128(writer: anytype, int_value: anytype) !void {...@@ -147,17 +154,25 @@ pub fn writeIleb128(writer: anytype, int_value: anytype) !void {
147/// "relocatable", meaning that it becomes possible to later go back and patch the number to be a154/// "relocatable", meaning that it becomes possible to later go back and patch the number to be a
148/// different value without shifting all the following code.155/// different value without shifting all the following code.
149pub fn writeUnsignedFixed(comptime l: usize, ptr: *[l]u8, int: std.meta.Int(.unsigned, l * 7)) void {156pub fn writeUnsignedFixed(comptime l: usize, ptr: *[l]u8, int: std.meta.Int(.unsigned, l * 7)) void {
150 const T = @TypeOf(int);157 writeUnsignedExtended(ptr, int);
151 const U = if (@typeInfo(T).Int.bits < 8) u8 else T;158}
152 var value: U = @intCast(int);
153159
154 comptime var i = 0;160/// Same as `writeUnsignedFixed` but with a runtime-known length.
155 inline while (i < (l - 1)) : (i += 1) {161/// Asserts `slice.len > 0`.
156 const byte = @as(u8, @truncate(value)) | 0b1000_0000;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);
157 value >>= 7;173 value >>= 7;
158 ptr[i] = byte;
159 }174 }
160 ptr[i] = @truncate(value);175 slice[slice.len - 1] = @as(u7, @intCast(value));
161}176}
162177
163/// Deprecated: use `writeIleb128`178/// Deprecated: use `writeIleb128`
lib/std/math/big/int.zig+7-3
...@@ -2092,6 +2092,12 @@ pub const Const = struct {...@@ -2092,6 +2092,12 @@ pub const Const = struct {
2092 return bits;2092 return bits;
2093 }2093 }
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
2095 /// @popCount with two's complement semantics.2101 /// @popCount with two's complement semantics.
2096 ///2102 ///
2097 /// This returns the number of 1 bits set when the value would be represented in2103 /// This returns the number of 1 bits set when the value would be represented in
...@@ -2147,9 +2153,7 @@ pub const Const = struct {...@@ -2147,9 +2153,7 @@ pub const Const = struct {
2147 if (signedness == .unsigned and !self.positive) {2153 if (signedness == .unsigned and !self.positive) {
2148 return false;2154 return false;
2149 }2155 }
21502156 return bit_count >= self.bitCountTwosCompForSignedness(signedness);
2151 const req_bits = self.bitCountTwosComp() + @intFromBool(self.positive and signedness == .signed);
2152 return bit_count >= req_bits;
2153 }2157 }
21542158
2155 /// Returns whether self can fit into an integer of the requested type.2159 /// 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 {...@@ -128,7 +128,7 @@ pub fn alignAllocLen(full_len: usize, alloc_len: usize, len_align: u29) usize {
128 assert(full_len >= alloc_len);128 assert(full_len >= alloc_len);
129 if (len_align == 0)129 if (len_align == 0)
130 return alloc_len;130 return alloc_len;
131 const adjusted = alignBackwardAnyAlign(full_len, len_align);131 const adjusted = alignBackwardAnyAlign(usize, full_len, len_align);
132 assert(adjusted >= alloc_len);132 assert(adjusted >= alloc_len);
133 return adjusted;133 return adjusted;
134}134}
...@@ -4312,6 +4312,15 @@ test "sliceAsBytes preserves pointer attributes" {...@@ -4312,6 +4312,15 @@ test "sliceAsBytes preserves pointer attributes" {
4312 try testing.expectEqual(in.alignment, out.alignment);4312 try testing.expectEqual(in.alignment, out.alignment);
4313}4313}
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
4315/// Round an address up to the next (or current) aligned address.4324/// Round an address up to the next (or current) aligned address.
4316/// The alignment must be a power of 2 and greater than 0.4325/// The alignment must be a power of 2 and greater than 0.
4317/// Asserts that rounding up the address does not cause integer overflow.4326/// Asserts that rounding up the address does not cause integer overflow.
...@@ -4433,11 +4442,11 @@ test alignForward {...@@ -4433,11 +4442,11 @@ test alignForward {
44334442
4434/// Round an address down to the previous (or current) aligned address.4443/// Round an address down to the previous (or current) aligned address.
4435/// Unlike `alignBackward`, `alignment` can be any positive number, not just a power of 2.4444/// Unlike `alignBackward`, `alignment` can be any positive number, not just a power of 2.
4436pub fn alignBackwardAnyAlign(i: usize, alignment: usize) usize {4445pub fn alignBackwardAnyAlign(comptime T: type, addr: T, alignment: T) T {
4437 if (isValidAlign(alignment))4446 if (isValidAlignGeneric(T, alignment))
4438 return alignBackward(usize, i, alignment);4447 return alignBackward(T, addr, alignment);
4439 assert(alignment != 0);4448 assert(alignment != 0);
4440 return i - @mod(i, alignment);4449 return addr - @mod(addr, alignment);
4441}4450}
44424451
4443/// Round an address down to the previous (or current) aligned address.4452/// Round an address down to the previous (or current) aligned address.
lib/std/zig/AstGen.zig+4-1
...@@ -4405,7 +4405,6 @@ fn globalVarDecl(...@@ -4405,7 +4405,6 @@ fn globalVarDecl(
4405 .decl_line = astgen.source_line,4405 .decl_line = astgen.source_line,
4406 .astgen = astgen,4406 .astgen = astgen,
4407 .is_comptime = true,4407 .is_comptime = true,
4408 .anon_name_strategy = .parent,
4409 .instructions = gz.instructions,4408 .instructions = gz.instructions,
4410 .instructions_top = gz.instructions.items.len,4409 .instructions_top = gz.instructions.items.len,
4411 };4410 };
...@@ -4463,6 +4462,8 @@ fn globalVarDecl(...@@ -4463,6 +4462,8 @@ fn globalVarDecl(
4463 else4462 else
4464 .none;4463 .none;
44654464
4465 block_scope.anon_name_strategy = .parent;
4466
4466 const init_inst = try expr(4467 const init_inst = try expr(
4467 &block_scope,4468 &block_scope,
4468 &block_scope.base,4469 &block_scope.base,
...@@ -4490,6 +4491,8 @@ fn globalVarDecl(...@@ -4490,6 +4491,8 @@ fn globalVarDecl(
4490 // Extern variable which has an explicit type.4491 // Extern variable which has an explicit type.
4491 const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node);4492 const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node);
44924493
4494 block_scope.anon_name_strategy = .parent;
4495
4493 const var_inst = try block_scope.addVar(.{4496 const var_inst = try block_scope.addVar(.{
4494 .var_type = type_inst,4497 .var_type = type_inst,
4495 .lib_name = lib_name,4498 .lib_name = lib_name,
src/Compilation.zig+10
...@@ -363,6 +363,7 @@ const Job = union(enum) {...@@ -363,6 +363,7 @@ const Job = union(enum) {
363 /// It must be deinited when the job is processed.363 /// It must be deinited when the job is processed.
364 air: Air,364 air: Air,
365 },365 },
366 codegen_type: InternPool.Index,
366 /// The `Cau` must be semantically analyzed (and possibly export itself).367 /// The `Cau` must be semantically analyzed (and possibly export itself).
367 /// This may be its first time being analyzed, or it may be outdated.368 /// This may be its first time being analyzed, or it may be outdated.
368 analyze_cau: InternPool.Cau.Index,369 analyze_cau: InternPool.Cau.Index,
...@@ -423,6 +424,7 @@ const CodegenJob = union(enum) {...@@ -423,6 +424,7 @@ const CodegenJob = union(enum) {
423 /// It must be deinited when the job is processed.424 /// It must be deinited when the job is processed.
424 air: Air,425 air: Air,
425 },426 },
427 type: InternPool.Index,
426};428};
427429
428pub const CObject = struct {430pub const CObject = struct {
...@@ -3712,6 +3714,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3712,6 +3714,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3712 .air = func.air,3714 .air = func.air,
3713 } });3715 } });
3714 },3716 },
3717 .codegen_type => |ty| try comp.queueCodegenJob(tid, .{ .type = ty }),
3715 .analyze_func => |func| {3718 .analyze_func => |func| {
3716 const named_frame = tracy.namedFrame("analyze_func");3719 const named_frame = tracy.namedFrame("analyze_func");
3717 defer named_frame.end();3720 defer named_frame.end();
...@@ -4001,6 +4004,13 @@ fn processOneCodegenJob(tid: usize, comp: *Compilation, codegen_job: CodegenJob)...@@ -4001,6 +4004,13 @@ fn processOneCodegenJob(tid: usize, comp: *Compilation, codegen_job: CodegenJob)
4001 // This call takes ownership of `func.air`.4004 // This call takes ownership of `func.air`.
4002 try pt.linkerUpdateFunc(func.func, func.air);4005 try pt.linkerUpdateFunc(func.func, func.air);
4003 },4006 },
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 },
4004 }4014 }
4005}4015}
40064016
src/InternPool.zig+1-1
...@@ -4003,7 +4003,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {...@@ -4003,7 +4003,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
4003 }4003 }
4004}4004}
40054005
4006const LoadedEnumType = struct {4006pub const LoadedEnumType = struct {
4007 // TODO: the non-fqn will be needed by the new dwarf structure4007 // TODO: the non-fqn will be needed by the new dwarf structure
4008 /// The name of this enum type.4008 /// The name of this enum type.
4009 name: NullTerminatedString,4009 name: NullTerminatedString,
src/Sema.zig+35
...@@ -2845,6 +2845,11 @@ fn zirStructDecl(...@@ -2845,6 +2845,11 @@ fn zirStructDecl(
2845 try pt.scanNamespace(new_namespace_index, decls);2845 try pt.scanNamespace(new_namespace_index, decls);
28462846
2847 try mod.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });2847 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 }
2848 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index }));2853 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index }));
2849 try sema.declareDependency(.{ .interned = wip_ty.index });2854 try sema.declareDependency(.{ .interned = wip_ty.index });
2850 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));2855 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
...@@ -3213,6 +3218,11 @@ fn zirEnumDecl(...@@ -3213,6 +3218,11 @@ fn zirEnumDecl(
3213 }3218 }
3214 }3219 }
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 }
3216 return Air.internedToRef(wip_ty.index);3226 return Air.internedToRef(wip_ty.index);
3217}3227}
32183228
...@@ -3323,6 +3333,11 @@ fn zirUnionDecl(...@@ -3323,6 +3333,11 @@ fn zirUnionDecl(
3323 try pt.scanNamespace(new_namespace_index, decls);3333 try pt.scanNamespace(new_namespace_index, decls);
33243334
3325 try mod.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });3335 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 }
3326 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index }));3341 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index }));
3327 try sema.declareDependency(.{ .interned = wip_ty.index });3342 try sema.declareDependency(.{ .interned = wip_ty.index });
3328 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));3343 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
...@@ -3396,6 +3411,11 @@ fn zirOpaqueDecl(...@@ -3396,6 +3411,11 @@ fn zirOpaqueDecl(
3396 const decls = sema.code.bodySlice(extra_index, decls_len);3411 const decls = sema.code.bodySlice(extra_index, decls_len);
3397 try pt.scanNamespace(new_namespace_index, decls);3412 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 }
3399 return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index));3419 return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index));
3400}3420}
34013421
...@@ -22071,6 +22091,11 @@ fn reifyEnum(...@@ -22071,6 +22091,11 @@ fn reifyEnum(
22071 return sema.fail(block, src, "non-exhaustive enum specified every value", .{});22091 return sema.fail(block, src, "non-exhaustive enum specified every value", .{});
22072 }22092 }
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 }
22074 return Air.internedToRef(wip_ty.index);22099 return Air.internedToRef(wip_ty.index);
22075}22100}
2207622101
...@@ -22318,6 +22343,11 @@ fn reifyUnion(...@@ -22318,6 +22343,11 @@ fn reifyUnion(
22318 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);22343 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
2231922344
22320 try mod.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });22345 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 }
22321 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index }));22351 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index }));
22322 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));22352 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
22323}22353}
...@@ -22591,6 +22621,11 @@ fn reifyStruct(...@@ -22591,6 +22621,11 @@ fn reifyStruct(
22591 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);22621 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
2259222622
22593 try mod.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });22623 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 }
22594 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index }));22629 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index }));
22595 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));22630 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
22596}22631}
src/Type.zig+1-1
...@@ -2208,7 +2208,7 @@ pub fn errorSetHasField(ty: Type, name: []const u8, mod: *Module) bool {...@@ -2208,7 +2208,7 @@ pub fn errorSetHasField(ty: Type, name: []const u8, mod: *Module) bool {
2208 const field_name_interned = ip.getString(name).unwrap() orelse return false;2208 const field_name_interned = ip.getString(name).unwrap() orelse return false;
2209 return error_set_type.nameIndex(ip, field_name_interned) != null;2209 return error_set_type.nameIndex(ip, field_name_interned) != null;
2210 },2210 },
2211 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {2211 .inferred_error_set_type => |i| switch (ip.funcIesResolvedUnordered(i)) {
2212 .anyerror_type => true,2212 .anyerror_type => true,
2213 .none => false,2213 .none => false,
2214 else => |t| {2214 else => |t| {
src/Zcu.zig+9-1
...@@ -2737,7 +2737,7 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit...@@ -2737,7 +2737,7 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit
27372737
2738pub fn errorSetBits(mod: *Zcu) u16 {2738pub fn errorSetBits(mod: *Zcu) u16 {
2739 if (mod.error_limit == 0) return 0;2739 if (mod.error_limit == 0) return 0;
2740 return std.math.log2_int_ceil(ErrorInt, mod.error_limit + 1); // +1 for no error2740 return @as(u16, std.math.log2_int(ErrorInt, mod.error_limit)) + 1;
2741}2741}
27422742
2743pub fn errNote(2743pub fn errNote(
...@@ -3005,6 +3005,14 @@ pub const UnionLayout = struct {...@@ -3005,6 +3005,14 @@ pub const UnionLayout = struct {
3005 tag_align: Alignment,3005 tag_align: Alignment,
3006 tag_size: u64,3006 tag_size: u64,
3007 padding: u32,3007 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 }
3008};3016};
30093017
3010/// Returns the index of the active field, given the current tag value3018/// Returns the index of the active field, given the current tag value
src/Zcu/PerThread.zig+25-1
...@@ -911,6 +911,11 @@ fn createFileRootStruct(...@@ -911,6 +911,11 @@ fn createFileRootStruct(
911911
912 try pt.scanNamespace(namespace_index, decls);912 try pt.scanNamespace(namespace_index, decls);
913 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });913 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 }
914 zcu.setFileRootType(file_index, wip_ty.index);919 zcu.setFileRootType(file_index, wip_ty.index);
915 return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index);920 return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index);
916}921}
...@@ -1332,7 +1337,10 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {...@@ -1332,7 +1337,10 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
1332 // to the `codegen_nav` job.1337 // to the `codegen_nav` job.
1333 try decl_ty.resolveFully(pt);1338 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
1337 try zcu.comp.queueJob(.{ .codegen_nav = nav_index });1345 try zcu.comp.queueJob(.{ .codegen_nav = nav_index });
1338 }1346 }
...@@ -2588,6 +2596,22 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void...@@ -2588,6 +2596,22 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void
2588 }2596 }
2589}2597}
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
2591pub fn reportRetryableAstGenError(2615pub fn reportRetryableAstGenError(
2592 pt: Zcu.PerThread,2616 pt: Zcu.PerThread,
2593 src: Zcu.AstGenSrc,2617 src: Zcu.AstGenSrc,
src/arch/aarch64/CodeGen.zig+20-31
...@@ -18,7 +18,6 @@ const ErrorMsg = Zcu.ErrorMsg;...@@ -18,7 +18,6 @@ const ErrorMsg = Zcu.ErrorMsg;
18const Target = std.Target;18const Target = std.Target;
19const Allocator = mem.Allocator;19const Allocator = mem.Allocator;
20const trace = @import("../../tracy.zig").trace;20const trace = @import("../../tracy.zig").trace;
21const DW = std.dwarf;
22const leb128 = std.leb;21const leb128 = std.leb;
23const log = std.log.scoped(.codegen);22const log = std.log.scoped(.codegen);
24const build_options = @import("build_options");23const build_options = @import("build_options");
...@@ -181,11 +180,11 @@ const DbgInfoReloc = struct {...@@ -181,11 +180,11 @@ const DbgInfoReloc = struct {
181 }180 }
182 }181 }
183182
184 fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void {183 fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
185 switch (function.debug_output) {184 switch (function.debug_output) {
186 .dwarf => |dw| {185 .dwarf => |dw| {
187 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (reloc.mcv) {186 const loc: link.File.Dwarf.Loc = switch (reloc.mcv) {
188 .register => |reg| .{ .register = reg.dwarfLocOp() },187 .register => |reg| .{ .reg = reg.dwarfNum() },
189 .stack_offset,188 .stack_offset,
190 .stack_argument_offset,189 .stack_argument_offset,
191 => |offset| blk: {190 => |offset| blk: {
...@@ -194,15 +193,15 @@ const DbgInfoReloc = struct {...@@ -194,15 +193,15 @@ const DbgInfoReloc = struct {
194 .stack_argument_offset => @as(i32, @intCast(function.saved_regs_stack_space + offset)),193 .stack_argument_offset => @as(i32, @intCast(function.saved_regs_stack_space + offset)),
195 else => unreachable,194 else => unreachable,
196 };195 };
197 break :blk .{ .stack = .{196 break :blk .{ .plus = .{
198 .fp_register = Register.x29.dwarfLocOpDeref(),197 &.{ .breg = Register.x29.dwarfNum() },
199 .offset = adjusted_offset,198 &.{ .consts = adjusted_offset },
200 } };199 } };
201 },200 },
202 else => unreachable, // not a possible argument201 else => unreachable, // not a possible argument
203202
204 };203 };
205 try dw.genArgDbgInfo(reloc.name, reloc.ty, function.owner_nav, loc);204 try dw.genVarDebugInfo(.local_arg, reloc.name, reloc.ty, loc);
206 },205 },
207 .plan9 => {},206 .plan9 => {},
208 .none => {},207 .none => {},
...@@ -210,16 +209,10 @@ const DbgInfoReloc = struct {...@@ -210,16 +209,10 @@ const DbgInfoReloc = struct {
210 }209 }
211210
212 fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void {211 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
219 switch (function.debug_output) {212 switch (function.debug_output) {
220 .dwarf => |dw| {213 .dwarf => |dwarf| {
221 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (reloc.mcv) {214 const loc: link.File.Dwarf.Loc = switch (reloc.mcv) {
222 .register => |reg| .{ .register = reg.dwarfLocOp() },215 .register => |reg| .{ .reg = reg.dwarfNum() },
223 .ptr_stack_offset,216 .ptr_stack_offset,
224 .stack_offset,217 .stack_offset,
225 .stack_argument_offset,218 .stack_argument_offset,
...@@ -231,24 +224,20 @@ const DbgInfoReloc = struct {...@@ -231,24 +224,20 @@ const DbgInfoReloc = struct {
231 .stack_argument_offset => @as(i32, @intCast(function.saved_regs_stack_space + offset)),224 .stack_argument_offset => @as(i32, @intCast(function.saved_regs_stack_space + offset)),
232 else => unreachable,225 else => unreachable,
233 };226 };
234 break :blk .{227 break :blk .{ .plus = .{
235 .stack = .{228 &.{ .reg = Register.x29.dwarfNum() },
236 .fp_register = Register.x29.dwarfLocOpDeref(),229 &.{ .consts = adjusted_offset },
237 .offset = adjusted_offset,230 } };
238 },
239 };
240 },231 },
241 .memory => |address| .{ .memory = address },232 .memory => |address| .{ .constu = address },
242 .linker_load => |linker_load| .{ .linker_load = linker_load },233 .immediate => |x| .{ .constu = x },
243 .immediate => |x| .{ .immediate = x },234 .none => .empty,
244 .undef => .undef,
245 .none => .none,
246 else => blk: {235 else => blk: {
247 log.debug("TODO generate debug info for {}", .{reloc.mcv});236 log.debug("TODO generate debug info for {}", .{reloc.mcv});
248 break :blk .nop;237 break :blk .empty;
249 },238 },
250 };239 };
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);
252 },241 },
253 .plan9 => {},242 .plan9 => {},
254 .none => {},243 .none => {},
...@@ -6207,7 +6196,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {...@@ -6207,7 +6196,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
6207 .memory => |addr| .{ .memory = addr },6196 .memory => |addr| .{ .memory = addr },
6208 .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },6197 .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },
6209 .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } },6198 .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } },
6210 .load_symbol, .load_tlv, .lea_symbol => unreachable, // TODO6199 .load_symbol, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO
6211 },6200 },
6212 .fail => |msg| {6201 .fail => |msg| {
6213 self.err_msg = msg;6202 self.err_msg = msg;
src/arch/aarch64/bits.zig+2-10
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const DW = std.dwarf;
4const assert = std.debug.assert;3const assert = std.debug.assert;
5const testing = std.testing;4const testing = std.testing;
65
...@@ -295,15 +294,8 @@ pub const Register = enum(u8) {...@@ -295,15 +294,8 @@ pub const Register = enum(u8) {
295 };294 };
296 }295 }
297296
298 pub fn dwarfLocOp(self: Register) u8 {297 pub fn dwarfNum(self: Register) u5 {
299 return @as(u8, self.enc()) + DW.OP.reg0;298 return self.enc();
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;
307 }299 }
308};300};
309301
src/arch/arm/CodeGen.zig+18-26
...@@ -18,7 +18,6 @@ const ErrorMsg = Zcu.ErrorMsg;...@@ -18,7 +18,6 @@ const ErrorMsg = Zcu.ErrorMsg;
18const Target = std.Target;18const Target = std.Target;
19const Allocator = mem.Allocator;19const Allocator = mem.Allocator;
20const trace = @import("../../tracy.zig").trace;20const trace = @import("../../tracy.zig").trace;
21const DW = std.dwarf;
22const leb128 = std.leb;21const leb128 = std.leb;
23const log = std.log.scoped(.codegen);22const log = std.log.scoped(.codegen);
24const build_options = @import("build_options");23const build_options = @import("build_options");
...@@ -259,11 +258,11 @@ const DbgInfoReloc = struct {...@@ -259,11 +258,11 @@ const DbgInfoReloc = struct {
259 }258 }
260 }259 }
261260
262 fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void {261 fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
263 switch (function.debug_output) {262 switch (function.debug_output) {
264 .dwarf => |dw| {263 .dwarf => |dw| {
265 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (reloc.mcv) {264 const loc: link.File.Dwarf.Loc = switch (reloc.mcv) {
266 .register => |reg| .{ .register = reg.dwarfLocOp() },265 .register => |reg| .{ .reg = reg.dwarfNum() },
267 .stack_offset,266 .stack_offset,
268 .stack_argument_offset,267 .stack_argument_offset,
269 => blk: {268 => blk: {
...@@ -272,15 +271,15 @@ const DbgInfoReloc = struct {...@@ -272,15 +271,15 @@ const DbgInfoReloc = struct {
272 .stack_argument_offset => |offset| @as(i32, @intCast(function.saved_regs_stack_space + offset)),271 .stack_argument_offset => |offset| @as(i32, @intCast(function.saved_regs_stack_space + offset)),
273 else => unreachable,272 else => unreachable,
274 };273 };
275 break :blk .{ .stack = .{274 break :blk .{ .plus = .{
276 .fp_register = DW.OP.breg11,275 &.{ .reg = 11 },
277 .offset = adjusted_stack_offset,276 &.{ .consts = adjusted_stack_offset },
278 } };277 } };
279 },278 },
280 else => unreachable, // not a possible argument279 else => unreachable, // not a possible argument
281 };280 };
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);
284 },283 },
285 .plan9 => {},284 .plan9 => {},
286 .none => {},285 .none => {},
...@@ -288,16 +287,10 @@ const DbgInfoReloc = struct {...@@ -288,16 +287,10 @@ const DbgInfoReloc = struct {
288 }287 }
289288
290 fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void {289 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
297 switch (function.debug_output) {290 switch (function.debug_output) {
298 .dwarf => |dw| {291 .dwarf => |dw| {
299 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (reloc.mcv) {292 const loc: link.File.Dwarf.Loc = switch (reloc.mcv) {
300 .register => |reg| .{ .register = reg.dwarfLocOp() },293 .register => |reg| .{ .reg = reg.dwarfNum() },
301 .ptr_stack_offset,294 .ptr_stack_offset,
302 .stack_offset,295 .stack_offset,
303 .stack_argument_offset,296 .stack_argument_offset,
...@@ -309,21 +302,20 @@ const DbgInfoReloc = struct {...@@ -309,21 +302,20 @@ const DbgInfoReloc = struct {
309 .stack_argument_offset => @as(i32, @intCast(function.saved_regs_stack_space + offset)),302 .stack_argument_offset => @as(i32, @intCast(function.saved_regs_stack_space + offset)),
310 else => unreachable,303 else => unreachable,
311 };304 };
312 break :blk .{ .stack = .{305 break :blk .{ .plus = .{
313 .fp_register = DW.OP.breg11,306 &.{ .reg = 11 },
314 .offset = adjusted_offset,307 &.{ .consts = adjusted_offset },
315 } };308 } };
316 },309 },
317 .memory => |address| .{ .memory = address },310 .memory => |address| .{ .constu = address },
318 .immediate => |x| .{ .immediate = x },311 .immediate => |x| .{ .constu = x },
319 .undef => .undef,312 .none => .empty,
320 .none => .none,
321 else => blk: {313 else => blk: {
322 log.debug("TODO generate debug info for {}", .{reloc.mcv});314 log.debug("TODO generate debug info for {}", .{reloc.mcv});
323 break :blk .nop;315 break :blk .empty;
324 },316 },
325 };317 };
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);
327 },319 },
328 .plan9 => {},320 .plan9 => {},
329 .none => {},321 .none => {},
...@@ -6170,7 +6162,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {...@@ -6170,7 +6162,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
6170 .mcv => |mcv| switch (mcv) {6162 .mcv => |mcv| switch (mcv) {
6171 .none => .none,6163 .none => .none,
6172 .undef => .undef,6164 .undef => .undef,
6173 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol => unreachable, // TODO6165 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO
6174 .immediate => |imm| .{ .immediate = @truncate(imm) },6166 .immediate => |imm| .{ .immediate = @truncate(imm) },
6175 .memory => |addr| .{ .memory = addr },6167 .memory => |addr| .{ .memory = addr },
6176 },6168 },
src/arch/arm/bits.zig+4-5
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const DW = std.dwarf;
3const assert = std.debug.assert;2const assert = std.debug.assert;
4const testing = std.testing;3const testing = std.testing;
54
...@@ -158,12 +157,12 @@ pub const Register = enum(u5) {...@@ -158,12 +157,12 @@ pub const Register = enum(u5) {
158157
159 /// Returns the unique 4-bit ID of this register which is used in158 /// Returns the unique 4-bit ID of this register which is used in
160 /// the machine code159 /// the machine code
161 pub fn id(self: Register) u4 {160 pub fn id(reg: Register) u4 {
162 return @as(u4, @truncate(@intFromEnum(self)));161 return @truncate(@intFromEnum(reg));
163 }162 }
164163
165 pub fn dwarfLocOp(self: Register) u8 {164 pub fn dwarfNum(reg: Register) u4 {
166 return @as(u8, self.id()) + DW.OP.reg0;165 return reg.id();
167 }166 }
168};167};
169168
src/arch/riscv64/CodeGen.zig+12-27
...@@ -4677,9 +4677,7 @@ fn genArgDbgInfo(func: Func, inst: Air.Inst.Index, mcv: MCValue) !void {...@@ -4677,9 +4677,7 @@ fn genArgDbgInfo(func: Func, inst: Air.Inst.Index, mcv: MCValue) !void {
46774677
4678 switch (func.debug_output) {4678 switch (func.debug_output) {
4679 .dwarf => |dw| switch (mcv) {4679 .dwarf => |dw| switch (mcv) {
4680 .register => |reg| try dw.genArgDbgInfo(name, ty, func.owner.nav_index, .{4680 .register => |reg| try dw.genVarDebugInfo(.local_arg, name, ty, .{ .reg = reg.dwarfNum() }),
4681 .register = reg.dwarfLocOp(),
4682 }),
4683 .load_frame => {},4681 .load_frame => {},
4684 else => {},4682 else => {},
4685 },4683 },
...@@ -5184,43 +5182,30 @@ fn airDbgVar(func: *Func, inst: Air.Inst.Index) !void {...@@ -5184,43 +5182,30 @@ fn airDbgVar(func: *Func, inst: Air.Inst.Index) !void {
51845182
5185 const name = func.air.nullTerminatedString(pl_op.payload);5183 const name = func.air.nullTerminatedString(pl_op.payload);
51865184
5187 const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)];5185 try func.genVarDbgInfo(ty, mcv, name);
5188 try func.genVarDbgInfo(tag, ty, mcv, name);
51895186
5190 return func.finishAir(inst, .unreach, .{ operand, .none, .none });5187 return func.finishAir(inst, .unreach, .{ operand, .none, .none });
5191}5188}
51925189
5193fn genVarDbgInfo(5190fn genVarDbgInfo(
5194 func: Func,5191 func: Func,
5195 tag: Air.Inst.Tag,
5196 ty: Type,5192 ty: Type,
5197 mcv: MCValue,5193 mcv: MCValue,
5198 name: [:0]const u8,5194 name: []const u8,
5199) !void {5195) !void {
5200 const is_ptr = switch (tag) {
5201 .dbg_var_ptr => true,
5202 .dbg_var_val => false,
5203 else => unreachable,
5204 };
5205
5206 switch (func.debug_output) {5196 switch (func.debug_output) {
5207 .dwarf => |dw| {5197 .dwarf => |dwarf| {
5208 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (mcv) {5198 const loc: link.File.Dwarf.Loc = switch (mcv) {
5209 .register => |reg| .{ .register = reg.dwarfLocOp() },5199 .register => |reg| .{ .reg = reg.dwarfNum() },
5210 .memory => |address| .{ .memory = address },5200 .memory => |address| .{ .constu = address },
5211 .load_symbol => |sym_off| loc: {5201 .immediate => |x| .{ .constu = x },
5212 assert(sym_off.off == 0);5202 .none => .empty,
5213 break :loc .{ .linker_load = .{ .type = .direct, .sym_index = sym_off.sym } };
5214 },
5215 .immediate => |x| .{ .immediate = x },
5216 .undef => .undef,
5217 .none => .none,
5218 else => blk: {5203 else => blk: {
5219 // log.warn("TODO generate debug info for {}", .{mcv});5204 // log.warn("TODO generate debug info for {}", .{mcv});
5220 break :blk .nop;5205 break :blk .empty;
5221 },5206 },
5222 };5207 };
5223 try dw.genVarDbgInfo(name, ty, func.owner.nav_index, is_ptr, loc);5208 try dwarf.genVarDebugInfo(.local_var, name, ty, loc);
5224 },5209 },
5225 .plan9 => {},5210 .plan9 => {},
5226 .none => {},5211 .none => {},
...@@ -8031,7 +8016,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {...@@ -8031,7 +8016,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
8031 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },8016 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
8032 .immediate => |imm| .{ .immediate = imm },8017 .immediate => |imm| .{ .immediate = imm },
8033 .memory => |addr| .{ .memory = addr },8018 .memory => |addr| .{ .memory = addr },
8034 .load_got, .load_direct => {8019 .load_got, .load_direct, .lea_direct => {
8035 return func.fail("TODO: genTypedValue {s}", .{@tagName(mcv)});8020 return func.fail("TODO: genTypedValue {s}", .{@tagName(mcv)});
8036 },8021 },
8037 },8022 },
src/arch/riscv64/bits.zig+2-3
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const DW = std.dwarf;
3const assert = std.debug.assert;2const assert = std.debug.assert;
4const testing = std.testing;3const testing = std.testing;
5const Target = std.Target;4const Target = std.Target;
...@@ -207,8 +206,8 @@ pub const Register = enum(u8) {...@@ -207,8 +206,8 @@ pub const Register = enum(u8) {
207 return @truncate(@intFromEnum(reg));206 return @truncate(@intFromEnum(reg));
208 }207 }
209208
210 pub fn dwarfLocOp(reg: Register) u8 {209 pub fn dwarfNum(reg: Register) u8 {
211 return @as(u8, reg.id());210 return reg.id();
212 }211 }
213212
214 pub fn bitSize(reg: Register, zcu: *const Zcu) u32 {213 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...@@ -3579,18 +3579,15 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
3579}3579}
35803580
3581fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {3581fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
3582 const pt = self.pt;
3583 const mod = pt.zcu;
3584 const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg;3582 const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg;
3585 const ty = arg.ty.toType();3583 const ty = arg.ty.toType();
3586 const owner_nav = mod.funcInfo(self.func_index).owner_nav;
3587 if (arg.name == .none) return;3584 if (arg.name == .none) return;
3588 const name = self.air.nullTerminatedString(@intFromEnum(arg.name));3585 const name = self.air.nullTerminatedString(@intFromEnum(arg.name));
35893586
3590 switch (self.debug_output) {3587 switch (self.debug_output) {
3591 .dwarf => |dw| switch (mcv) {3588 .dwarf => |dw| switch (mcv) {
3592 .register => |reg| try dw.genArgDbgInfo(name, ty, owner_nav, .{3589 .register => |reg| try dw.genVarDebugInfo(.local_arg, name, ty, .{
3593 .register = reg.dwarfLocOp(),3590 .reg = reg.dwarfNum(),
3594 }),3591 }),
3595 else => {},3592 else => {},
3596 },3593 },
...@@ -4127,7 +4124,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {...@@ -4127,7 +4124,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
4127 .mcv => |mcv| switch (mcv) {4124 .mcv => |mcv| switch (mcv) {
4128 .none => .none,4125 .none => .none,
4129 .undef => .undef,4126 .undef => .undef,
4130 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol => unreachable, // TODO4127 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO
4131 .immediate => |imm| .{ .immediate = imm },4128 .immediate => |imm| .{ .immediate = imm },
4132 .memory => |addr| .{ .memory = addr },4129 .memory => |addr| .{ .memory = addr },
4133 },4130 },
src/arch/sparc64/bits.zig+6-7
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const DW = std.dwarf;
3const assert = std.debug.assert;2const assert = std.debug.assert;
4const testing = std.testing;3const testing = std.testing;
54
...@@ -15,17 +14,17 @@ pub const Register = enum(u6) {...@@ -15,17 +14,17 @@ pub const Register = enum(u6) {
15 fp = 62, // frame pointer (i6)14 fp = 62, // frame pointer (i6)
16 // zig fmt: on15 // zig fmt: on
1716
18 pub fn id(self: Register) u5 {17 pub fn id(reg: Register) u5 {
19 return @as(u5, @truncate(@intFromEnum(self)));18 return @truncate(@intFromEnum(reg));
20 }19 }
2120
22 pub fn enc(self: Register) u5 {21 pub fn enc(reg: Register) u5 {
23 // For integer registers, enc() == id().22 // For integer registers, enc() == id().
24 return self.id();23 return reg.id();
25 }24 }
2625
27 pub fn dwarfLocOp(reg: Register) u8 {26 pub fn dwarfNum(reg: Register) u5 {
28 return @as(u8, reg.id()) + DW.OP.reg0;27 return reg.id();
29 }28 }
30};29};
3130
src/arch/wasm/CodeGen.zig+8-7
...@@ -742,7 +742,7 @@ const InnerError = error{...@@ -742,7 +742,7 @@ const InnerError = error{
742 CodegenFail,742 CodegenFail,
743 /// Compiler implementation could not handle a large integer.743 /// Compiler implementation could not handle a large integer.
744 Overflow,744 Overflow,
745};745} || link.File.UpdateDebugInfoError;
746746
747pub fn deinit(func: *CodeGen) void {747pub fn deinit(func: *CodeGen) void {
748 // in case of an error and we still have branches748 // in case of an error and we still have branches
...@@ -2588,8 +2588,8 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2588,8 +2588,8 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2588 const name_nts = func.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;2588 const name_nts = func.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
2589 if (name_nts != .none) {2589 if (name_nts != .none) {
2590 const name = func.air.nullTerminatedString(@intFromEnum(name_nts));2590 const name = func.air.nullTerminatedString(@intFromEnum(name_nts));
2591 try dwarf.genArgDbgInfo(name, arg_ty, func.owner_nav, .{2591 try dwarf.genVarDebugInfo(.local_arg, name, arg_ty, .{
2592 .wasm_local = arg.local.value,2592 .wasm_ext = .{ .local = arg.local.value },
2593 });2593 });
2594 }2594 }
2595 },2595 },
...@@ -6455,6 +6455,7 @@ fn airDbgInlineBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6455,6 +6455,7 @@ fn airDbgInlineBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6455}6455}
64566456
6457fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void {6457fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void {
6458 _ = is_ptr;
6458 if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{});6459 if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{});
64596460
6460 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;6461 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...@@ -6466,14 +6467,14 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void
6466 const name = func.air.nullTerminatedString(pl_op.payload);6467 const name = func.air.nullTerminatedString(pl_op.payload);
6467 log.debug(" var name = ({s})", .{name});6468 log.debug(" var name = ({s})", .{name});
64686469
6469 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (operand) {6470 const loc: link.File.Dwarf.Loc = switch (operand) {
6470 .local => |local| .{ .wasm_local = local.value },6471 .local => |local| .{ .wasm_ext = .{ .local = local.value } },
6471 else => blk: {6472 else => blk: {
6472 log.debug("TODO generate debug info for {}", .{operand});6473 log.debug("TODO generate debug info for {}", .{operand});
6473 break :blk .nop;6474 break :blk .empty;
6474 },6475 },
6475 };6476 };
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
6478 return func.finishAir(inst, .none, &.{});6479 return func.finishAir(inst, .none, &.{});
6479}6480}
src/arch/x86/bits.zig+3-14
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const DW = std.dwarf;
32
4// zig fmt: off3// zig fmt: off
5pub const Register = enum(u8) {4pub const Register = enum(u8) {
...@@ -44,18 +43,8 @@ pub const Register = enum(u8) {...@@ -44,18 +43,8 @@ pub const Register = enum(u8) {
44 return @enumFromInt(@as(u8, self.id()) + 16);43 return @enumFromInt(@as(u8, self.id()) + 16);
45 }44 }
4645
47 pub fn dwarfLocOp(reg: Register) u8 {46 pub fn dwarfNum(reg: Register) u8 {
48 return switch (reg.to32()) {47 return @intFromEnum(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 };
59 }48 }
60};49};
6150
...@@ -64,7 +53,7 @@ pub const Register = enum(u8) {...@@ -64,7 +53,7 @@ pub const Register = enum(u8) {
64/// TODO this set is actually a set of caller-saved registers.53/// TODO this set is actually a set of caller-saved registers.
65pub const callee_preserved_regs = [_]Register{ .eax, .ecx, .edx, .esi, .edi };54pub const callee_preserved_regs = [_]Register{ .eax, .ecx, .edx, .esi, .edi };
6655
67// TODO add these to Register enum and corresponding dwarfLocOp56// TODO add these to Register enum and corresponding dwarfNum
68// // Return Address register. This is stored in `0(%esp, "")` and is not a physical register.57// // Return Address register. This is stored in `0(%esp, "")` and is not a physical register.
69// RA = (8, "RA"),58// RA = (8, "RA"),
70//59//
src/arch/x86_64/CodeGen.zig+183-129
...@@ -18,7 +18,6 @@ const Allocator = mem.Allocator;...@@ -18,7 +18,6 @@ const Allocator = mem.Allocator;
18const CodeGenError = codegen.CodeGenError;18const CodeGenError = codegen.CodeGenError;
19const Compilation = @import("../../Compilation.zig");19const Compilation = @import("../../Compilation.zig");
20const DebugInfoOutput = codegen.DebugInfoOutput;20const DebugInfoOutput = codegen.DebugInfoOutput;
21const DW = std.dwarf;
22const ErrorMsg = Zcu.ErrorMsg;21const ErrorMsg = Zcu.ErrorMsg;
23const Result = codegen.Result;22const Result = codegen.Result;
24const Emit = @import("Emit.zig");23const Emit = @import("Emit.zig");
...@@ -82,6 +81,9 @@ mir_instructions: std.MultiArrayList(Mir.Inst) = .{},...@@ -82,6 +81,9 @@ mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
82/// MIR extra data81/// MIR extra data
83mir_extra: std.ArrayListUnmanaged(u32) = .{},82mir_extra: std.ArrayListUnmanaged(u32) = .{},
8483
84stack_args: std.ArrayListUnmanaged(StackVar) = .{},
85stack_vars: std.ArrayListUnmanaged(StackVar) = .{},
86
85/// Byte offset within the source file of the ending curly.87/// Byte offset within the source file of the ending curly.
86end_di_line: u32,88end_di_line: u32,
87end_di_column: u32,89end_di_column: u32,
...@@ -726,6 +728,12 @@ const InstTracking = struct {...@@ -726,6 +728,12 @@ const InstTracking = struct {
726 }728 }
727};729};
728730
731const StackVar = struct {
732 name: []const u8,
733 type: Type,
734 frame_addr: FrameAddr,
735};
736
729const FrameAlloc = struct {737const FrameAlloc = struct {
730 abi_size: u31,738 abi_size: u31,
731 spill_pad: u3,739 spill_pad: u3,
...@@ -831,6 +839,8 @@ pub fn generate(...@@ -831,6 +839,8 @@ pub fn generate(
831 function.exitlude_jump_relocs.deinit(gpa);839 function.exitlude_jump_relocs.deinit(gpa);
832 function.mir_instructions.deinit(gpa);840 function.mir_instructions.deinit(gpa);
833 function.mir_extra.deinit(gpa);841 function.mir_extra.deinit(gpa);
842 function.stack_args.deinit(gpa);
843 function.stack_vars.deinit(gpa);
834 }844 }
835845
836 wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)});846 wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)});
...@@ -903,14 +913,17 @@ pub fn generate(...@@ -903,14 +913,17 @@ pub fn generate(
903 else => |e| return e,913 else => |e| return e,
904 };914 };
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 = .{
907 .instructions = function.mir_instructions.toOwnedSlice(),920 .instructions = function.mir_instructions.toOwnedSlice(),
908 .extra = try function.mir_extra.toOwnedSlice(gpa),921 .extra = try function.mir_extra.toOwnedSlice(gpa),
909 .frame_locs = function.frame_locs.toOwnedSlice(),922 .frame_locs = function.frame_locs.toOwnedSlice(),
910 };923 };
911 defer mir.deinit(gpa);924 defer mir.deinit(gpa);
912925
913 var emit = Emit{926 var emit: Emit = .{
914 .lower = .{927 .lower = .{
915 .bin_file = bin_file,928 .bin_file = bin_file,
916 .allocator = gpa,929 .allocator = gpa,
...@@ -1956,12 +1969,46 @@ fn gen(self: *Self) InnerError!void {...@@ -1956,12 +1969,46 @@ fn gen(self: *Self) InnerError!void {
1956 });1969 });
1957}1970}
19581971
1972fn checkInvariantsAfterAirInst(self: *Self, inst: Air.Inst.Index, old_air_bookkeeping: @TypeOf(air_bookkeeping_init)) void {
1973 assert(!self.register_manager.lockedRegsExist());
1974
1975 if (std.debug.runtime_safety) {
1976 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
1977 std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, self.air.instructions.items(.tag)[@intFromEnum(inst)] });
1978 }
1979
1980 { // check consistency of tracked registers
1981 var it = self.register_manager.free_registers.iterator(.{ .kind = .unset });
1982 while (it.next()) |index| {
1983 const tracked_inst = self.register_manager.registers[index];
1984 const tracking = self.getResolvedInstValue(tracked_inst);
1985 for (tracking.getRegs()) |reg| {
1986 if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break;
1987 } else unreachable; // tracked register not in use
1988 }
1989 }
1990 }
1991}
1992
1959fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {1993fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1960 const pt = self.pt;1994 const pt = self.pt;
1961 const mod = pt.zcu;1995 const mod = pt.zcu;
1962 const ip = &mod.intern_pool;1996 const ip = &mod.intern_pool;
1963 const air_tags = self.air.instructions.items(.tag);1997 const air_tags = self.air.instructions.items(.tag);
19641998
1999 for (body) |inst| {
2000 wip_mir_log.debug("{}", .{self.fmtAir(inst)});
2001 verbose_tracking_log.debug("{}", .{self.fmtTracking()});
2002
2003 const old_air_bookkeeping = self.air_bookkeeping;
2004 try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1);
2005 switch (air_tags[@intFromEnum(inst)]) {
2006 .arg => try self.airArg(inst),
2007 else => break,
2008 }
2009 self.checkInvariantsAfterAirInst(inst, old_air_bookkeeping);
2010 }
2011
1965 for (body) |inst| {2012 for (body) |inst| {
1966 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue;2013 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue;
1967 wip_mir_log.debug("{}", .{self.fmtAir(inst)});2014 wip_mir_log.debug("{}", .{self.fmtAir(inst)});
...@@ -2041,7 +2088,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -2041,7 +2088,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
20412088
2042 .alloc => try self.airAlloc(inst),2089 .alloc => try self.airAlloc(inst),
2043 .ret_ptr => try self.airRetPtr(inst),2090 .ret_ptr => try self.airRetPtr(inst),
2044 .arg => try self.airArg(inst),2091 .arg => try self.airDbgArg(inst),
2045 .assembly => try self.airAsm(inst),2092 .assembly => try self.airAsm(inst),
2046 .bitcast => try self.airBitCast(inst),2093 .bitcast => try self.airBitCast(inst),
2047 .block => try self.airBlock(inst),2094 .block => try self.airBlock(inst),
...@@ -2205,25 +2252,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -2205,25 +2252,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
2205 .work_group_id => unreachable,2252 .work_group_id => unreachable,
2206 // zig fmt: on2253 // zig fmt: on
2207 }2254 }
22082255 self.checkInvariantsAfterAirInst(inst, old_air_bookkeeping);
2209 assert(!self.register_manager.lockedRegsExist());
2210
2211 if (std.debug.runtime_safety) {
2212 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
2213 std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, air_tags[@intFromEnum(inst)] });
2214 }
2215
2216 { // check consistency of tracked registers
2217 var it = self.register_manager.free_registers.iterator(.{ .kind = .unset });
2218 while (it.next()) |index| {
2219 const tracked_inst = self.register_manager.registers[index];
2220 const tracking = self.getResolvedInstValue(tracked_inst);
2221 for (tracking.getRegs()) |reg| {
2222 if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break;
2223 } else unreachable; // tracked register not in use
2224 }
2225 }
2226 }
2227 }2256 }
2228 verbose_tracking_log.debug("{}", .{self.fmtTracking()});2257 verbose_tracking_log.debug("{}", .{self.fmtTracking()});
2229}2258}
...@@ -2338,7 +2367,7 @@ fn finishAirBookkeeping(self: *Self) void {...@@ -2338,7 +2367,7 @@ fn finishAirBookkeeping(self: *Self) void {
2338}2367}
23392368
2340fn finishAirResult(self: *Self, inst: Air.Inst.Index, result: MCValue) void {2369fn finishAirResult(self: *Self, inst: Air.Inst.Index, result: MCValue) void {
2341 if (self.liveness.isUnused(inst)) switch (result) {2370 if (self.liveness.isUnused(inst) and self.air.instructions.items(.tag)[@intFromEnum(inst)] != .arg) switch (result) {
2342 .none, .dead, .unreach => {},2371 .none, .dead, .unreach => {},
2343 else => unreachable, // Why didn't the result die?2372 else => unreachable, // Why didn't the result die?
2344 } else {2373 } else {
...@@ -2425,7 +2454,7 @@ fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayo...@@ -2425,7 +2454,7 @@ fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayo
2425 const callee_preserved_regs =2454 const callee_preserved_regs =
2426 abi.getCalleePreservedRegs(abi.resolveCallingConvention(cc, self.target.*));2455 abi.getCalleePreservedRegs(abi.resolveCallingConvention(cc, self.target.*));
2427 for (callee_preserved_regs) |reg| {2456 for (callee_preserved_regs) |reg| {
2428 if (self.register_manager.isRegAllocated(reg) or true) {2457 if (self.register_manager.isRegAllocated(reg)) {
2429 save_reg_list.push(callee_preserved_regs, reg);2458 save_reg_list.push(callee_preserved_regs, reg);
2430 }2459 }
2431 }2460 }
...@@ -5985,10 +6014,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -5985,10 +6014,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
5985 switch (operand) {6014 switch (operand) {
5986 .load_frame => |frame_addr| {6015 .load_frame => |frame_addr| {
5987 if (tag_abi_size <= 8) {6016 if (tag_abi_size <= 8) {
5988 const off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))6017 const off: i32 = @intCast(layout.tagOffset());
5989 @intCast(layout.payload_size)
5990 else
5991 0;
5992 break :blk try self.copyToRegisterWithInstTracking(inst, tag_ty, .{6018 break :blk try self.copyToRegisterWithInstTracking(inst, tag_ty, .{
5993 .load_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off },6019 .load_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off },
5994 });6020 });
...@@ -6000,10 +6026,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -6000,10 +6026,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
6000 );6026 );
6001 },6027 },
6002 .register => {6028 .register => {
6003 const shift: u6 = if (layout.tag_align.compare(.lt, layout.payload_align))6029 const shift: u6 = @intCast(layout.tagOffset() * 8);
6004 @intCast(layout.payload_size * 8)
6005 else
6006 0;
6007 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);6030 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
6008 try self.genShiftBinOpMir(6031 try self.genShiftBinOpMir(
6009 .{ ._r, .sh },6032 .{ ._r, .sh },
...@@ -11813,30 +11836,30 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -11813,30 +11836,30 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
1181311836
11814fn airArg(self: *Self, inst: Air.Inst.Index) !void {11837fn airArg(self: *Self, inst: Air.Inst.Index) !void {
11815 const pt = self.pt;11838 const pt = self.pt;
11816 const mod = pt.zcu;11839 const zcu = pt.zcu;
11817 // skip zero-bit arguments as they don't have a corresponding arg instruction11840 // skip zero-bit arguments as they don't have a corresponding arg instruction
11818 var arg_index = self.arg_index;11841 var arg_index = self.arg_index;
11819 while (self.args[arg_index] == .none) arg_index += 1;11842 while (self.args[arg_index] == .none) arg_index += 1;
11820 self.arg_index = arg_index + 1;11843 self.arg_index = arg_index + 1;
1182111844
11822 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {11845 const result: MCValue = if (self.debug_output == .none and self.liveness.isUnused(inst)) .unreach else result: {
11823 const arg_ty = self.typeOfIndex(inst);11846 const arg_ty = self.typeOfIndex(inst);
11824 const src_mcv = self.args[arg_index];11847 const src_mcv = self.args[arg_index];
11825 const dst_mcv = switch (src_mcv) {11848 switch (src_mcv) {
11826 .register, .register_pair, .load_frame => dst: {11849 .register, .register_pair, .load_frame => {
11827 for (src_mcv.getRegs()) |reg| self.register_manager.getRegAssumeFree(reg, inst);11850 for (src_mcv.getRegs()) |reg| self.register_manager.getRegAssumeFree(reg, inst);
11828 break :dst src_mcv;11851 break :result src_mcv;
11829 },11852 },
11830 .indirect => |reg_off| dst: {11853 .indirect => |reg_off| {
11831 self.register_manager.getRegAssumeFree(reg_off.reg, inst);11854 self.register_manager.getRegAssumeFree(reg_off.reg, inst);
11832 const dst_mcv = try self.allocRegOrMem(inst, false);11855 const dst_mcv = try self.allocRegOrMem(inst, false);
11833 try self.genCopy(arg_ty, dst_mcv, src_mcv, .{});11856 try self.genCopy(arg_ty, dst_mcv, src_mcv, .{});
11834 break :dst dst_mcv;11857 break :result dst_mcv;
11835 },11858 },
11836 .elementwise_regs_then_frame => |regs_frame_addr| dst: {11859 .elementwise_regs_then_frame => |regs_frame_addr| {
11837 try self.spillEflagsIfOccupied();11860 try self.spillEflagsIfOccupied();
1183811861
11839 const fn_info = mod.typeToFunc(self.fn_type).?;11862 const fn_info = zcu.typeToFunc(self.fn_type).?;
11840 const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*);11863 const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*);
11841 const param_int_regs = abi.getCAbiIntParamRegs(cc);11864 const param_int_regs = abi.getCAbiIntParamRegs(cc);
11842 var prev_reg: Register = undefined;11865 var prev_reg: Register = undefined;
...@@ -11913,99 +11936,99 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -11913,99 +11936,99 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
11913 try self.asmRegisterImmediate(11936 try self.asmRegisterImmediate(
11914 .{ ._, .cmp },11937 .{ ._, .cmp },
11915 index_reg.to32(),11938 index_reg.to32(),
11916 Immediate.u(arg_ty.vectorLen(mod)),11939 Immediate.u(arg_ty.vectorLen(zcu)),
11917 );11940 );
11918 _ = try self.asmJccReloc(.b, loop);11941 _ = try self.asmJccReloc(.b, loop);
1191911942
11920 break :dst dst_mcv;11943 break :result dst_mcv;
11921 },11944 },
11922 else => return self.fail("TODO implement arg for {}", .{src_mcv}),11945 else => return self.fail("TODO implement arg for {}", .{src_mcv}),
11923 };
11924
11925 const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
11926 switch (name_nts) {
11927 .none => {},
11928 _ => try self.genArgDbgInfo(arg_ty, self.air.nullTerminatedString(@intFromEnum(name_nts)), src_mcv),
11929 }11946 }
11930
11931 break :result dst_mcv;
11932 };11947 };
11933 return self.finishAir(inst, result, .{ .none, .none, .none });11948 return self.finishAir(inst, result, .{ .none, .none, .none });
11934}11949}
1193511950
11936fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {11951fn airDbgArg(self: *Self, inst: Air.Inst.Index) !void {
11937 switch (self.debug_output) {11952 defer self.finishAirBookkeeping();
11938 .dwarf => |dw| {11953 if (self.debug_output == .none) return;
11939 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (mcv) {11954 const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
11940 .register => |reg| .{ .register = reg.dwarfNum() },11955 const name = self.air.nullTerminatedString(@intFromEnum(name_nts));
11941 .register_pair => |regs| .{ .register_pair = .{11956 if (name.len > 0) {
11942 regs[0].dwarfNum(), regs[1].dwarfNum(),11957 const arg_ty = self.typeOfIndex(inst);
11943 } },11958 const arg_mcv = self.getResolvedInstValue(inst).short;
11944 // TODO use a frame index11959 try self.genVarDebugInfo(.local_arg, .dbg_var_val, name, arg_ty, arg_mcv);
11945 .load_frame, .elementwise_regs_then_frame => return,
11946 //.stack_offset => |off| .{
11947 // .stack = .{
11948 // // TODO handle -fomit-frame-pointer
11949 // .fp_register = Register.rbp.dwarfNum(),
11950 // .offset = -off,
11951 // },
11952 //},
11953 else => unreachable, // not a valid function parameter
11954 };
11955 // TODO: this might need adjusting like the linkers do.
11956 // Instead of flattening the owner and passing Decl.Index here we may
11957 // want to special case LazySymbol in DWARF linker too.
11958 try dw.genArgDbgInfo(name, ty, self.owner.nav_index, loc);
11959 },
11960 .plan9 => {},
11961 .none => {},
11962 }11960 }
11961 if (self.liveness.isUnused(inst)) try self.processDeath(inst);
11963}11962}
1196411963
11965fn genVarDbgInfo(11964fn genVarDebugInfo(
11966 self: Self,11965 self: *Self,
11966 var_tag: link.File.Dwarf.WipNav.VarTag,
11967 tag: Air.Inst.Tag,11967 tag: Air.Inst.Tag,
11968 name: []const u8,
11968 ty: Type,11969 ty: Type,
11969 mcv: MCValue,11970 mcv: MCValue,
11970 name: [:0]const u8,
11971) !void {11971) !void {
11972 const is_ptr = switch (tag) {11972 const stack_vars = switch (var_tag) {
11973 .dbg_var_ptr => true,11973 .local_arg => &self.stack_args,
11974 .dbg_var_val => false,11974 .local_var => &self.stack_vars,
11975 else => unreachable,
11976 };11975 };
11977
11978 switch (self.debug_output) {11976 switch (self.debug_output) {
11979 .dwarf => |dw| {11977 .dwarf => |dwarf| switch (tag) {
11980 const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (mcv) {11978 else => unreachable,
11981 .register => |reg| .{ .register = reg.dwarfNum() },11979 .dbg_var_ptr => {
11982 // TODO use a frame index11980 const var_ty = ty.childType(self.pt.zcu);
11983 .load_frame, .lea_frame => return,11981 switch (mcv) {
11984 //=> |off| .{ .stack = .{11982 else => {
11985 // .fp_register = Register.rbp.dwarfNum(),11983 log.info("dbg_var_ptr({s}({}))", .{ @tagName(mcv), mcv });
11986 // .offset = -off,11984 unreachable;
11987 //} },11985 },
11988 .memory => |address| .{ .memory = address },11986 .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
11989 .load_symbol => |sym_off| loc: {11987 .lea_frame => |frame_addr| try stack_vars.append(self.gpa, .{
11990 assert(sym_off.off == 0);11988 .name = name,
11991 break :loc .{ .linker_load = .{ .type = .direct, .sym_index = sym_off.sym } };11989 .type = var_ty,
11992 }, // TODO11990 .frame_addr = frame_addr,
11993 .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },11991 }),
11994 .load_direct => |sym_index| .{11992 .lea_symbol => |sym_off| try dwarf.genVarDebugInfo(var_tag, name, var_ty, .{ .plus = .{
11995 .linker_load = .{ .type = .direct, .sym_index = sym_index },11993 &.{ .addr = .{ .sym = sym_off.sym } },
11996 },11994 &.{ .consts = sym_off.off },
11997 .immediate => |x| .{ .immediate = x },11995 } }),
11998 .undef => .undef,11996 }
11999 .none => .none,11997 },
12000 else => blk: {11998 .dbg_var_val => switch (mcv) {
12001 log.debug("TODO generate debug info for {}", .{mcv});11999 .none => try dwarf.genVarDebugInfo(var_tag, name, ty, .empty),
12002 break :blk .nop;12000 .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
12001 .immediate => |immediate| try dwarf.genVarDebugInfo(var_tag, name, ty, .{ .stack_value = &.{
12002 .constu = immediate,
12003 } }),
12004 else => {
12005 const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(ty, self.pt));
12006 try self.genSetMem(.{ .frame = frame_index }, 0, ty, mcv, .{});
12007 try stack_vars.append(self.gpa, .{
12008 .name = name,
12009 .type = ty,
12010 .frame_addr = .{ .index = frame_index },
12011 });
12003 },12012 },
12004 };12013 },
12005 // TODO: this might need adjusting like the linkers do.12014 },
12006 // Instead of flattening the owner and passing Decl.Index here we may12015 .plan9 => {},
12007 // want to special case LazySymbol in DWARF linker too.12016 .none => {},
12008 try dw.genVarDbgInfo(name, ty, self.owner.nav_index, is_ptr, loc);12017 }
12018}
12019
12020fn genStackVarDebugInfo(
12021 self: Self,
12022 var_tag: link.File.Dwarf.WipNav.VarTag,
12023 stack_vars: []const StackVar,
12024) !void {
12025 switch (self.debug_output) {
12026 .dwarf => |dwarf| for (stack_vars) |stack_var| {
12027 const frame_loc = self.frame_locs.get(@intFromEnum(stack_var.frame_addr.index));
12028 try dwarf.genVarDebugInfo(var_tag, stack_var.name, stack_var.type, .{ .plus = .{
12029 &.{ .breg = frame_loc.base.dwarfNum() },
12030 &.{ .consts = @as(i33, frame_loc.disp) + stack_var.frame_addr.off },
12031 } });
12009 },12032 },
12010 .plan9 => {},12033 .plan9 => {},
12011 .none => {},12034 .none => {},
...@@ -13045,7 +13068,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {...@@ -13045,7 +13068,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
13045 const name = self.air.nullTerminatedString(pl_op.payload);13068 const name = self.air.nullTerminatedString(pl_op.payload);
1304613069
13047 const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];13070 const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
13048 try self.genVarDbgInfo(tag, ty, mcv, name);13071 try self.genVarDebugInfo(.local_var, tag, name, ty, mcv);
1304913072
13050 return self.finishAir(inst, .unreach, .{ operand, .none, .none });13073 return self.finishAir(inst, .unreach, .{ operand, .none, .none });
13051}13074}
...@@ -13154,13 +13177,17 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC...@@ -13154,13 +13177,17 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
13154 .lea_direct,13177 .lea_direct,
13155 .lea_got,13178 .lea_got,
13156 .lea_tlv,13179 .lea_tlv,
13157 .lea_frame,
13158 .lea_symbol,13180 .lea_symbol,
13159 .elementwise_regs_then_frame,13181 .elementwise_regs_then_frame,
13160 .reserved_frame,13182 .reserved_frame,
13161 .air_ref,13183 .air_ref,
13162 => unreachable,13184 => unreachable,
1316313185
13186 .lea_frame => {
13187 self.eflags_inst = null;
13188 return .{ .immediate = @intFromBool(false) };
13189 },
13190
13164 .register => |opt_reg| {13191 .register => |opt_reg| {
13165 if (some_info.off == 0) {13192 if (some_info.off == 0) {
13166 const some_abi_size: u32 = @intCast(some_info.ty.abiSize(pt));13193 const some_abi_size: u32 = @intCast(some_info.ty.abiSize(pt));
...@@ -13402,7 +13429,8 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {...@@ -13402,7 +13429,8 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
13402 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;13429 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
13403 const operand = try self.resolveInst(un_op);13430 const operand = try self.resolveInst(un_op);
13404 const ty = self.typeOf(un_op);13431 const ty = self.typeOf(un_op);
13405 const result = switch (try self.isNull(inst, ty, operand)) {13432 const result: MCValue = switch (try self.isNull(inst, ty, operand)) {
13433 .immediate => |imm| .{ .immediate = @intFromBool(imm == 0) },
13406 .eflags => |cc| .{ .eflags = cc.negate() },13434 .eflags => |cc| .{ .eflags = cc.negate() },
13407 else => unreachable,13435 else => unreachable,
13408 };13436 };
...@@ -15156,7 +15184,7 @@ fn genSetMem(...@@ -15156,7 +15184,7 @@ fn genSetMem(
15156 })).write(15184 })).write(
15157 self,15185 self,
15158 .{ .base = base, .mod = .{ .rm = .{15186 .{ .base = base, .mod = .{ .rm = .{
15159 .size = self.memSize(ty),15187 .size = Memory.Size.fromBitSize(@min(self.memSize(ty).bitSize(), src_alias.bitSize())),
15160 .disp = disp,15188 .disp = disp,
15161 } } },15189 } } },
15162 src_alias,15190 src_alias,
...@@ -15202,7 +15230,33 @@ fn genSetMem(...@@ -15202,7 +15230,33 @@ fn genSetMem(
15202 @tagName(src_mcv), ty.fmt(pt),15230 @tagName(src_mcv), ty.fmt(pt),
15203 }),15231 }),
15204 },15232 },
15205 .register_offset,15233 .register_offset => |reg_off| {
15234 const src_reg = self.copyToTmpRegister(ty, src_mcv) catch |err| switch (err) {
15235 error.OutOfRegisters => {
15236 const src_reg = registerAlias(reg_off.reg, abi_size);
15237 try self.asmRegisterMemory(.{ ._, .lea }, src_reg, .{
15238 .base = .{ .reg = src_reg },
15239 .mod = .{ .rm = .{
15240 .size = .qword,
15241 .disp = reg_off.off,
15242 } },
15243 });
15244 try self.genSetMem(base, disp, ty, .{ .register = reg_off.reg }, opts);
15245 return self.asmRegisterMemory(.{ ._, .lea }, src_reg, .{
15246 .base = .{ .reg = src_reg },
15247 .mod = .{ .rm = .{
15248 .size = .qword,
15249 .disp = -reg_off.off,
15250 } },
15251 });
15252 },
15253 else => |e| return e,
15254 };
15255 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
15256 defer self.register_manager.unlockReg(src_lock);
15257
15258 try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts);
15259 },
15206 .memory,15260 .memory,
15207 .indirect,15261 .indirect,
15208 .load_direct,15262 .load_direct,
...@@ -15422,9 +15476,14 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -15422,9 +15476,14 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
15422 const src_ty = self.typeOf(ty_op.operand);15476 const src_ty = self.typeOf(ty_op.operand);
1542315477
15424 const result = result: {15478 const result = result: {
15479 const src_mcv = try self.resolveInst(ty_op.operand);
15480 if (dst_ty.isPtrAtRuntime(mod) and src_ty.isPtrAtRuntime(mod)) switch (src_mcv) {
15481 .lea_frame => break :result src_mcv,
15482 else => if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv,
15483 };
15484
15425 const dst_rc = self.regClassForType(dst_ty);15485 const dst_rc = self.regClassForType(dst_ty);
15426 const src_rc = self.regClassForType(src_ty);15486 const src_rc = self.regClassForType(src_ty);
15427 const src_mcv = try self.resolveInst(ty_op.operand);
1542815487
15429 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;15488 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
15430 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);15489 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -18236,10 +18295,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -18236,10 +18295,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
18236 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);18295 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
18237 const tag_int_val = try tag_val.intFromEnum(tag_ty, pt);18296 const tag_int_val = try tag_val.intFromEnum(tag_ty, pt);
18238 const tag_int = tag_int_val.toUnsignedInt(pt);18297 const tag_int = tag_int_val.toUnsignedInt(pt);
18239 const tag_off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))18298 const tag_off: i32 = @intCast(layout.tagOffset());
18240 @intCast(layout.payload_size)
18241 else
18242 0;
18243 try self.genCopy(18299 try self.genCopy(
18244 tag_ty,18300 tag_ty,
18245 dst_mcv.address().offset(tag_off).deref(),18301 dst_mcv.address().offset(tag_off).deref(),
...@@ -18247,10 +18303,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -18247,10 +18303,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
18247 .{},18303 .{},
18248 );18304 );
1824918305
18250 const pl_off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))18306 const pl_off: i32 = @intCast(layout.payloadOffset());
18251 0
18252 else
18253 @intCast(layout.tag_size);
18254 try self.genCopy(src_ty, dst_mcv.address().offset(pl_off).deref(), src_mcv, .{});18307 try self.genCopy(src_ty, dst_mcv.address().offset(pl_off).deref(), src_mcv, .{});
1825518308
18256 break :result dst_mcv;18309 break :result dst_mcv;
...@@ -18790,6 +18843,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {...@@ -18790,6 +18843,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
18790 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },18843 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
18791 .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } },18844 .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } },
18792 .load_direct => |sym_index| .{ .load_direct = sym_index },18845 .load_direct => |sym_index| .{ .load_direct = sym_index },
18846 .lea_direct => |sym_index| .{ .lea_direct = sym_index },
18793 .load_got => |sym_index| .{ .lea_got = sym_index },18847 .load_got => |sym_index| .{ .lea_got = sym_index },
18794 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },18848 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
18795 },18849 },
src/arch/x86_64/Emit.zig+2-8
...@@ -14,7 +14,7 @@ relocs: std.ArrayListUnmanaged(Reloc) = .{},...@@ -14,7 +14,7 @@ relocs: std.ArrayListUnmanaged(Reloc) = .{},
1414
15pub const Error = Lower.Error || error{15pub const Error = Lower.Error || error{
16 EmitFail,16 EmitFail,
17};17} || link.File.UpdateDebugInfoError;
1818
19pub fn emitMir(emit: *Emit) Error!void {19pub fn emitMir(emit: *Emit) Error!void {
20 for (0..emit.lower.mir.instructions.len) |mir_i| {20 for (0..emit.lower.mir.instructions.len) |mir_i| {
...@@ -222,13 +222,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -222,13 +222,7 @@ pub fn emitMir(emit: *Emit) Error!void {
222 else => unreachable,222 else => unreachable,
223 .pseudo_dbg_prologue_end_none => {223 .pseudo_dbg_prologue_end_none => {
224 switch (emit.debug_output) {224 switch (emit.debug_output) {
225 .dwarf => |dw| {225 .dwarf => |dw| try dw.setPrologueEnd(),
226 try dw.setPrologueEnd();
227 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
228 emit.prev_di_line, emit.prev_di_column,
229 });
230 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
231 },
232 .plan9 => {},226 .plan9 => {},
233 .none => {},227 .none => {},
234 }228 }
src/arch/x86_64/Mir.zig+1-1
...@@ -1204,7 +1204,7 @@ pub const FrameLoc = struct {...@@ -1204,7 +1204,7 @@ pub const FrameLoc = struct {
1204pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {1204pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
1205 return switch (mem.info.base) {1205 return switch (mem.info.base) {
1206 .none, .reg, .reloc => mem,1206 .none, .reg, .reloc => mem,
1207 .frame => if (mir.frame_locs.len > 0) Memory{1207 .frame => if (mir.frame_locs.len > 0) .{
1208 .info = .{1208 .info = .{
1209 .base = .reg,1209 .base = .reg,
1210 .mod = mem.info.mod,1210 .mod = mem.info.mod,
src/arch/x86_64/bits.zig-1
...@@ -4,7 +4,6 @@ const expect = std.testing.expect;...@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44
5const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
6const ArrayList = std.ArrayList;6const ArrayList = std.ArrayList;
7const DW = std.dwarf;
87
9/// EFLAGS condition codes8/// EFLAGS condition codes
10pub const Condition = enum(u5) {9pub const Condition = enum(u5) {
src/codegen.zig+47-38
...@@ -36,10 +36,10 @@ pub const CodeGenError = error{...@@ -36,10 +36,10 @@ pub const CodeGenError = error{
36 OutOfMemory,36 OutOfMemory,
37 Overflow,37 Overflow,
38 CodegenFail,38 CodegenFail,
39};39} || link.File.UpdateDebugInfoError;
4040
41pub const DebugInfoOutput = union(enum) {41pub const DebugInfoOutput = union(enum) {
42 dwarf: *link.File.Dwarf.NavState,42 dwarf: *link.File.Dwarf.WipNav,
43 plan9: *link.File.Plan9.DebugInfoOutput,43 plan9: *link.File.Plan9.DebugInfoOutput,
44 none,44 none,
45};45};
...@@ -819,6 +819,9 @@ pub const GenResult = union(enum) {...@@ -819,6 +819,9 @@ pub const GenResult = union(enum) {
819 /// Decl with address deferred until the linker allocates everything in virtual memory.819 /// Decl with address deferred until the linker allocates everything in virtual memory.
820 /// Payload is a symbol index.820 /// Payload is a symbol index.
821 load_direct: u32,821 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,
822 /// Decl referenced via GOT with address deferred until the linker allocates825 /// Decl referenced via GOT with address deferred until the linker allocates
823 /// everything in virtual memory.826 /// everything in virtual memory.
824 /// Payload is a symbol index.827 /// Payload is a symbol index.
...@@ -833,10 +836,6 @@ pub const GenResult = union(enum) {...@@ -833,10 +836,6 @@ pub const GenResult = union(enum) {
833 lea_symbol: u32,836 lea_symbol: u32,
834 };837 };
835838
836 fn mcv(val: MCValue) GenResult {
837 return .{ .mcv = val };
838 }
839
840 fn fail(839 fn fail(
841 gpa: Allocator,840 gpa: Allocator,
842 src_loc: Zcu.LazySrcLoc,841 src_loc: Zcu.LazySrcLoc,
...@@ -869,7 +868,7 @@ fn genNavRef(...@@ -869,7 +868,7 @@ fn genNavRef(
869 8 => 0xaaaaaaaaaaaaaaaa,868 8 => 0xaaaaaaaaaaaaaaaa,
870 else => unreachable,869 else => unreachable,
871 };870 };
872 return GenResult.mcv(.{ .immediate = imm });871 return .{ .mcv = .{ .immediate = imm } };
873 }872 }
874873
875 const comp = lf.comp;874 const comp = lf.comp;
...@@ -878,12 +877,12 @@ fn genNavRef(...@@ -878,12 +877,12 @@ fn genNavRef(
878 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?877 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
879 if (ty.castPtrToFn(zcu)) |fn_ty| {878 if (ty.castPtrToFn(zcu)) |fn_ty| {
880 if (zcu.typeToFunc(fn_ty).?.is_generic) {879 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().? } };
882 }881 }
883 } else if (ty.zigTypeTag(zcu) == .Pointer) {882 } else if (ty.zigTypeTag(zcu) == .Pointer) {
884 const elem_ty = ty.elemType2(zcu);883 const elem_ty = ty.elemType2(zcu);
885 if (!elem_ty.hasRuntimeBits(pt)) {884 if (!elem_ty.hasRuntimeBits(pt)) {
886 return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(pt).toByteUnits().? });885 return .{ .mcv = .{ .immediate = elem_ty.abiAlignment(pt).toByteUnits().? } };
887 }886 }
888 }887 }
889888
...@@ -900,40 +899,40 @@ fn genNavRef(...@@ -900,40 +899,40 @@ fn genNavRef(
900 if (is_extern) {899 if (is_extern) {
901 const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));900 const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
902 zo.symbol(sym_index).flags.is_extern_ptr = true;901 zo.symbol(sym_index).flags.is_extern_ptr = true;
903 return GenResult.mcv(.{ .lea_symbol = sym_index });902 return .{ .mcv = .{ .lea_symbol = sym_index } };
904 }903 }
905 const sym_index = try zo.getOrCreateMetadataForNav(elf_file, nav_index);904 const sym_index = try zo.getOrCreateMetadataForNav(elf_file, nav_index);
906 if (!single_threaded and is_threadlocal) {905 if (!single_threaded and is_threadlocal) {
907 return GenResult.mcv(.{ .load_tlv = sym_index });906 return .{ .mcv = .{ .load_tlv = sym_index } };
908 }907 }
909 return GenResult.mcv(.{ .lea_symbol = sym_index });908 return .{ .mcv = .{ .lea_symbol = sym_index } };
910 } else if (lf.cast(.macho)) |macho_file| {909 } else if (lf.cast(.macho)) |macho_file| {
911 const zo = macho_file.getZigObject().?;910 const zo = macho_file.getZigObject().?;
912 if (is_extern) {911 if (is_extern) {
913 const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));912 const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
914 zo.symbols.items[sym_index].setSectionFlags(.{ .needs_got = true });913 zo.symbols.items[sym_index].setSectionFlags(.{ .needs_got = true });
915 return GenResult.mcv(.{ .load_symbol = sym_index });914 return .{ .mcv = .{ .load_symbol = sym_index } };
916 }915 }
917 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);916 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
918 const sym = zo.symbols.items[sym_index];917 const sym = zo.symbols.items[sym_index];
919 if (!single_threaded and is_threadlocal) {918 if (!single_threaded and is_threadlocal) {
920 return GenResult.mcv(.{ .load_tlv = sym.nlist_idx });919 return .{ .mcv = .{ .load_tlv = sym.nlist_idx } };
921 }920 }
922 return GenResult.mcv(.{ .load_symbol = sym.nlist_idx });921 return .{ .mcv = .{ .load_symbol = sym.nlist_idx } };
923 } else if (lf.cast(.coff)) |coff_file| {922 } else if (lf.cast(.coff)) |coff_file| {
924 if (is_extern) {923 if (is_extern) {
925 // TODO audit this924 // TODO audit this
926 const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));925 const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
927 try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT926 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 } };
929 }928 }
930 const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);929 const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);
931 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;930 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
932 return GenResult.mcv(.{ .load_got = sym_index });931 return .{ .mcv = .{ .load_got = sym_index } };
933 } else if (lf.cast(.plan9)) |p9| {932 } else if (lf.cast(.plan9)) |p9| {
934 const atom_index = try p9.seeNav(pt, nav_index);933 const atom_index = try p9.seeNav(pt, nav_index);
935 const atom = p9.getAtom(atom_index);934 const atom = p9.getAtom(atom_index);
936 return GenResult.mcv(.{ .memory = atom.getOffsetTableAddress(p9) });935 return .{ .mcv = .{ .memory = atom.getOffsetTableAddress(p9) } };
937 } else {936 } else {
938 return GenResult.fail(gpa, src_loc, "TODO genNavRef for target {}", .{target});937 return GenResult.fail(gpa, src_loc, "TODO genNavRef for target {}", .{target});
939 }938 }
...@@ -952,30 +951,40 @@ pub fn genTypedValue(...@@ -952,30 +951,40 @@ pub fn genTypedValue(
952951
953 log.debug("genTypedValue: val = {}", .{val.fmtValue(pt)});952 log.debug("genTypedValue: val = {}", .{val.fmtValue(pt)});
954953
955 if (val.isUndef(zcu)) {954 if (val.isUndef(zcu)) return .{ .mcv = .undef };
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 };
966955
967 switch (ty.zigTypeTag(zcu)) {956 switch (ty.zigTypeTag(zcu)) {
968 .Void => return GenResult.mcv(.none),957 .Void => return .{ .mcv = .none },
969 .Pointer => switch (ty.ptrSize(zcu)) {958 .Pointer => switch (ty.ptrSize(zcu)) {
970 .Slice => {},959 .Slice => {},
971 else => switch (val.toIntern()) {960 else => switch (val.toIntern()) {
972 .null_value => {961 .null_value => {
973 return GenResult.mcv(.{ .immediate = 0 });962 return .{ .mcv = .{ .immediate = 0 } };
974 },963 },
975 .none => {},
976 else => switch (ip.indexToKey(val.toIntern())) {964 else => switch (ip.indexToKey(val.toIntern())) {
977 .int => {965 .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 => {},
979 },988 },
980 else => {},989 else => {},
981 },990 },
...@@ -988,11 +997,11 @@ pub fn genTypedValue(...@@ -988,11 +997,11 @@ pub fn genTypedValue(
988 .signed => @bitCast(val.toSignedInt(pt)),997 .signed => @bitCast(val.toSignedInt(pt)),
989 .unsigned => val.toUnsignedInt(pt),998 .unsigned => val.toUnsignedInt(pt),
990 };999 };
991 return GenResult.mcv(.{ .immediate = unsigned });1000 return .{ .mcv = .{ .immediate = unsigned } };
992 }1001 }
993 },1002 },
994 .Bool => {1003 .Bool => {
995 return GenResult.mcv(.{ .immediate = @intFromBool(val.toBool()) });1004 return .{ .mcv = .{ .immediate = @intFromBool(val.toBool()) } };
996 },1005 },
997 .Optional => {1006 .Optional => {
998 if (ty.isPtrLikeOptional(zcu)) {1007 if (ty.isPtrLikeOptional(zcu)) {
...@@ -1000,11 +1009,11 @@ pub fn genTypedValue(...@@ -1000,11 +1009,11 @@ pub fn genTypedValue(
1000 lf,1009 lf,
1001 pt,1010 pt,
1002 src_loc,1011 src_loc,
1003 val.optionalValue(zcu) orelse return GenResult.mcv(.{ .immediate = 0 }),1012 val.optionalValue(zcu) orelse return .{ .mcv = .{ .immediate = 0 } },
1004 target,1013 target,
1005 );1014 );
1006 } else if (ty.abiSize(pt) == 1) {1015 } else if (ty.abiSize(pt) == 1) {
1007 return GenResult.mcv(.{ .immediate = @intFromBool(!val.isNull(zcu)) });1016 return .{ .mcv = .{ .immediate = @intFromBool(!val.isNull(zcu)) } };
1008 }1017 }
1009 },1018 },
1010 .Enum => {1019 .Enum => {
...@@ -1020,7 +1029,7 @@ pub fn genTypedValue(...@@ -1020,7 +1029,7 @@ pub fn genTypedValue(
1020 .ErrorSet => {1029 .ErrorSet => {
1021 const err_name = ip.indexToKey(val.toIntern()).err.name;1030 const err_name = ip.indexToKey(val.toIntern()).err.name;
1022 const error_index = try pt.getErrorValue(err_name);1031 const error_index = try pt.getErrorValue(err_name);
1023 return GenResult.mcv(.{ .immediate = error_index });1032 return .{ .mcv = .{ .immediate = error_index } };
1024 },1033 },
1025 .ErrorUnion => {1034 .ErrorUnion => {
1026 const err_type = ty.errorUnionSet(zcu);1035 const err_type = ty.errorUnionSet(zcu);
src/link.zig+15-1
...@@ -329,6 +329,9 @@ pub const File = struct {...@@ -329,6 +329,9 @@ pub const File = struct {
329 }329 }
330 }330 }
331331
332 pub const UpdateDebugInfoError = Dwarf.UpdateError;
333 pub const FlushDebugInfoError = Dwarf.FlushError;
334
332 pub const UpdateNavError = error{335 pub const UpdateNavError = error{
333 OutOfMemory,336 OutOfMemory,
334 Overflow,337 Overflow,
...@@ -365,7 +368,7 @@ pub const File = struct {...@@ -365,7 +368,7 @@ pub const File = struct {
365 DeviceBusy,368 DeviceBusy,
366 InvalidArgument,369 InvalidArgument,
367 HotSwapUnavailableOnHostOperatingSystem,370 HotSwapUnavailableOnHostOperatingSystem,
368 };371 } || UpdateDebugInfoError;
369372
370 /// Called from within CodeGen to retrieve the symbol index of a global symbol.373 /// Called from within CodeGen to retrieve the symbol index of a global symbol.
371 /// If no symbol exists yet with this name, a new undefined global symbol will374 /// If no symbol exists yet with this name, a new undefined global symbol will
...@@ -398,6 +401,16 @@ pub const File = struct {...@@ -398,6 +401,16 @@ pub const File = struct {
398 }401 }
399 }402 }
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
401 /// May be called before or after updateExports for any given Decl.414 /// May be called before or after updateExports for any given Decl.
402 pub fn updateFunc(415 pub fn updateFunc(
403 base: *File,416 base: *File,
...@@ -570,6 +583,7 @@ pub const File = struct {...@@ -570,6 +583,7 @@ pub const File = struct {
570 Unseekable,583 Unseekable,
571 UnsupportedCpuArchitecture,584 UnsupportedCpuArchitecture,
572 UnsupportedVersion,585 UnsupportedVersion,
586 UnexpectedEndOfFile,
573 } ||587 } ||
574 fs.File.WriteFileError ||588 fs.File.WriteFileError ||
575 fs.File.OpenError ||589 fs.File.OpenError ||
src/link/Coff.zig+32-29
...@@ -1205,10 +1205,11 @@ pub fn updateNav(...@@ -1205,10 +1205,11 @@ pub fn updateNav(
1205 const ip = &zcu.intern_pool;1205 const ip = &zcu.intern_pool;
1206 const nav = ip.getNav(nav_index);1206 const nav = ip.getNav(nav_index);
12071207
1208 const init_val = switch (ip.indexToKey(nav.status.resolved.val)) {1208 const nav_val = zcu.navValue(nav_index);
1209 .variable => |variable| variable.init,1209 const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
1210 .variable => |variable| Value.fromInterned(variable.init),
1210 .@"extern" => |@"extern"| {1211 .@"extern" => |@"extern"| {
1211 if (ip.isFunctionType(nav.typeOf(ip))) return;1212 if (ip.isFunctionType(@"extern".ty)) return;
1212 // TODO make this part of getGlobalSymbol1213 // TODO make this part of getGlobalSymbol
1213 const name = nav.name.toSlice(ip);1214 const name = nav.name.toSlice(ip);
1214 const lib_name = @"extern".lib_name.toSlice(ip);1215 const lib_name = @"extern".lib_name.toSlice(ip);
...@@ -1216,34 +1217,36 @@ pub fn updateNav(...@@ -1216,34 +1217,36 @@ pub fn updateNav(
1216 try self.need_got_table.put(gpa, global_index, {});1217 try self.need_got_table.put(gpa, global_index, {});
1217 return;1218 return;
1218 },1219 },
1219 else => nav.status.resolved.val,1220 else => nav_val,
1220 };1221 };
12211222
1222 const atom_index = try self.getOrCreateAtomForNav(nav_index);1223 if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
1223 Atom.freeRelocations(self, atom_index);1224 const atom_index = try self.getOrCreateAtomForNav(nav_index);
1224 const atom = self.getAtom(atom_index);1225 Atom.freeRelocations(self, atom_index);
1226 const atom = self.getAtom(atom_index);
12251227
1226 var code_buffer = std.ArrayList(u8).init(gpa);1228 var code_buffer = std.ArrayList(u8).init(gpa);
1227 defer code_buffer.deinit();1229 defer code_buffer.deinit();
12281230
1229 const res = try codegen.generateSymbol(1231 const res = try codegen.generateSymbol(
1230 &self.base,1232 &self.base,
1231 pt,1233 pt,
1232 zcu.navSrcLoc(nav_index),1234 zcu.navSrcLoc(nav_index),
1233 Value.fromInterned(init_val),1235 nav_init,
1234 &code_buffer,1236 &code_buffer,
1235 .none,1237 .none,
1236 .{ .parent_atom_index = atom.getSymbolIndex().? },1238 .{ .parent_atom_index = atom.getSymbolIndex().? },
1237 );1239 );
1238 const code = switch (res) {1240 const code = switch (res) {
1239 .ok => code_buffer.items,1241 .ok => code_buffer.items,
1240 .fail => |em| {1242 .fail => |em| {
1241 try zcu.failed_codegen.put(gpa, nav_index, em);1243 try zcu.failed_codegen.put(gpa, nav_index, em);
1242 return;1244 return;
1243 },1245 },
1244 };1246 };
12451247
1246 try self.updateNavCode(pt, nav_index, code, .NULL);1248 try self.updateNavCode(pt, nav_index, code, .NULL);
1249 }
12471250
1248 // Exports will be updated by `Zcu.processExports` after the update.1251 // Exports will be updated by `Zcu.processExports` after the update.
1249}1252}
...@@ -1290,10 +1293,10 @@ fn updateLazySymbolAtom(...@@ -1290,10 +1293,10 @@ fn updateLazySymbolAtom(
1290 },1293 },
1291 };1294 };
12921295
1293 const code_len = @as(u32, @intCast(code.len));1296 const code_len: u32 = @intCast(code.len);
1294 const symbol = atom.getSymbolPtr(self);1297 const symbol = atom.getSymbolPtr(self);
1295 try self.setSymbolName(symbol, name);1298 try self.setSymbolName(symbol, name);
1296 symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1));1299 symbol.section_number = @enumFromInt(section_index + 1);
1297 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };1300 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };
12981301
1299 const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));1302 const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
...@@ -1691,7 +1694,7 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -1691,7 +1694,7 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
1691 .tid = tid,1694 .tid = tid,
1692 };1695 };
16931696
1694 if (self.lazy_syms.getPtr(.none)) |metadata| {1697 if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {
1695 // Most lazy symbols can be updated on first use, but1698 // Most lazy symbols can be updated on first use, but
1696 // anyerror needs to wait for everything to be flushed.1699 // anyerror needs to wait for everything to be flushed.
1697 if (metadata.text_state != .unused) self.updateLazySymbolAtom(1700 if (metadata.text_state != .unused) self.updateLazySymbolAtom(
src/link/Dwarf.zig+3594-2658
...@@ -1,2884 +1,3820 @@...@@ -1,2884 +1,3820 @@
1allocator: Allocator,1gpa: std.mem.Allocator,
2bin_file: *File,2bin_file: *link.File,
3format: Format,3format: DW.Format,
4ptr_width: PtrWidth,4endian: std.builtin.Endian,
55address_size: AddressSize,
6/// A list of `Atom`s whose Line Number Programs have surplus capacity.6
7/// This is the same concept as `Section.free_list` in Elf; see those doc comments.7mods: std.AutoArrayHashMapUnmanaged(*Module, ModInfo),
8src_fn_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{},8types: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index),
9src_fn_first_index: ?Atom.Index = null,9navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index),
10src_fn_last_index: ?Atom.Index = null,10
11src_fns: std.ArrayListUnmanaged(Atom) = .{},11debug_abbrev: DebugAbbrev,
12src_fn_navs: AtomTable = .{},12debug_aranges: DebugAranges,
1313debug_info: DebugInfo,
14/// A list of `Atom`s whose corresponding .debug_info tags have surplus capacity.14debug_line: DebugLine,
15/// This is the same concept as `text_block_free_list`; see those doc comments.15debug_line_str: StringSection,
16di_atom_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{},16debug_loclists: DebugLocLists,
17di_atom_first_index: ?Atom.Index = null,17debug_rnglists: DebugRngLists,
18di_atom_last_index: ?Atom.Index = null,18debug_str: StringSection,
19di_atoms: std.ArrayListUnmanaged(Atom) = .{},19
20di_atom_navs: AtomTable = .{},20pub const UpdateError =
2121 std.fs.File.OpenError ||
22dbg_line_header: DbgLineHeader,22 std.fs.File.SetEndPosError ||
2323 std.fs.File.CopyRangeError ||
24abbrev_table_offset: ?u64 = null,24 std.fs.File.PWriteError ||
2525 error{ Overflow, Underflow, UnexpectedEndOfFile };
26/// TODO replace with InternPool26
27/// Table of debug symbol names.27pub const FlushError =
28strtab: StringTable = .{},28 UpdateError ||
2929 std.process.GetCwdError;
30/// Quick lookup array of all defined source files referenced by at least one Nav.30
31/// They will end up in the DWARF debug_line header as two lists:31pub const RelocError =
32/// * []include_directory32 std.fs.File.PWriteError;
33/// * []file_names33
34di_files: std.AutoArrayHashMapUnmanaged(*const Zcu.File, void) = .{},34pub const AddressSize = enum(u8) {
3535 @"32" = 4,
36global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},36 @"64" = 8,
3737 _,
38const AtomTable = std.AutoHashMapUnmanaged(InternPool.Nav.Index, Atom.Index);38};
3939
40const Atom = struct {40const ModInfo = struct {
41 /// Offset into .debug_info pointing to the tag for this Nav, or41 root_dir_path: Entry.Index,
42 /// offset from the beginning of the Debug Line Program header that contains this function.42 dirs: std.AutoArrayHashMapUnmanaged(Unit.Index, void),
43 off: u32,43 files: Files,
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,
4844
49 prev_index: ?Index,45 const Files = std.AutoArrayHashMapUnmanaged(Zcu.File.Index, void);
50 next_index: ?Index,
5146
52 pub const Index = u32;47 fn deinit(mod_info: *ModInfo, gpa: std.mem.Allocator) void {
48 mod_info.dirs.deinit(gpa);
49 mod_info.files.deinit(gpa);
50 mod_info.* = undefined;
51 }
53};52};
5453
55const DbgLineHeader = struct {54const DebugAbbrev = struct {
56 minimum_instruction_length: u8,55 section: Section,
57 maximum_operations_per_instruction: u8,56 const unit: Unit.Index = @enumFromInt(0);
58 default_is_stmt: bool,57 const entry: Entry.Index = @enumFromInt(0);
59 line_base: i8,
60 line_range: u8,
61 opcode_base: u8,
62};58};
6359
64/// Represents state of the analysed Nav.60const DebugAranges = struct {
65/// Includes Nav's abbrev table of type Types, matching arena61 section: Section,
66/// and a set of relocations that will be resolved once this62
67/// Nav's inner Atom is assigned an offset within the DWARF section.63 fn headerBytes(dwarf: *Dwarf) u32 {
68pub const NavState = struct {64 return std.mem.alignForwardAnyAlign(
69 dwarf: *Dwarf,65 u32,
70 pt: Zcu.PerThread,66 dwarf.unitLengthBytes() + 2 + dwarf.sectionOffsetBytes() + 1 + 1,
71 di_atom_navs: *const AtomTable,67 @intFromEnum(dwarf.address_size) * 2,
72 dbg_line_func: InternPool.Index,68 );
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 });
102 }69 }
10370
104 /// Adds global type relocation of the form: @offset => @symbol + 071 fn trailerBytes(dwarf: *Dwarf) u32 {
105 /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section72 return @intFromEnum(dwarf.address_size) * 2;
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 });
127 }73 }
74};
12875
129 fn addDbgInfoType(76const DebugInfo = struct {
130 self: *NavState,77 section: Section,
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;
14078
141 switch (ty.zigTypeTag(zcu)) {79 fn headerBytes(dwarf: *Dwarf) u32 {
142 .NoReturn => unreachable,80 return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() +
143 .Void => {81 uleb128Bytes(@intFromEnum(AbbrevCode.compile_unit)) + 1 + dwarf.sectionOffsetBytes() * 6 + uleb128Bytes(0) +
144 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.zero_bit_type));82 uleb128Bytes(@intFromEnum(AbbrevCode.module)) + dwarf.sectionOffsetBytes() + uleb128Bytes(0);
145 },83 }
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 }
32384
324 if (struct_type.isTuple(ip)) {85 fn declEntryLineOff(dwarf: *Dwarf) u32 {
325 for (struct_type.field_types.get(ip), struct_type.offsets.get(ip), 0..) |field_ty, field_off, field_index| {86 return AbbrevCode.decl_bytes + dwarf.sectionOffsetBytes();
326 if (!Type.fromInterned(field_ty).hasRuntimeBits(pt)) continue;87 }
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 }
36388
364 // DW.AT.structure_type delimit children89 const trailer_bytes = 1 + 1;
365 try dbg_info_buffer.append(0);90};
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 }
39591
396 // DW.AT.enumeration_type delimit children92const DebugLine = struct {
397 try dbg_info_buffer.append(0);93 header: Header,
398 },94 section: Section,
399 .Union => {95
400 const union_obj = zcu.typeToUnion(ty).?;96 const Header = struct {
401 const layout = pt.getUnionLayout(union_obj);97 minimum_instruction_length: u8,
402 const payload_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) layout.tag_size else 0;98 maximum_operations_per_instruction: u8,
403 const tag_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) 0 else layout.payload_size;99 default_is_stmt: bool,
404 // TODO this is temporary to match current state of unions in Zig - we don't yet have100 line_base: i8,
405 // safety checks implemented meaning the implicit tag is not yet stored and generated101 line_range: u8,
406 // for untagged unions.102 opcode_base: u8,
407 const is_tagged = layout.tag_size > 0;103 };
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 }
430104
431 // DW.AT.union_type105 fn dirIndexInfo(dir_count: u32) struct { bytes: u8, form: DeclValEnum(DW.FORM) } {
432 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.union_type));106 return if (dir_count <= 1 << 8)
433 // DW.AT.byte_size, DW.FORM.udata,107 .{ .bytes = 1, .form = .data1 }
434 try leb128.writeUleb128(dbg_info_buffer.writer(), layout.payload_size);108 else if (dir_count <= 1 << 16)
435 // DW.AT.name, DW.FORM.string109 .{ .bytes = 2, .form = .data2 }
436 if (is_tagged) {110 else
437 try dbg_info_buffer.writer().print("AnonUnion\x00", .{});111 unreachable;
438 } else {112 }
439 try ty.print(dbg_info_buffer.writer(), pt);
440 try dbg_info_buffer.append(0);
441 }
442113
443 for (union_obj.field_types.get(ip), union_obj.loadTagType(ip).names.get(ip)) |field_ty, field_name| {114 fn headerBytes(dwarf: *Dwarf, dir_count: u32, file_count: u32) u32 {
444 if (!Type.fromInterned(field_ty).hasRuntimeBits(pt)) continue;115 const dir_index_info = dirIndexInfo(dir_count);
445 const field_name_slice = field_name.toSlice(ip);116 return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() + 1 + 1 + 1 + 1 + 1 + 1 + 1 * (dwarf.debug_line.header.opcode_base - 1) +
446 // DW.AT.member117 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(dir_count) + (dwarf.sectionOffsetBytes()) * dir_count +
447 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_member));118 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(DW.LNCT.directory_index) + uleb128Bytes(@intFromEnum(dir_index_info.form)) + uleb128Bytes(DW.LNCT.LLVM_source) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(file_count) + (dwarf.sectionOffsetBytes() + dir_index_info.bytes + dwarf.sectionOffsetBytes()) * file_count;
448 // DW.AT.name, DW.FORM.string119 }
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 }
510120
511 {121 const trailer_bytes = 1 + uleb128Bytes(0) +
512 // DW.AT.member122 1 + uleb128Bytes(1) + 1;
513 try dbg_info_buffer.ensureUnusedCapacity(9);123};
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 }
525124
526 // DW.AT.structure_type delimit children125const DebugLocLists = struct {
527 try dbg_info_buffer.append(0);126 section: Section,
528 },127
529 else => {128 fn baseOffset(dwarf: *Dwarf) u32 {
530 log.debug("TODO implement .debug_info for type '{}'", .{ty.fmt(pt)});129 return dwarf.unitLengthBytes() + 2 + 1 + 1 + 4;
531 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.zero_bit_type));
532 },
533 }
534 }130 }
535131
536 pub const DbgInfoLoc = union(enum) {132 fn headerBytes(dwarf: *Dwarf) u32 {
537 register: u8,133 return baseOffset(dwarf);
538 register_pair: [2]u8,134 }
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 };
551135
552 pub fn genArgDbgInfo(136 const trailer_bytes = 0;
553 self: *NavState,137};
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];
563138
564 switch (loc) {139const DebugRngLists = struct {
565 .register => |reg| {140 section: Section,
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 }
660141
661 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);142 const baseOffset = DebugLocLists.baseOffset;
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 }
667143
668 pub fn genVarDbgInfo(144 fn headerBytes(dwarf: *Dwarf) u32 {
669 self: *NavState,145 return baseOffset(dwarf) + dwarf.sectionOffsetBytes() * 1;
670 name: [:0]const u8,146 }
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;
685147
686 switch (loc) {148 const trailer_bytes = 1;
687 .register => |reg| {149};
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 },
705150
706 .register_pair => |regs| {151const StringSection = struct {
707 const reg_bits = pt.zcu.getTarget().ptrBitWidth();152 contents: std.ArrayListUnmanaged(u8),
708 const reg_bytes: u8 = @intCast(@divExact(reg_bits, 8));153 map: std.AutoArrayHashMapUnmanaged(void, void),
709 const abi_size = child_ty.abiSize(pt);154 section: Section,
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 },
741155
742 .stack => |info| {156 const unit: Unit.Index = @enumFromInt(0);
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 },
778157
779 .memory,158 const init: StringSection = .{
780 .linker_load,159 .contents = .{},
781 => {160 .map = .{},
782 const ptr_width: u8 = @intCast(@divExact(target.ptrBitWidth(), 8));161 .section = Section.init,
783 try dbg_info.ensureUnusedCapacity(2 + ptr_width);162 };
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 },
829163
830 .immediate => |x| {164 fn deinit(str_sec: *StringSection, gpa: std.mem.Allocator) void {
831 try dbg_info.ensureUnusedCapacity(2);165 str_sec.contents.deinit(gpa);
832 const fixup = dbg_info.items.len;166 str_sec.map.deinit(gpa);
833 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc167 str_sec.section.deinit(gpa);
834 1,168 }
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 },
868169
869 .nop => {170 fn addString(str_sec: *StringSection, dwarf: *Dwarf, str: []const u8) UpdateError!Entry.Index {
870 try dbg_info.ensureUnusedCapacity(2);171 const gop = try str_sec.map.getOrPutAdapted(dwarf.gpa, str, Adapter{ .str_sec = str_sec });
871 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc172 errdefer _ = str_sec.map.pop();
872 1, DW.OP.nop,173 const entry: Entry.Index = @enumFromInt(gop.index);
873 });174 if (!gop.found_existing) {
874 },175 assert(try str_sec.section.addEntry(unit, dwarf) == entry);
176 errdefer _ = str_sec.section.getUnit(unit).entries.pop();
177 const entry_ptr = str_sec.section.getUnit(unit).getEntry(entry);
178 assert(entry_ptr.off == str_sec.contents.items.len);
179 entry_ptr.len = @intCast(str.len + 1);
180 try str_sec.contents.ensureUnusedCapacity(dwarf.gpa, str.len + 1);
181 str_sec.contents.appendSliceAssumeCapacity(str);
182 str_sec.contents.appendAssumeCapacity(0);
183 str_sec.section.dirty = true;
875 }184 }
876185 return entry;
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
882 }186 }
883187
884 pub fn advancePCAndLine(188 const Adapter = struct {
885 self: *NavState,189 str_sec: *StringSection,
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);
891190
892 const header = self.dwarf.dbg_line_header;191 pub fn hash(_: Adapter, key: []const u8) u32 {
893 assert(header.maximum_operations_per_instruction == 1);192 return @truncate(std.hash.Wyhash.hash(0, key));
894 const delta_op: u64 = 0;193 }
895194
896 const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or195 pub fn eql(adapter: Adapter, key: []const u8, _: void, rhs_index: usize) bool {
897 delta_line - header.line_base >= header.line_range)196 const entry = adapter.str_sec.section.getUnit(unit).getEntry(@enumFromInt(rhs_index));
898 remaining: {197 return std.mem.eql(u8, key, adapter.str_sec.contents.items[entry.off..][0 .. entry.len - 1 :0]);
899 assert(delta_line != 0);198 }
900 dbg_line.appendAssumeCapacity(DW.LNS.advance_line);199 };
901 leb128.writeIleb128(dbg_line.writer(), delta_line) catch unreachable;200};
902 break :remaining 0;
903 } else delta_line);
904201
905 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *202/// A linker section containing a sequence of `Unit`s.
906 header.maximum_operations_per_instruction + delta_op;203const Section = struct {
907 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;204 dirty: bool,
908 const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: {205 pad_to_ideal: bool,
909 dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);206 alignment: InternPool.Alignment,
910 leb128.writeUleb128(dbg_line.writer(), op_advance) catch unreachable;207 index: u32,
911 break :remaining 0;208 first: Unit.Index.Optional,
912 } else if (op_advance >= max_op_advance) remaining: {209 last: Unit.Index.Optional,
913 dbg_line.appendAssumeCapacity(DW.LNS.const_add_pc);210 off: u64,
914 break :remaining op_advance - max_op_advance;211 len: u64,
915 } else op_advance);212 units: std.ArrayListUnmanaged(Unit),
213
214 const Index = enum {
215 debug_abbrev,
216 debug_info,
217 debug_line,
218 debug_line_str,
219 debug_loclists,
220 debug_rnglists,
221 debug_str,
222 };
916223
917 if (remaining_delta_line == 0 and remaining_op_advance == 0) {224 const init: Section = .{
918 dbg_line.appendAssumeCapacity(DW.LNS.copy);225 .dirty = true,
919 } else {226 .pad_to_ideal = true,
920 dbg_line.appendAssumeCapacity(@intCast((remaining_delta_line - header.line_base) +227 .alignment = .@"1",
921 (header.line_range * remaining_op_advance) + header.opcode_base));228 .index = std.math.maxInt(u32),
922 }229 .first = .none,
230 .last = .none,
231 .off = 0,
232 .len = 0,
233 .units = .{},
234 };
235
236 fn deinit(sec: *Section, gpa: std.mem.Allocator) void {
237 for (sec.units.items) |*unit| unit.deinit(gpa);
238 sec.units.deinit(gpa);
239 sec.* = undefined;
923 }240 }
924241
925 pub fn setColumn(self: *NavState, column: u32) error{OutOfMemory}!void {242 fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index {
926 try self.dbg_line.ensureUnusedCapacity(1 + 5);243 const unit: Unit.Index = @enumFromInt(sec.units.items.len);
927 self.dbg_line.appendAssumeCapacity(DW.LNS.set_column);244 const unit_ptr = try sec.units.addOne(dwarf.gpa);
928 leb128.writeUleb128(self.dbg_line.writer(), column + 1) catch unreachable;245 errdefer sec.popUnit();
246 unit_ptr.* = .{
247 .prev = sec.last,
248 .next = .none,
249 .first = .none,
250 .last = .none,
251 .off = 0,
252 .header_len = header_len,
253 .trailer_len = trailer_len,
254 .len = header_len + trailer_len,
255 .entries = .{},
256 .cross_entry_relocs = .{},
257 .cross_unit_relocs = .{},
258 .cross_section_relocs = .{},
259 .external_relocs = .{},
260 };
261 if (sec.last.unwrap()) |last_unit| {
262 const last_unit_ptr = sec.getUnit(last_unit);
263 last_unit_ptr.next = unit.toOptional();
264 unit_ptr.off = last_unit_ptr.off + sec.padToIdeal(last_unit_ptr.len);
265 }
266 if (sec.first == .none)
267 sec.first = unit.toOptional();
268 sec.last = unit.toOptional();
269 try sec.resize(dwarf, unit_ptr.off + sec.padToIdeal(unit_ptr.len));
270 return unit;
929 }271 }
930272
931 pub fn setPrologueEnd(self: *NavState) error{OutOfMemory}!void {273 fn unlinkUnit(sec: *Section, unit: Unit.Index) void {
932 try self.dbg_line.append(DW.LNS.set_prologue_end);274 const unit_ptr = sec.getUnit(unit);
275 if (unit_ptr.prev.unwrap()) |prev_unit| sec.getUnit(prev_unit).next = unit_ptr.next;
276 if (unit_ptr.next.unwrap()) |next_unit| sec.getUnit(next_unit).prev = unit_ptr.prev;
277 if (sec.first.unwrap().? == unit) sec.first = unit_ptr.next;
278 if (sec.last.unwrap().? == unit) sec.last = unit_ptr.prev;
933 }279 }
934280
935 pub fn setEpilogueBegin(self: *NavState) error{OutOfMemory}!void {281 fn popUnit(sec: *Section) void {
936 try self.dbg_line.append(DW.LNS.set_epilogue_begin);282 const unit: Unit.Index = @enumFromInt(sec.units.items.len - 1);
283 sec.unlinkUnit(unit);
284 _ = sec.units.pop();
937 }285 }
938286
939 pub fn setInlineFunc(self: *NavState, func: InternPool.Index) error{OutOfMemory}!void {287 fn addEntry(sec: *Section, unit: Unit.Index, dwarf: *Dwarf) UpdateError!Entry.Index {
940 const zcu = self.pt.zcu;288 return sec.getUnit(unit).addEntry(sec, dwarf);
941 if (self.dbg_line_func == func) return;289 }
942290
943 try self.dbg_line.ensureUnusedCapacity((1 + 4) + (1 + 5));291 fn getUnit(sec: *Section, unit: Unit.Index) *Unit {
292 return &sec.units.items[@intFromEnum(unit)];
293 }
944294
945 const old_func_info = zcu.funcInfo(self.dbg_line_func);295 fn replaceEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
946 const new_func_info = zcu.funcInfo(func);296 const unit_ptr = sec.getUnit(unit);
297 try unit_ptr.getEntry(entry).replace(unit_ptr, sec, dwarf, contents);
298 }
947299
948 const old_file = try self.dwarf.addDIFile(zcu, old_func_info.owner_nav);300 fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {
949 const new_file = try self.dwarf.addDIFile(zcu, new_func_info.owner_nav);301 if (dwarf.bin_file.cast(.elf)) |elf_file| {
950 if (old_file != new_file) {302 try elf_file.growNonAllocSection(sec.index, len, @intCast(sec.alignment.toByteUnits().?), true);
951 self.dbg_line.appendAssumeCapacity(DW.LNS.set_file);303 const shdr = &elf_file.shdrs.items[sec.index];
952 leb128.writeUnsignedFixed(4, self.dbg_line.addManyAsArrayAssumeCapacity(4), new_file);304 sec.off = shdr.sh_offset;
305 sec.len = shdr.sh_size;
306 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
307 const header = if (macho_file.d_sym) |*d_sym| header: {
308 try d_sym.growSection(@intCast(sec.index), len, true, macho_file);
309 break :header &d_sym.sections.items[sec.index];
310 } else header: {
311 try macho_file.growSection(@intCast(sec.index), len);
312 break :header &macho_file.sections.items(.header)[sec.index];
313 };
314 sec.off = header.offset;
315 sec.len = header.size;
953 }316 }
317 }
954318
955 const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav);319 fn trim(sec: *Section, dwarf: *Dwarf) void {
956 const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav);320 const len = sec.getUnit(sec.first.unwrap() orelse return).off;
957 if (new_src_line != old_src_line) {321 if (len == 0) return;
958 self.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);322 for (sec.units.items) |*unit| unit.off -= len;
959 leb128.writeSignedFixed(5, self.dbg_line.addManyAsArrayAssumeCapacity(5), new_src_line - old_src_line);323 sec.off += len;
324 sec.len -= len;
325 if (dwarf.bin_file.cast(.elf)) |elf_file| {
326 const shdr = &elf_file.shdrs.items[sec.index];
327 shdr.sh_offset = sec.off;
328 shdr.sh_size = sec.len;
329 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
330 const header = if (macho_file.d_sym) |*d_sym|
331 &d_sym.sections.items[sec.index]
332 else
333 &macho_file.sections.items(.header)[sec.index];
334 header.offset = @intCast(sec.off);
335 header.size = sec.len;
960 }336 }
961
962 self.dbg_line_func = func;
963 }337 }
964};
965338
966pub const AbbrevEntry = struct {339 fn resolveRelocs(sec: *Section, dwarf: *Dwarf) RelocError!void {
967 atom_index: Atom.Index,340 for (sec.units.items) |*unit| try unit.resolveRelocs(sec, dwarf);
968 type: Type,341 }
969 offset: u32,
970};
971342
972pub const AbbrevRelocation = struct {343 fn padToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) {
973 /// If target is null, we deal with a local relocation that is based on simple offset + addend344 return if (sec.pad_to_ideal) Dwarf.padToIdeal(actual_size) else actual_size;
974 /// only.345 }
975 target: ?u32,
976 atom_index: Atom.Index,
977 offset: u32,
978 addend: u32,
979};346};
980347
981pub const ExprlocRelocation = struct {348/// A unit within a `Section` containing a sequence of `Entry`s.
982 /// Type of the relocation: direct load ref, or GOT load ref (via GOT table)349const Unit = struct {
983 type: enum {350 prev: Index.Optional,
984 direct_load,351 next: Index.Optional,
985 got_load,352 first: Entry.Index.Optional,
986 },353 last: Entry.Index.Optional,
987 /// Index of the target in the linker's locals symbol table.354 /// offset within containing section
988 target: u32,355 off: u32,
989 /// Offset within the debug info buffer where to patch up the address value.356 header_len: u32,
990 offset: u32,357 trailer_len: u32,
991};358 /// data length in bytes
359 len: u32,
360 entries: std.ArrayListUnmanaged(Entry),
361 cross_entry_relocs: std.ArrayListUnmanaged(CrossEntryReloc),
362 cross_unit_relocs: std.ArrayListUnmanaged(CrossUnitReloc),
363 cross_section_relocs: std.ArrayListUnmanaged(CrossSectionReloc),
364 external_relocs: std.ArrayListUnmanaged(ExternalReloc),
365
366 const Index = enum(u32) {
367 main,
368 _,
369
370 const Optional = enum(u32) {
371 none = std.math.maxInt(u32),
372 _,
373
374 fn unwrap(uio: Optional) ?Index {
375 return if (uio != .none) @enumFromInt(@intFromEnum(uio)) else null;
376 }
377 };
992378
993pub const PtrWidth = enum { p32, p64 };379 fn toOptional(ui: Index) Optional {
380 return @enumFromInt(@intFromEnum(ui));
381 }
382 };
994383
995pub const AbbrevCode = enum(u8) {384 fn deinit(unit: *Unit, gpa: std.mem.Allocator) void {
996 null,385 unit.entries.deinit(gpa);
997 padding,386 unit.cross_entry_relocs.deinit(gpa);
998 compile_unit,387 unit.cross_unit_relocs.deinit(gpa);
999 subprogram,388 unit.cross_section_relocs.deinit(gpa);
1000 subprogram_retvoid,389 unit.external_relocs.deinit(gpa);
1001 base_type,390 unit.* = undefined;
1002 ptr_type,391 }
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};
1014392
1015/// The reloc offset for the virtual address of a function in its Line Number Program.393 fn addEntry(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!Entry.Index {
1016/// Size is a virtual address integer.394 const entry: Entry.Index = @enumFromInt(unit.entries.items.len);
1017const dbg_line_vaddr_reloc_index = 3;395 const entry_ptr = try unit.entries.addOne(dwarf.gpa);
1018/// The reloc offset for the virtual address of a function in its .debug_info TAG.subprogram.396 entry_ptr.* = .{
1019/// Size is a virtual address integer.397 .prev = unit.last,
1020const dbg_info_low_pc_reloc_index = 1;398 .next = .none,
399 .off = 0,
400 .len = 0,
401 };
402 if (unit.last.unwrap()) |last_entry| {
403 const last_entry_ptr = unit.getEntry(last_entry);
404 last_entry_ptr.next = entry.toOptional();
405 entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);
406 }
407 if (unit.first == .none)
408 unit.first = entry.toOptional();
409 unit.last = entry.toOptional();
410 return entry;
411 }
1021412
1022const min_nop_size = 2;413 fn getEntry(unit: *Unit, entry: Entry.Index) *Entry {
414 return &unit.entries.items[@intFromEnum(entry)];
415 }
1023416
1024/// When allocating, the ideal_capacity is calculated by417 fn resize(unit_ptr: *Unit, sec: *Section, dwarf: *Dwarf, extra_header_len: u32, len: u32) UpdateError!void {
1025/// actual_capacity + (actual_capacity / ideal_factor)418 const end = if (unit_ptr.next.unwrap()) |next_unit|
1026const ideal_factor = 3;419 sec.getUnit(next_unit).off
420 else
421 sec.len;
422 if (extra_header_len > 0 or unit_ptr.off + len > end) {
423 unit_ptr.len = @min(unit_ptr.len, len);
424 var new_off = unit_ptr.off;
425 if (unit_ptr.next.unwrap()) |next_unit| {
426 const next_unit_ptr = sec.getUnit(next_unit);
427 if (unit_ptr.prev.unwrap()) |prev_unit|
428 sec.getUnit(prev_unit).next = unit_ptr.next
429 else
430 sec.first = unit_ptr.next;
431 const unit = next_unit_ptr.prev;
432 next_unit_ptr.prev = unit_ptr.prev;
433 const last_unit_ptr = sec.getUnit(sec.last.unwrap().?);
434 last_unit_ptr.next = unit;
435 unit_ptr.prev = sec.last;
436 unit_ptr.next = .none;
437 new_off = last_unit_ptr.off + sec.padToIdeal(last_unit_ptr.len);
438 sec.last = unit;
439 sec.dirty = true;
440 } else if (extra_header_len > 0) {
441 // `copyRangeAll` in `move` does not support overlapping ranges
442 // so make sure new location is disjoint from current location.
443 new_off += unit_ptr.len -| extra_header_len;
444 }
445 try sec.resize(dwarf, new_off + len);
446 try unit_ptr.move(sec, dwarf, new_off + extra_header_len);
447 unit_ptr.off -= extra_header_len;
448 unit_ptr.header_len += extra_header_len;
449 sec.trim(dwarf);
450 }
451 unit_ptr.len = len;
452 }
1027453
1028pub fn init(lf: *File, format: Format) Dwarf {454 fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {
1029 const comp = lf.comp;455 if (unit.off == new_off) return;
1030 const gpa = comp.gpa;456 if (try dwarf.getFile().?.copyRangeAll(
1031 const target = comp.root_mod.resolved_target.result;457 sec.off + unit.off,
1032 const ptr_width: PtrWidth = switch (target.ptrBitWidth()) {458 dwarf.getFile().?,
1033 0...32 => .p32,459 sec.off + new_off,
1034 33...64 => .p64,460 unit.len,
1035 else => unreachable,461 ) != unit.len) return error.InputOutput;
1036 };462 unit.off = new_off;
1037 return .{463 }
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}
1062464
1063pub fn deinit(self: *Dwarf) void {465 fn resizeHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void {
1064 const gpa = self.allocator;466 if (unit.header_len == len) return;
467 const available_len = if (unit.prev.unwrap()) |prev_unit| prev_excess: {
468 const prev_unit_ptr = sec.getUnit(prev_unit);
469 break :prev_excess unit.off - prev_unit_ptr.off - prev_unit_ptr.len;
470 } else 0;
471 if (available_len + unit.header_len < len)
472 try unit.resize(sec, dwarf, len - unit.header_len, unit.len - unit.header_len + len);
473 if (unit.header_len > len) {
474 const excess_header_len = unit.header_len - len;
475 unit.off += excess_header_len;
476 unit.header_len -= excess_header_len;
477 unit.len -= excess_header_len;
478 } else if (unit.header_len < len) {
479 const needed_header_len = len - unit.header_len;
480 unit.off -= needed_header_len;
481 unit.header_len += needed_header_len;
482 unit.len += needed_header_len;
483 }
484 assert(unit.header_len == len);
485 sec.trim(dwarf);
486 }
1065487
1066 self.src_fn_free_list.deinit(gpa);488 fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
1067 self.src_fns.deinit(gpa);489 assert(contents.len == unit.header_len);
1068 self.src_fn_navs.deinit(gpa);490 try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off);
491 }
1069492
1070 self.di_atom_free_list.deinit(gpa);493 fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
1071 self.di_atoms.deinit(gpa);494 const start = unit.off + unit.header_len + if (unit.last.unwrap()) |last_entry| end: {
1072 self.di_atom_navs.deinit(gpa);495 const last_entry_ptr = unit.getEntry(last_entry);
496 break :end last_entry_ptr.off + last_entry_ptr.len;
497 } else 0;
498 const end = if (unit.next.unwrap()) |next_unit|
499 sec.getUnit(next_unit).off
500 else
501 sec.len;
502 const trailer_len: usize = @intCast(end - start);
503 assert(trailer_len >= unit.trailer_len);
504 var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, trailer_len);
505 defer trailer.deinit();
506 const fill_byte: u8 = if (sec == &dwarf.debug_aranges.section) fill: {
507 trailer.appendNTimesAssumeCapacity(0, @intFromEnum(dwarf.address_size) * 2);
508 break :fill 0;
509 } else if (sec == &dwarf.debug_info.section) fill: {
510 assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1);
511 trailer.appendNTimesAssumeCapacity(@intFromEnum(AbbrevCode.null), 2);
512 break :fill @intFromEnum(AbbrevCode.null);
513 } else if (sec == &dwarf.debug_line.section) fill: {
514 unit.len -= unit.trailer_len;
515 const extra_len: u32 = @intCast((trailer_len - DebugLine.trailer_bytes) & 1);
516 unit.trailer_len = DebugLine.trailer_bytes + extra_len;
517 unit.len += unit.trailer_len;
518
519 // prevent end sequence from emitting an invalid file index
520 trailer.appendAssumeCapacity(DW.LNS.set_file);
521 uleb128(trailer.fixedWriter(), 0) catch unreachable;
522
523 trailer.appendAssumeCapacity(DW.LNS.extended_op);
524 std.leb.writeUnsignedExtended(trailer.addManyAsSliceAssumeCapacity(uleb128Bytes(1) + extra_len), 1);
525 trailer.appendAssumeCapacity(DW.LNE.end_sequence);
526 break :fill DW.LNS.extended_op;
527 } else if (sec == &dwarf.debug_rnglists.section) fill: {
528 trailer.appendAssumeCapacity(DW.RLE.end_of_list);
529 break :fill DW.RLE.end_of_list;
530 } else unreachable;
531 assert(trailer.items.len == unit.trailer_len);
532 trailer.appendNTimesAssumeCapacity(fill_byte, trailer_len - trailer.items.len);
533 assert(trailer.items.len == trailer_len);
534 try dwarf.getFile().?.pwriteAll(trailer.items, sec.off + start);
535 }
1073536
1074 self.strtab.deinit(gpa);537 fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {
1075 self.di_files.deinit(gpa);538 for (unit.cross_entry_relocs.items) |reloc| {
1076 self.global_abbrev_relocs.deinit(gpa);539 try dwarf.resolveReloc(
1077}540 sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry|
541 unit.header_len + unit.getEntry(source_entry).off
542 else
543 0) + reloc.source_off,
544 unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off,
545 dwarf.sectionOffsetBytes(),
546 );
547 }
548 for (unit.cross_unit_relocs.items) |reloc| {
549 const target_unit = sec.getUnit(reloc.target_unit);
550 try dwarf.resolveReloc(
551 sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry|
552 unit.header_len + unit.getEntry(source_entry).off
553 else
554 0) + reloc.source_off,
555 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
556 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off
557 else
558 0) + reloc.target_off,
559 dwarf.sectionOffsetBytes(),
560 );
561 }
562 for (unit.cross_section_relocs.items) |reloc| {
563 const target_sec = switch (reloc.target_sec) {
564 inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section,
565 };
566 const target_unit = target_sec.getUnit(reloc.target_unit);
567 try dwarf.resolveReloc(
568 sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry|
569 unit.header_len + unit.getEntry(source_entry).off
570 else
571 0) + reloc.source_off,
572 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
573 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off
574 else
575 0) + reloc.target_off,
576 dwarf.sectionOffsetBytes(),
577 );
578 }
579 if (dwarf.bin_file.cast(.elf)) |elf_file| {
580 const zo = elf_file.zigObjectPtr().?;
581 for (unit.external_relocs.items) |reloc| {
582 const symbol = zo.symbol(reloc.target_sym);
583 try dwarf.resolveReloc(
584 sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off,
585 @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) -
586 if (symbol.flags.is_tls) elf_file.dtpAddress() else 0),
587 @intFromEnum(dwarf.address_size),
588 );
589 }
590 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
591 const zo = macho_file.getZigObject().?;
592 for (unit.external_relocs.items) |reloc| {
593 const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
594 try dwarf.resolveReloc(
595 sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off,
596 ref.getSymbol(macho_file).?.getAddress(.{}, macho_file),
597 @intFromEnum(dwarf.address_size),
598 );
599 }
600 }
601 }
1078602
1079/// Initializes Nav's state and its matching output buffers.603 const CrossEntryReloc = struct {
1080/// Call this before `commitNavState`.604 source_entry: Entry.Index.Optional = .none,
1081pub fn initNavState(self: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !NavState {605 source_off: u32 = 0,
1082 const tracy = trace(@src());606 target_entry: Entry.Index,
1083 defer tracy.end();607 target_off: u32 = 0,
608 };
609 const CrossUnitReloc = struct {
610 source_entry: Entry.Index.Optional = .none,
611 source_off: u32 = 0,
612 target_unit: Unit.Index,
613 target_entry: Entry.Index.Optional = .none,
614 target_off: u32 = 0,
615 };
616 const CrossSectionReloc = struct {
617 source_entry: Entry.Index.Optional = .none,
618 source_off: u32 = 0,
619 target_sec: Section.Index,
620 target_unit: Unit.Index,
621 target_entry: Entry.Index.Optional = .none,
622 target_off: u32 = 0,
623 };
624 const ExternalReloc = struct {
625 source_entry: Entry.Index,
626 source_off: u32 = 0,
627 target_sym: u32,
628 target_off: u64 = 0,
629 };
630};
1084631
1085 const nav = pt.zcu.intern_pool.getNav(nav_index);632/// An indivisible entry within a `Unit` containing section-specific data.
1086 log.debug("initNavState {}", .{nav.fqn.fmt(&pt.zcu.intern_pool)});633const Entry = struct {
634 prev: Index.Optional,
635 next: Index.Optional,
636 /// offset from end of containing unit header
637 off: u32,
638 /// data length in bytes
639 len: u32,
1087640
1088 const gpa = self.allocator;641 const Index = enum(u32) {
1089 var nav_state: NavState = .{642 _,
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;
1105643
1106 const di_atom_index = try self.getOrCreateAtomForNav(.di_atom, nav_index);644 const Optional = enum(u32) {
645 none = std.math.maxInt(u32),
646 _,
1107647
1108 const nav_val = Value.fromInterned(nav.status.resolved.val);648 fn unwrap(eio: Optional) ?Index {
649 return if (eio != .none) @enumFromInt(@intFromEnum(eio)) else null;
650 }
651 };
1109652
1110 switch (nav_val.typeOf(pt.zcu).zigTypeTag(pt.zcu)) {653 fn toOptional(ei: Index) Optional {
1111 .Fn => {654 return @enumFromInt(@intFromEnum(ei));
1112 _ = try self.getOrCreateAtomForNav(.src_fn, nav_index);655 }
656 };
1113657
1114 // For functions we need to add a prologue to the debug line program.658 fn pad(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
1115 const ptr_width_bytes = self.ptrWidthBytes();659 const start = entry.off + entry.len;
1116 try dbg_line_buffer.ensureTotalCapacity((3 + ptr_width_bytes) + (1 + 4) + (1 + 4) + (1 + 5) + 1);660 const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;
661 if (sec == &dwarf.debug_info.section) {
662 var buf: [
663 @max(
664 uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)),
665 uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) + uleb128Bytes(std.math.maxInt(u32)),
666 )
667 ]u8 = undefined;
668 var fbs = std.io.fixedBufferStream(&buf);
669 switch (len) {
670 0 => {},
671 1 => uleb128(fbs.writer(), @intFromEnum(AbbrevCode.pad_1)) catch unreachable,
672 else => {
673 uleb128(fbs.writer(), @intFromEnum(AbbrevCode.pad_n)) catch unreachable;
674 const abbrev_code_bytes = fbs.pos;
675 var block_len_bytes: u5 = 1;
676 while (true) switch (std.math.order(len - abbrev_code_bytes - block_len_bytes, @as(u32, 1) << 7 * block_len_bytes)) {
677 .lt => break uleb128(fbs.writer(), len - abbrev_code_bytes - block_len_bytes) catch unreachable,
678 .eq => {
679 // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
680 block_len_bytes += 1;
681 std.leb.writeUnsignedExtended(buf[fbs.pos..][0..block_len_bytes], len - abbrev_code_bytes - block_len_bytes);
682 fbs.pos += block_len_bytes;
683 break;
684 },
685 .gt => block_len_bytes += 1,
686 };
687 assert(fbs.pos == abbrev_code_bytes + block_len_bytes);
688 },
689 }
690 assert(fbs.pos <= len);
691 try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start);
692 } else if (sec == &dwarf.debug_line.section) {
693 const buf = try dwarf.gpa.alloc(u8, len);
694 defer dwarf.gpa.free(buf);
695 @memset(buf, DW.LNS.const_add_pc);
696 try dwarf.getFile().?.pwriteAll(buf, sec.off + unit.off + unit.header_len + start);
697 } else assert(!sec.pad_to_ideal and len == 0);
698 }
1117699
1118 nav_state.dbg_line_func = nav_val.toIntern();700 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
1119 const func = nav_val.getFunction(pt.zcu).?;701 const end = if (entry_ptr.next.unwrap()) |next_entry|
1120 log.debug("src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{702 unit.getEntry(next_entry).off
1121 pt.zcu.navSrcLine(nav_index),703 else
1122 func.lbrace_line,704 unit.len -| (unit.header_len + unit.trailer_len);
1123 func.rbrace_line,705 if (entry_ptr.off + contents.len > end) {
706 if (entry_ptr.next.unwrap()) |next_entry| {
707 if (entry_ptr.prev.unwrap()) |prev_entry| {
708 const prev_entry_ptr = unit.getEntry(prev_entry);
709 prev_entry_ptr.next = entry_ptr.next;
710 try prev_entry_ptr.pad(unit, sec, dwarf);
711 } else unit.first = entry_ptr.next;
712 const next_entry_ptr = unit.getEntry(next_entry);
713 const entry = next_entry_ptr.prev;
714 next_entry_ptr.prev = entry_ptr.prev;
715 const last_entry_ptr = unit.getEntry(unit.last.unwrap().?);
716 last_entry_ptr.next = entry;
717 entry_ptr.prev = unit.last;
718 entry_ptr.next = .none;
719 entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);
720 unit.last = entry;
721 }
722 try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padToIdeal(contents.len) + unit.trailer_len));
723 }
724 entry_ptr.len = @intCast(contents.len);
725 {
726 var prev_entry_ptr = entry_ptr;
727 while (prev_entry_ptr.prev.unwrap()) |prev_entry| {
728 prev_entry_ptr = unit.getEntry(prev_entry);
729 if (prev_entry_ptr.len == 0) continue;
730 try prev_entry_ptr.pad(unit, sec, dwarf);
731 break;
732 }
733 }
734 try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off);
735 try entry_ptr.pad(unit, sec, dwarf);
736 if (false) {
737 const buf = try dwarf.gpa.alloc(u8, sec.len);
738 defer dwarf.gpa.free(buf);
739 _ = try dwarf.getFile().?.preadAll(buf, sec.off);
740 log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{
741 @intFromEnum(sec.first),
742 @intFromEnum(sec.last),
743 sec.off,
744 sec.len,
1124 });745 });
1125 const line: u28 = @intCast(pt.zcu.navSrcLine(nav_index) + func.lbrace_line);746 for (sec.units.items) |*unit_ptr| {
747 log.info(" Unit{{ .prev = {}, .next = {}, .first = {}, .last = {}, .off = 0x{x}, .header_len = 0x{x}, .trailer_len = 0x{x}, .len = 0x{x} }}", .{
748 @intFromEnum(unit_ptr.prev),
749 @intFromEnum(unit_ptr.next),
750 @intFromEnum(unit_ptr.first),
751 @intFromEnum(unit_ptr.last),
752 unit_ptr.off,
753 unit_ptr.header_len,
754 unit_ptr.trailer_len,
755 unit_ptr.len,
756 });
757 for (unit_ptr.entries.items) |*entry| {
758 log.info(" Entry{{ .prev = {}, .next = {}, .off = 0x{x}, .len = 0x{x} }}", .{
759 @intFromEnum(entry.prev),
760 @intFromEnum(entry.next),
761 entry.off,
762 entry.len,
763 });
764 }
765 }
766 std.debug.dumpHex(buf);
767 }
768 }
1126769
1127 dbg_line_buffer.appendSliceAssumeCapacity(&.{770 fn assertNonEmpty(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) *Entry {
1128 DW.LNS.extended_op,771 if (entry.len > 0) return entry;
1129 ptr_width_bytes + 1,772 if (std.debug.runtime_safety) {
1130 DW.LNE.set_address,773 log.err("missing {} from {s}", .{
774 @as(Entry.Index, @enumFromInt(entry - unit.entries.items.ptr)),
775 std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file|
776 elf_file.shstrtab.items[elf_file.shdrs.items[sec.index].sh_name..]
777 else if (dwarf.bin_file.cast(.macho)) |macho_file|
778 if (macho_file.d_sym) |*d_sym|
779 &d_sym.sections.items[sec.index].segname
780 else
781 &macho_file.sections.items(.header)[sec.index].segname
782 else
783 "?", 0),
1131 });784 });
1132 // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`.785 const zcu = dwarf.bin_file.comp.module.?;
1133 assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len);786 const ip = &zcu.intern_pool;
1134 dbg_line_buffer.appendNTimesAssumeCapacity(0, ptr_width_bytes);787 for (dwarf.types.keys(), dwarf.types.values()) |ty, other_entry| {
1135788 const ty_unit: Unit.Index = if (Type.fromInterned(ty).typeDeclInst(zcu)) |inst_index|
1136 dbg_line_buffer.appendAssumeCapacity(DW.LNS.advance_line);789 dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFull(ip).file).mod) catch unreachable
1137 // This is the "relocatable" relative line offset from the previous function's end curly790 else
1138 // to this function's begin curly.791 .main;
1139 assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len);792 if (sec.getUnit(ty_unit) == unit and unit.getEntry(other_entry) == entry)
1140 // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later.793 log.err("missing Type({}({d}))", .{
1141 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line);794 Type.fromInterned(ty).fmt(.{ .tid = .main, .zcu = zcu }),
1142795 @intFromEnum(ty),
1143 dbg_line_buffer.appendAssumeCapacity(DW.LNS.set_file);796 });
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
1178 }797 }
1179 dbg_info_buffer.appendSliceAssumeCapacity(798 for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| {
1180 nav_name_slice[0 .. nav_name_slice.len + 1],799 const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFull(ip).file).mod) catch unreachable;
1181 ); // DW.AT.name, DW.FORM.string800 if (sec.getUnit(nav_unit) == unit and unit.getEntry(other_entry) == entry)
1182 dbg_info_buffer.appendSliceAssumeCapacity(801 log.err("missing Nav({}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) });
1183 nav_linkage_name_slice[0 .. nav_linkage_name_slice.len + 1],802 }
1184 ); // DW.AT.linkage_name, DW.FORM.string803 }
1185 },804 @panic("missing dwarf relocation target");
1186 else => {
1187 // TODO implement .debug_info for global variables
1188 },
1189 }805 }
806};
1190807
1191 return nav_state;808pub const Loc = union(enum) {
1192}809 empty,
810 addr: union(enum) { sym: u32 },
811 constu: u64,
812 consts: i64,
813 plus: Bin,
814 reg: u32,
815 breg: u32,
816 push_object_address,
817 form_tls_address: *const Loc,
818 implicit_value: []const u8,
819 stack_value: *const Loc,
820 wasm_ext: union(enum) {
821 local: u32,
822 global: u32,
823 operand_stack: u32,
824 },
1193825
1194pub fn commitNavState(826 pub const Bin = struct { *const Loc, *const Loc };
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();
1211827
1212 var dbg_line_buffer = &nav_state.dbg_line;828 fn getConst(loc: Loc, comptime Int: type) ?Int {
1213 var dbg_info_buffer = &nav_state.dbg_info;829 return switch (loc) {
830 .constu => |constu| std.math.cast(Int, constu),
831 .consts => |consts| std.math.cast(Int, consts),
832 else => null,
833 };
834 }
1214835
1215 const nav_val = Value.fromInterned(nav.status.resolved.val);836 fn getBaseReg(loc: Loc) ?u32 {
1216 switch (nav_val.typeOf(zcu).zigTypeTag(zcu)) {837 return switch (loc) {
1217 .Fn => {838 .breg => |breg| breg,
1218 try nav_state.setInlineFunc(nav_val.toIntern());839 else => null,
840 };
841 }
1219842
1220 // Since the Nav is a function, we need to update the .debug_line program.843 fn writeReg(reg: u32, op0: u8, opx: u8, writer: anytype) @TypeOf(writer).Error!void {
1221 // Perform the relocations based on vaddr.844 if (std.math.cast(u5, reg)) |small_reg| {
1222 switch (self.ptr_width) {845 try writer.writeByte(op0 + small_reg);
1223 .p32 => {846 } else {
1224 {847 try writer.writeByte(opx);
1225 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];848 try uleb128(writer, reg);
1226 mem.writeInt(u32, ptr, @intCast(sym_addr), target_endian);849 }
1227 }850 }
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 }
1252851
1253 try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS.extended_op, 1, DW.LNE.end_sequence });852 fn write(loc: Loc, wip: anytype) UpdateError!void {
1254853 const writer = wip.infoWriter();
1255 // Now we have the full contents and may allocate a region to store it.854 switch (loc) {
1256855 .empty => unreachable,
1257 // This logic is nearly identical to the logic below in `updateNavDebugInfo` for856 .addr => |addr| {
1258 // `TextBlock` and the .debug_info. If you are editing this logic, you857 try writer.writeByte(DW.OP.addr);
1259 // probably need to edit that logic too.858 switch (addr) {
1260 const src_fn_index = self.src_fn_navs.get(nav_index).?;859 .sym => |sym_index| try wip.addrSym(sym_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);
1315 }860 }
861 },
862 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
863 try writer.writeByte(@as(u8, DW.OP.lit0) + lit);
864 } else if (std.math.cast(u8, constu)) |const1u| {
865 try writer.writeAll(&.{ DW.OP.const1u, const1u });
866 } else if (std.math.cast(u16, constu)) |const2u| {
867 try writer.writeByte(DW.OP.const2u);
868 try writer.writeInt(u16, const2u, wip.dwarf.endian);
869 } else if (std.math.cast(u21, constu)) |const3u| {
870 try writer.writeByte(DW.OP.constu);
871 try uleb128(writer, const3u);
872 } else if (std.math.cast(u32, constu)) |const4u| {
873 try writer.writeByte(DW.OP.const4u);
874 try writer.writeInt(u32, const4u, wip.dwarf.endian);
875 } else if (std.math.cast(u49, constu)) |const7u| {
876 try writer.writeByte(DW.OP.constu);
877 try uleb128(writer, const7u);
1316 } else {878 } else {
1317 // This is the first function of the Line Number Program.879 try writer.writeByte(DW.OP.const8u);
1318 self.src_fn_first_index = src_fn_index;880 try writer.writeInt(u64, constu, wip.dwarf.endian);
1319 self.src_fn_last_index = src_fn_index;881 },
1320882 .consts => |consts| if (std.math.cast(i8, consts)) |const1s| {
1321 src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{}));883 try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) });
1322 }884 } else if (std.math.cast(i16, consts)) |const2s| {
1323885 try writer.writeByte(DW.OP.const2s);
1324 const last_src_fn_index = self.src_fn_last_index.?;886 try writer.writeInt(i16, const2s, wip.dwarf.endian);
1325 const last_src_fn = self.getAtom(.src_fn, last_src_fn_index);887 } else if (std.math.cast(i21, consts)) |const3s| {
1326 const needed_size = last_src_fn.off + last_src_fn.len;888 try writer.writeByte(DW.OP.consts);
1327 const prev_padding_size: u32 = if (src_fn.prev_index) |prev_index| blk: {889 try sleb128(writer, const3s);
1328 const prev = self.getAtom(.src_fn, prev_index);890 } else if (std.math.cast(i32, consts)) |const4s| {
1329 break :blk src_fn.off - (prev.off + prev.len);891 try writer.writeByte(DW.OP.const4s);
1330 } else 0;892 try writer.writeInt(i32, const4s, wip.dwarf.endian);
1331 const next_padding_size: u32 = if (src_fn.next_index) |next_index| blk: {893 } else if (std.math.cast(i49, consts)) |const7s| {
1332 const next = self.getAtom(.src_fn, next_index);894 try writer.writeByte(DW.OP.consts);
1333 break :blk next.off - (src_fn.off + src_fn.len);895 try sleb128(writer, const7s);
1334 } else 0;896 } else {
1335897 try writer.writeByte(DW.OP.const8s);
1336 // We only have support for one compilation unit so far, so the offsets are directly898 try writer.writeInt(i64, consts, wip.dwarf.endian);
1337 // from the .debug_line section.899 },
1338 if (self.bin_file.cast(.elf)) |elf_file| {900 .plus => |plus| done: {
1339 const shdr_index = elf_file.debug_line_section_index.?;901 if (plus[0].getConst(u0)) |_| {
1340 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);902 try plus[1].write(wip);
1341 const debug_line_sect = elf_file.shdrs.items[shdr_index];903 break :done;
1342 const file_pos = debug_line_sect.sh_offset + src_fn.off;904 }
1343 try pwriteDbgLineNops(905 if (plus[1].getConst(u0)) |_| {
1344 elf_file.base.file.?,906 try plus[0].write(wip);
1345 file_pos,907 break :done;
1346 prev_padding_size,908 }
1347 dbg_line_buffer.items,909 if (plus[0].getBaseReg()) |breg| {
1348 next_padding_size,910 if (plus[1].getConst(i65)) |offset| {
1349 );911 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
1350 } else if (self.bin_file.cast(.macho)) |macho_file| {912 try sleb128(writer, offset);
1351 if (macho_file.base.isRelocatable()) {913 break :done;
1352 const sect_index = macho_file.debug_line_sect_index.?;914 }
1353 try macho_file.growSection(sect_index, needed_size);915 }
1354 const sect = macho_file.sections.items(.header)[sect_index];916 if (plus[1].getBaseReg()) |breg| {
1355 const file_pos = sect.offset + src_fn.off;917 if (plus[0].getConst(i65)) |offset| {
1356 try pwriteDbgLineNops(918 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
1357 macho_file.base.file.?,919 try sleb128(writer, offset);
1358 file_pos,920 break :done;
1359 prev_padding_size,921 }
1360 dbg_line_buffer.items,922 }
1361 next_padding_size,923 if (plus[0].getConst(u64)) |uconst| {
1362 );924 try plus[1].write(wip);
1363 } else {925 try writer.writeByte(DW.OP.plus_uconst);
1364 const d_sym = macho_file.getDebugSymbols().?;926 try uleb128(writer, uconst);
1365 const sect_index = d_sym.debug_line_section_index.?;927 break :done;
1366 try d_sym.growSection(sect_index, needed_size, true, macho_file);928 }
1367 const sect = d_sym.getSection(sect_index);929 if (plus[1].getConst(u64)) |uconst| {
1368 const file_pos = sect.offset + src_fn.off;930 try plus[0].write(wip);
1369 try pwriteDbgLineNops(931 try writer.writeByte(DW.OP.plus_uconst);
1370 d_sym.file,932 try uleb128(writer, uconst);
1371 file_pos,933 break :done;
1372 prev_padding_size,934 }
1373 dbg_line_buffer.items,935 try plus[0].write(wip);
1374 next_padding_size,936 try plus[1].write(wip);
1375 );937 try writer.writeByte(DW.OP.plus);
938 },
939 .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer),
940 .breg => |breg| {
941 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
942 try sleb128(writer, 0);
943 },
944 .push_object_address => try writer.writeByte(DW.OP.push_object_address),
945 .form_tls_address => |addr| {
946 try addr.write(wip);
947 try writer.writeByte(DW.OP.form_tls_address);
948 },
949 .implicit_value => |value| {
950 try writer.writeByte(DW.OP.implicit_value);
951 try uleb128(writer, value.len);
952 try writer.writeAll(value);
953 },
954 .stack_value => |value| {
955 try value.write(wip);
956 try writer.writeByte(DW.OP.stack_value);
957 },
958 .wasm_ext => |wasm_ext| {
959 try writer.writeByte(DW.OP.WASM_location);
960 switch (wasm_ext) {
961 .local => |local| {
962 try writer.writeByte(DW.OP.WASM_local);
963 try uleb128(writer, local);
964 },
965 .global => |global| if (std.math.cast(u21, global)) |global_u21| {
966 try writer.writeByte(DW.OP.WASM_global);
967 try uleb128(writer, global_u21);
968 } else {
969 try writer.writeByte(DW.OP.WASM_global_u32);
970 try writer.writeInt(u32, global, wip.dwarf.endian);
971 },
972 .operand_stack => |operand_stack| {
973 try writer.writeByte(DW.OP.WASM_operand_stack);
974 try uleb128(writer, operand_stack);
975 },
1376 }976 }
1377 } else if (self.bin_file.cast(.wasm)) |wasm_file| {977 },
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);
1422 }978 }
1423 }979 }
980};
1424981
1425 try self.updateNavDebugInfoAllocation(di_atom_index, @intCast(dbg_info_buffer.items.len));982pub const WipNav = struct {
983 dwarf: *Dwarf,
984 pt: Zcu.PerThread,
985 unit: Unit.Index,
986 entry: Entry.Index,
987 any_children: bool,
988 func: InternPool.Index,
989 func_high_reloc: u32,
990 debug_info: std.ArrayListUnmanaged(u8),
991 debug_line: std.ArrayListUnmanaged(u8),
992 debug_loclists: std.ArrayListUnmanaged(u8),
993 pending_types: std.ArrayListUnmanaged(InternPool.Index),
994
995 pub fn deinit(wip_nav: *WipNav) void {
996 const gpa = wip_nav.dwarf.gpa;
997 wip_nav.debug_info.deinit(gpa);
998 wip_nav.debug_line.deinit(gpa);
999 wip_nav.debug_loclists.deinit(gpa);
1000 wip_nav.pending_types.deinit(gpa);
1001 }
14261002
1427 while (nav_state.abbrev_relocs.popOrNull()) |reloc| {1003 pub fn infoWriter(wip_nav: *WipNav) std.ArrayListUnmanaged(u8).Writer {
1428 if (reloc.target) |reloc_target| {1004 return wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
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 }
1464 }1005 }
14651006
1466 while (nav_state.exprloc_relocs.popOrNull()) |reloc| {1007 pub const VarTag = enum { local_arg, local_var };
1467 if (self.bin_file.cast(.elf)) |elf_file| {1008 pub fn genVarDebugInfo(
1468 _ = elf_file; // TODO1009 wip_nav: *WipNav,
1469 } else if (self.bin_file.cast(.macho)) |macho_file| {1010 tag: VarTag,
1470 if (macho_file.base.isRelocatable()) {1011 name: []const u8,
1471 // TODO1012 ty: Type,
1472 } else {1013 loc: Loc,
1473 const d_sym = macho_file.getDebugSymbols().?;1014 ) UpdateError!void {
1474 try d_sym.relocs.append(d_sym.allocator, .{1015 wip_nav.any_children = true;
1475 .type = switch (reloc.type) {1016 assert(wip_nav.func != .none);
1476 .direct_load => .direct_load,1017 const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
1477 .got_load => .got_load,1018 try uleb128(diw, @intFromEnum(switch (tag) {
1478 },1019 inline else => |ct_tag| @field(AbbrevCode, @tagName(ct_tag)),
1479 .target = reloc.target,1020 }));
1480 .offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off,1021 try wip_nav.strp(name);
1481 .addend = 0,1022 try wip_nav.refType(ty);
1482 });1023 try wip_nav.exprloc(loc);
1483 }
1484 } else unreachable;
1485 }1024 }
14861025
1487 try self.writeNavDebugInfo(di_atom_index, dbg_info_buffer.items);1026 pub fn advancePCAndLine(
1488}1027 wip_nav: *WipNav,
1028 delta_line: i33,
1029 delta_pc: u64,
1030 ) error{OutOfMemory}!void {
1031 const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
14891032
1490fn updateNavDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32) !void {1033 const header = wip_nav.dwarf.debug_line.header;
1491 const tracy = trace(@src());1034 assert(header.maximum_operations_per_instruction == 1);
1492 defer tracy.end();1035 const delta_op: u64 = 0;
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;
15581036
1559 atom.off = @intCast(padToIdeal(self.dbgInfoHeaderBytes()));1037 const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or
1038 delta_line - header.line_base >= header.line_range)
1039 remaining: {
1040 assert(delta_line != 0);
1041 try dlw.writeByte(DW.LNS.advance_line);
1042 try sleb128(dlw, delta_line);
1043 break :remaining 0;
1044 } else delta_line);
1045
1046 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
1047 header.maximum_operations_per_instruction + delta_op;
1048 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
1049 const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: {
1050 try dlw.writeByte(DW.LNS.advance_pc);
1051 try uleb128(dlw, op_advance);
1052 break :remaining 0;
1053 } else if (op_advance >= max_op_advance) remaining: {
1054 try dlw.writeByte(DW.LNS.const_add_pc);
1055 break :remaining op_advance - max_op_advance;
1056 } else op_advance);
1057
1058 if (remaining_delta_line == 0 and remaining_op_advance == 0)
1059 try dlw.writeByte(DW.LNS.copy)
1060 else
1061 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +
1062 (header.line_range * remaining_op_advance) + header.opcode_base));
1560 }1063 }
1561}
15621064
1563fn writeNavDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []const u8) !void {1065 pub fn setColumn(wip_nav: *WipNav, column: u32) error{OutOfMemory}!void {
1564 const tracy = trace(@src());1066 const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
1565 defer tracy.end();1067 try dlw.writeByte(DW.LNS.set_column);
15661068 try uleb128(dlw, column + 1);
1567 // This logic is nearly identical to the logic above in `updateNav` for1069 }
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}
16601070
1661pub fn updateNavLineNumber(self: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !void {1071 pub fn setPrologueEnd(wip_nav: *WipNav) error{OutOfMemory}!void {
1662 const tracy = trace(@src());1072 const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
1663 defer tracy.end();1073 try dlw.writeByte(DW.LNS.set_prologue_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,
1708 }1074 }
1709}
17101075
1711pub fn freeNav(self: *Dwarf, nav_index: InternPool.Nav.Index) void {1076 pub fn setEpilogueBegin(wip_nav: *WipNav) error{OutOfMemory}!void {
1712 const gpa = self.allocator;1077 const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
17131078 try dlw.writeByte(DW.LNS.set_epilogue_begin);
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 }
1739 }1079 }
17401080
1741 // Free DI atom1081 pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void {
1742 if (self.di_atom_navs.fetchRemove(nav_index)) |kv| {1082 const zcu = wip_nav.pt.zcu;
1743 const di_atom_index = kv.value;1083 const dwarf = wip_nav.dwarf;
1744 const di_atom = self.getAtomPtr(.di_atom, di_atom_index);1084 if (wip_nav.func == func) return;
17451085
1746 if (self.di_atom_first_index == di_atom_index) {1086 const new_func_info = zcu.funcInfo(func);
1747 self.di_atom_first_index = di_atom.next_index;1087 const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav);
1748 }1088 const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod);
1749 if (self.di_atom_last_index == di_atom_index) {1089
1750 // TODO shrink the .debug_info section size here1090 const dlw = wip_nav.debug_line.writer(dwarf.gpa);
1751 self.di_atom_last_index = di_atom.prev_index;1091 if (dwarf.incremental()) {
1092 const new_nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, new_func_info.owner_nav);
1093 errdefer _ = dwarf.navs.pop();
1094 if (!new_nav_gop.found_existing) new_nav_gop.value_ptr.* = try dwarf.addCommonEntry(new_unit);
1095
1096 try dlw.writeByte(DW.LNS.extended_op);
1097 try uleb128(dlw, 1 + dwarf.sectionOffsetBytes());
1098 try dlw.writeByte(DW.LNE.ZIG_set_decl);
1099 try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{
1100 .source_entry = wip_nav.entry.toOptional(),
1101 .source_off = @intCast(wip_nav.debug_line.items.len),
1102 .target_sec = .debug_info,
1103 .target_unit = new_unit,
1104 .target_entry = new_nav_gop.value_ptr.toOptional(),
1105 });
1106 try dlw.writeByteNTimes(0, dwarf.sectionOffsetBytes());
1107 return;
1752 }1108 }
17531109
1754 if (di_atom.prev_index) |prev_index| {1110 const old_func_info = zcu.funcInfo(wip_nav.func);
1755 self.getAtomPtr(.di_atom, prev_index).next_index = di_atom.next_index;1111 const old_file = zcu.navFileScopeIndex(old_func_info.owner_nav);
1756 // TODO the free list logic like we do for SrcFn above1112 if (old_file != new_file) {
1757 } else {1113 const mod_info = dwarf.getModInfo(wip_nav.unit);
1758 di_atom.prev_index = null;1114 const mod_gop = try mod_info.dirs.getOrPut(dwarf.gpa, new_unit);
1115 errdefer _ = if (!mod_gop.found_existing) mod_info.dirs.pop();
1116 const file_gop = try mod_info.files.getOrPut(dwarf.gpa, new_file);
1117 errdefer _ = if (!file_gop.found_existing) mod_info.files.pop();
1118
1119 try dlw.writeByte(DW.LNS.set_file);
1120 try uleb128(dlw, file_gop.index);
1759 }1121 }
17601122
1761 if (di_atom.next_index) |next_index| {1123 const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav);
1762 self.getAtomPtr(.di_atom, next_index).prev_index = di_atom.prev_index;1124 const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav);
1763 } else {1125 if (new_src_line != old_src_line) {
1764 di_atom.next_index = null;1126 try dlw.writeByte(DW.LNS.advance_line);
1127 try sleb128(dlw, new_src_line - old_src_line);
1765 }1128 }
1129
1130 wip_nav.func = func;
1766 }1131 }
1767}
17681132
1769pub fn writeDbgAbbrev(self: *Dwarf) !void {1133 fn infoSectionOffset(wip_nav: *WipNav, sec: Section.Index, unit: Unit.Index, entry: Entry.Index, off: u32) UpdateError!void {
1770 // These are LEB encoded but since the values are all less than 1271134 const dwarf = wip_nav.dwarf;
1771 // we can simply append these bytes.1135 const gpa = dwarf.gpa;
1772 // zig fmt: off1136 if (sec != .debug_info) {
1773 const abbrev_buf = [_]u8{1137 try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_section_relocs.append(gpa, .{
1774 @intFromEnum(AbbrevCode.padding),1138 .source_entry = wip_nav.entry.toOptional(),
1775 @as(u8, 0x80) | @as(u7, @truncate(DW.TAG.ZIG_padding >> 0)),1139 .source_off = @intCast(wip_nav.debug_info.items.len),
1776 @as(u8, 0x80) | @as(u7, @truncate(DW.TAG.ZIG_padding >> 7)),1140 .target_sec = sec,
1777 @as(u8, 0x00) | @as(u7, @intCast(DW.TAG.ZIG_padding >> 14)),1141 .target_unit = unit,
1778 DW.CHILDREN.no,1142 .target_entry = entry.toOptional(),
1779 0, 0,1143 .target_off = off,
17801144 });
1781 @intFromEnum(AbbrevCode.compile_unit),1145 } else if (unit != wip_nav.unit) {
1782 DW.TAG.compile_unit,1146 try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_unit_relocs.append(gpa, .{
1783 DW.CHILDREN.yes,1147 .source_entry = wip_nav.entry.toOptional(),
1784 DW.AT.stmt_list, DW.FORM.sec_offset,1148 .source_off = @intCast(wip_nav.debug_info.items.len),
1785 DW.AT.low_pc, DW.FORM.addr,1149 .target_unit = unit,
1786 DW.AT.high_pc, DW.FORM.addr,1150 .target_entry = entry.toOptional(),
1787 DW.AT.name, DW.FORM.strp,1151 .target_off = off,
1788 DW.AT.comp_dir, DW.FORM.strp,1152 });
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 {1153 } else {
1913 const d_sym = macho_file.getDebugSymbols().?;1154 try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.append(gpa, .{
1914 const sect_index = d_sym.debug_abbrev_section_index.?;1155 .source_entry = wip_nav.entry.toOptional(),
1915 try d_sym.growSection(sect_index, needed_size, false, macho_file);1156 .source_off = @intCast(wip_nav.debug_info.items.len),
1916 const sect = d_sym.getSection(sect_index);1157 .target_entry = entry,
1917 const file_pos = sect.offset + abbrev_offset;1158 .target_off = off,
1918 try d_sym.file.pwriteAll(&abbrev_buf, file_pos);1159 });
1919 }1160 }
1920 } else if (self.bin_file.cast(.wasm)) |wasm_file| {1161 try wip_nav.debug_info.appendNTimes(gpa, 0, dwarf.sectionOffsetBytes());
1921 _ = wasm_file;1162 }
1922 // const debug_abbrev = &wasm_file.getAtomPtr(wasm_file.debug_abbrev_atom.?).code;
1923 // try debug_abbrev.resize(gpa, needed_size);
1924 // debug_abbrev.items[0..abbrev_buf.len].* = abbrev_buf;
1925 } else unreachable;
1926}
1927
1928fn dbgInfoHeaderBytes(self: *Dwarf) usize {
1929 _ = self;
1930 return 120;
1931}
19321163
1933pub fn writeDbgInfoHeader(self: *Dwarf, zcu: *Zcu, low_pc: u64, high_pc: u64) !void {1164 fn strp(wip_nav: *WipNav, str: []const u8) UpdateError!void {
1934 // If this value is null it means there is an error in the module;1165 try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0);
1935 // leave debug_info_header_dirty=true.1166 }
1936 const first_dbg_info_off = self.getDebugInfoOff() orelse return;
19371167
1938 // We have a function to compute the upper bound size, because it's needed1168 fn addrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void {
1939 // for determining where to put the offset of the first `LinkBlock`.1169 const dwarf = wip_nav.dwarf;
1940 const needed_bytes = self.dbgInfoHeaderBytes();1170 try dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{
1941 var di_buf = try std.ArrayList(u8).initCapacity(self.allocator, needed_bytes);1171 .source_entry = wip_nav.entry,
1942 defer di_buf.deinit();1172 .source_off = @intCast(wip_nav.debug_info.items.len),
1173 .target_sym = sym_index,
1174 });
1175 try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, @intFromEnum(dwarf.address_size));
1176 }
19431177
1944 const comp = self.bin_file.comp;1178 fn exprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
1945 const target = comp.root_mod.resolved_target.result;1179 if (loc == .empty) return;
1946 const target_endian = target.cpu.arch.endian();1180 var wip: struct {
1947 const init_len_size: usize = switch (self.format) {1181 const Info = std.io.CountingWriter(std.io.NullWriter);
1948 .dwarf32 => 4,1182 dwarf: *Dwarf,
1949 .dwarf64 => 12,1183 debug_info: Info,
1950 };1184 fn infoWriter(wip: *@This()) Info.Writer {
1185 return wip.debug_info.writer();
1186 }
1187 fn addrSym(wip: *@This(), _: u32) error{}!void {
1188 wip.debug_info.bytes_written += @intFromEnum(wip.dwarf.address_size);
1189 }
1190 } = .{
1191 .dwarf = wip_nav.dwarf,
1192 .debug_info = std.io.countingWriter(std.io.null_writer),
1193 };
1194 try loc.write(&wip);
1195 try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), wip.debug_info.bytes_written);
1196 try loc.write(wip_nav);
1197 }
19511198
1952 // initial length - length of the .debug_info contribution for this compilation unit,1199 fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } {
1953 // not including the initial length itself.1200 const zcu = wip_nav.pt.zcu;
1954 // We have to come back and write it later after we know the size.1201 const ip = &zcu.intern_pool;
1955 const after_init_len = di_buf.items.len + init_len_size;1202 const maybe_inst_index = ty.typeDeclInst(zcu);
1956 const dbg_info_end = self.getDebugInfoEnd().?;1203 const unit = if (maybe_inst_index) |inst_index|
1957 const init_len = dbg_info_end - after_init_len + 1;1204 try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFull(ip).file).mod)
19581205 else
1959 if (self.format == .dwarf64) di_buf.appendNTimesAssumeCapacity(0xff, 4);1206 .main;
1960 self.writeOffsetAssumeCapacity(&di_buf, init_len);1207 const gop = try wip_nav.dwarf.types.getOrPut(wip_nav.dwarf.gpa, ty.toIntern());
19611208 if (gop.found_existing) return .{ unit, gop.value_ptr.* };
1962 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version1209 const entry = try wip_nav.dwarf.addCommonEntry(unit);
1963 const abbrev_offset = self.abbrev_table_offset.?;1210 gop.value_ptr.* = entry;
19641211 if (maybe_inst_index == null) try wip_nav.pending_types.append(wip_nav.dwarf.gpa, ty.toIntern());
1965 self.writeOffsetAssumeCapacity(&di_buf, abbrev_offset);1212 return .{ unit, entry };
1966 di_buf.appendAssumeCapacity(self.ptrWidthBytes()); // address size1213 }
1967
1968 // Write the form for the compile unit, which must match the abbrev table above.
1969 const name_strp = try self.strtab.insert(self.allocator, zcu.root_mod.root_src_path);
1970 var compile_unit_dir_buffer: [std.fs.max_path_bytes]u8 = undefined;
1971 const compile_unit_dir = resolveCompilationDir(zcu, &compile_unit_dir_buffer);
1972 const comp_dir_strp = try self.strtab.insert(self.allocator, compile_unit_dir);
1973 const producer_strp = try self.strtab.insert(self.allocator, link.producer_string);
1974
1975 di_buf.appendAssumeCapacity(@intFromEnum(AbbrevCode.compile_unit));
1976 self.writeOffsetAssumeCapacity(&di_buf, 0); // DW.AT.stmt_list, DW.FORM.sec_offset
1977 self.writeAddrAssumeCapacity(&di_buf, low_pc);
1978 self.writeAddrAssumeCapacity(&di_buf, high_pc);
1979 self.writeOffsetAssumeCapacity(&di_buf, name_strp);
1980 self.writeOffsetAssumeCapacity(&di_buf, comp_dir_strp);
1981 self.writeOffsetAssumeCapacity(&di_buf, producer_strp);
1982
1983 // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number:
1984 // http://dwarfstd.org/ShowIssue.php?issue=171115.1
1985 // Until then we say it is C99.
1986 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG.C99, target_endian);
1987
1988 if (di_buf.items.len > first_dbg_info_off) {
1989 // Move the first N navs to the end to make more padding for the header.
1990 @panic("TODO: handle .debug_info header exceeding its padding");
1991 }
1992 const jmp_amt = first_dbg_info_off - di_buf.items.len;
1993 if (self.bin_file.cast(.elf)) |elf_file| {
1994 const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?];
1995 const file_pos = debug_info_sect.sh_offset;
1996 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
1997 } else if (self.bin_file.cast(.macho)) |macho_file| {
1998 if (macho_file.base.isRelocatable()) {
1999 const debug_info_sect = macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?];
2000 const file_pos = debug_info_sect.offset;
2001 try pwriteDbgInfoNops(macho_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
2002 } else {
2003 const d_sym = macho_file.getDebugSymbols().?;
2004 const debug_info_sect = d_sym.getSection(d_sym.debug_info_section_index.?);
2005 const file_pos = debug_info_sect.offset;
2006 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false);
2007 }
2008 } else if (self.bin_file.cast(.wasm)) |wasm_file| {
2009 _ = wasm_file;
2010 // const debug_info = &wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;
2011 // try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);
2012 } else unreachable;
2013}
20141214
2015fn resolveCompilationDir(zcu: *Zcu, buffer: *[std.fs.max_path_bytes]u8) []const u8 {1215 fn refType(wip_nav: *WipNav, ty: Type) UpdateError!void {
2016 // We fully resolve all paths at this point to avoid lack of source line info in stack1216 const unit, const entry = try wip_nav.getTypeEntry(ty);
2017 // traces or lack of debugging information which, if relative paths were used, would1217 try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
2018 // be very location dependent.1218 }
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}
20331219
2034fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) void {1220 fn refForward(wip_nav: *WipNav) std.mem.Allocator.Error!u32 {
2035 const comp = self.bin_file.comp;1221 const dwarf = wip_nav.dwarf;
2036 const target = comp.root_mod.resolved_target.result;1222 const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs;
2037 const target_endian = target.cpu.arch.endian();1223 const reloc_index: u32 = @intCast(cross_entry_relocs.items.len);
2038 switch (self.ptr_width) {1224 try cross_entry_relocs.append(dwarf.gpa, .{
2039 .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(addr), target_endian),1225 .source_entry = wip_nav.entry.toOptional(),
2040 .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian),1226 .source_off = @intCast(wip_nav.debug_info.items.len),
1227 .target_entry = undefined,
1228 .target_off = undefined,
1229 });
1230 try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, dwarf.sectionOffsetBytes());
1231 return reloc_index;
2041 }1232 }
2042}
20431233
2044fn writeOffsetAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), off: u64) void {1234 fn finishForward(wip_nav: *WipNav, reloc_index: u32) void {
2045 const comp = self.bin_file.comp;1235 const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.items[reloc_index];
2046 const target = comp.root_mod.resolved_target.result;1236 reloc.target_entry = wip_nav.entry;
2047 const target_endian = target.cpu.arch.endian();1237 reloc.target_off = @intCast(wip_nav.debug_info.items.len);
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),
2051 }1238 }
2052}
20531239
2054/// Writes to the file a buffer, prefixed and suffixed by the specified number of1240 fn enumConstValue(
2055/// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes1241 wip_nav: *WipNav,
2056/// are less than 1044480 bytes (if this limit is ever reached, this function can be1242 loaded_enum: InternPool.LoadedEnumType,
2057/// improved to make more than one pwritev call, or the limit can be raised by a fixed1243 abbrev_code: std.enums.EnumFieldStruct(std.builtin.Signedness, AbbrevCode, null),
2058/// amount by increasing the length of `vecs`).1244 field_index: usize,
2059fn pwriteDbgLineNops(1245 ) std.mem.Allocator.Error!void {
2060 file: fs.File,1246 const zcu = wip_nav.pt.zcu;
2061 offset: u64,1247 const ip = &zcu.intern_pool;
2062 prev_padding_size: usize,1248 const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
2063 buf: []const u8,1249 const signedness = switch (loaded_enum.tag_ty) {
2064 next_padding_size: usize,1250 .comptime_int_type => .signed,
2065) !void {1251 else => Type.fromInterned(loaded_enum.tag_ty).intInfo(zcu).signedness,
2066 const tracy = trace(@src());1252 };
2067 defer tracy.end();1253 try uleb128(diw, @intFromEnum(switch (signedness) {
20681254 inline .signed, .unsigned => |ct_signedness| @field(abbrev_code, @tagName(ct_signedness)),
2069 const page_of_nops = [1]u8{DW.LNS.negate_stmt} ** 4096;1255 }));
2070 const three_byte_nop = [3]u8{ DW.LNS.advance_pc, 0b1000_0000, 0 };1256 if (loaded_enum.values.len > 0) switch (ip.indexToKey(loaded_enum.values.get(ip)[field_index]).int.storage) {
2071 var vecs: [512]std.posix.iovec_const = undefined;1257 .u64 => |value| switch (signedness) {
2072 var vec_index: usize = 0;1258 .signed => try sleb128(diw, value),
2073 {1259 .unsigned => try uleb128(diw, value),
2074 var padding_left = prev_padding_size;1260 },
2075 if (padding_left % 2 != 0) {1261 .i64 => |value| switch (signedness) {
2076 vecs[vec_index] = .{1262 .signed => try sleb128(diw, value),
2077 .base = &three_byte_nop,1263 .unsigned => unreachable,
2078 .len = three_byte_nop.len,1264 },
2079 };1265 .big_int => |big_int| {
2080 vec_index += 1;1266 const bits = big_int.bitCountTwosCompForSignedness(signedness);
2081 padding_left -= three_byte_nop.len;1267 try wip_nav.debug_info.ensureUnusedCapacity(wip_nav.dwarf.gpa, std.math.divCeil(usize, bits, 7) catch unreachable);
2082 }1268 var bit: usize = 0;
2083 while (padding_left > page_of_nops.len) {1269 var carry: u1 = 1;
2084 vecs[vec_index] = .{1270 while (bit < bits) : (bit += 7) {
2085 .base = &page_of_nops,1271 const limb_bits = @typeInfo(std.math.big.Limb).Int.bits;
2086 .len = page_of_nops.len,1272 const limb_index = bit / limb_bits;
2087 };1273 const limb_shift: std.math.Log2Int(std.math.big.Limb) = @intCast(bit % limb_bits);
2088 vec_index += 1;1274 const low_abs_part: u7 = @truncate(big_int.limbs[limb_index] >> limb_shift);
2089 padding_left -= page_of_nops.len;1275 const abs_part = if (limb_shift > limb_bits - 7) abs_part: {
2090 }1276 const next_limb: std.math.big.Limb = if (limb_index + 1 < big_int.limbs.len)
2091 if (padding_left > 0) {1277 big_int.limbs[limb_index + 1]
2092 vecs[vec_index] = .{1278 else if (big_int.positive) 0 else std.math.maxInt(std.math.big.Limb);
2093 .base = &page_of_nops,1279 const high_abs_part: u7 = @truncate(next_limb << -%limb_shift);
2094 .len = padding_left,1280 break :abs_part high_abs_part | low_abs_part;
2095 };1281 } else low_abs_part;
2096 vec_index += 1;1282 const twos_comp_part = if (big_int.positive) abs_part else twos_comp_part: {
1283 const twos_comp_part, carry = @addWithOverflow(~abs_part, carry);
1284 break :twos_comp_part twos_comp_part;
1285 };
1286 wip_nav.debug_info.appendAssumeCapacity(@as(u8, if (bit + 7 < bits) 0x80 else 0x00) | twos_comp_part);
1287 }
1288 },
1289 .lazy_align, .lazy_size => unreachable,
1290 } else switch (signedness) {
1291 .signed => try sleb128(diw, field_index),
1292 .unsigned => try uleb128(diw, field_index),
2097 }1293 }
2098 }1294 }
20991295
2100 vecs[vec_index] = .{1296 fn flush(wip_nav: *WipNav) UpdateError!void {
2101 .base = buf.ptr,1297 while (wip_nav.pending_types.popOrNull()) |ty| try wip_nav.dwarf.updateType(wip_nav.pt, ty, &wip_nav.pending_types);
2102 .len = buf.len,1298 }
1299};
1300
1301/// When allocating, the ideal_capacity is calculated by
1302/// actual_capacity + (actual_capacity / ideal_factor)
1303const ideal_factor = 3;
1304
1305fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
1306 return actual_size +| (actual_size / ideal_factor);
1307}
1308
1309pub fn init(lf: *link.File, format: DW.Format) Dwarf {
1310 const comp = lf.comp;
1311 const gpa = comp.gpa;
1312 const target = comp.root_mod.resolved_target.result;
1313 return .{
1314 .gpa = gpa,
1315 .bin_file = lf,
1316 .format = format,
1317 .address_size = switch (target.ptrBitWidth()) {
1318 0...32 => .@"32",
1319 33...64 => .@"64",
1320 else => unreachable,
1321 },
1322 .endian = target.cpu.arch.endian(),
1323
1324 .mods = .{},
1325 .types = .{},
1326 .navs = .{},
1327
1328 .debug_abbrev = .{ .section = Section.init },
1329 .debug_aranges = .{ .section = Section.init },
1330 .debug_info = .{ .section = Section.init },
1331 .debug_line = .{
1332 .header = switch (target.cpu.arch) {
1333 .x86_64, .aarch64 => .{
1334 .minimum_instruction_length = 1,
1335 .maximum_operations_per_instruction = 1,
1336 .default_is_stmt = true,
1337 .line_base = -5,
1338 .line_range = 14,
1339 .opcode_base = DW.LNS.set_isa + 1,
1340 },
1341 else => .{
1342 .minimum_instruction_length = 1,
1343 .maximum_operations_per_instruction = 1,
1344 .default_is_stmt = true,
1345 .line_base = 0,
1346 .line_range = 1,
1347 .opcode_base = DW.LNS.set_isa + 1,
1348 },
1349 },
1350 .section = Section.init,
1351 },
1352 .debug_line_str = StringSection.init,
1353 .debug_loclists = .{ .section = Section.init },
1354 .debug_rnglists = .{ .section = Section.init },
1355 .debug_str = StringSection.init,
2103 };1356 };
2104 if (buf.len > 0) vec_index += 1;1357}
21051358
2106 {1359pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
2107 var padding_left = next_padding_size;1360 if (dwarf.bin_file.cast(.elf)) |elf_file| {
2108 if (padding_left % 2 != 0) {1361 for ([_]*Section{
2109 vecs[vec_index] = .{1362 &dwarf.debug_abbrev.section,
2110 .base = &three_byte_nop,1363 &dwarf.debug_aranges.section,
2111 .len = three_byte_nop.len,1364 &dwarf.debug_info.section,
2112 };1365 &dwarf.debug_line.section,
2113 vec_index += 1;1366 &dwarf.debug_line_str.section,
2114 padding_left -= three_byte_nop.len;1367 &dwarf.debug_loclists.section,
2115 }1368 &dwarf.debug_rnglists.section,
2116 while (padding_left > page_of_nops.len) {1369 &dwarf.debug_str.section,
2117 vecs[vec_index] = .{1370 }, [_]u32{
2118 .base = &page_of_nops,1371 elf_file.debug_abbrev_section_index.?,
2119 .len = page_of_nops.len,1372 elf_file.debug_aranges_section_index.?,
2120 };1373 elf_file.debug_info_section_index.?,
2121 vec_index += 1;1374 elf_file.debug_line_section_index.?,
2122 padding_left -= page_of_nops.len;1375 elf_file.debug_line_str_section_index.?,
1376 elf_file.debug_loclists_section_index.?,
1377 elf_file.debug_rnglists_section_index.?,
1378 elf_file.debug_str_section_index.?,
1379 }) |sec, section_index| {
1380 const shdr = &elf_file.shdrs.items[section_index];
1381 sec.index = section_index;
1382 sec.off = shdr.sh_offset;
1383 sec.len = shdr.sh_size;
2123 }1384 }
2124 if (padding_left > 0) {1385 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
2125 vecs[vec_index] = .{1386 if (macho_file.d_sym) |*d_sym| {
2126 .base = &page_of_nops,1387 for ([_]*Section{
2127 .len = padding_left,1388 &dwarf.debug_abbrev.section,
2128 };1389 &dwarf.debug_aranges.section,
2129 vec_index += 1;1390 &dwarf.debug_info.section,
1391 &dwarf.debug_line.section,
1392 &dwarf.debug_line_str.section,
1393 &dwarf.debug_loclists.section,
1394 &dwarf.debug_rnglists.section,
1395 &dwarf.debug_str.section,
1396 }, [_]u8{
1397 d_sym.debug_abbrev_section_index.?,
1398 d_sym.debug_aranges_section_index.?,
1399 d_sym.debug_info_section_index.?,
1400 d_sym.debug_line_section_index.?,
1401 d_sym.debug_line_str_section_index.?,
1402 d_sym.debug_loclists_section_index.?,
1403 d_sym.debug_rnglists_section_index.?,
1404 d_sym.debug_str_section_index.?,
1405 }) |sec, sect_index| {
1406 const header = &d_sym.sections.items[sect_index];
1407 sec.index = sect_index;
1408 sec.off = header.offset;
1409 sec.len = header.size;
1410 }
1411 } else {
1412 for ([_]*Section{
1413 &dwarf.debug_abbrev.section,
1414 &dwarf.debug_aranges.section,
1415 &dwarf.debug_info.section,
1416 &dwarf.debug_line.section,
1417 &dwarf.debug_line_str.section,
1418 &dwarf.debug_loclists.section,
1419 &dwarf.debug_rnglists.section,
1420 &dwarf.debug_str.section,
1421 }, [_]u8{
1422 macho_file.debug_abbrev_sect_index.?,
1423 macho_file.debug_aranges_sect_index.?,
1424 macho_file.debug_info_sect_index.?,
1425 macho_file.debug_line_sect_index.?,
1426 macho_file.debug_line_str_sect_index.?,
1427 macho_file.debug_loclists_sect_index.?,
1428 macho_file.debug_rnglists_sect_index.?,
1429 macho_file.debug_str_sect_index.?,
1430 }) |sec, sect_index| {
1431 const header = &macho_file.sections.items(.header)[sect_index];
1432 sec.index = sect_index;
1433 sec.off = header.offset;
1434 sec.len = header.size;
1435 }
2130 }1436 }
2131 }1437 }
2132 try file.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
2133}1438}
21341439
2135fn writeDbgLineNopsBuffered(1440pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
2136 buf: []u8,1441 dwarf.reloadSectionMetadata();
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 }
21531442
2154 while (padding_left > 0) : (padding_left -= 1) {1443 dwarf.debug_abbrev.section.pad_to_ideal = false;
2155 buf[offset - padding_left] = DW.LNS.negate_stmt;1444 assert(try dwarf.debug_abbrev.section.addUnit(0, 0, dwarf) == DebugAbbrev.unit);
2156 }1445 errdefer dwarf.debug_abbrev.section.popUnit();
2157 }1446 assert(try dwarf.debug_abbrev.section.addEntry(DebugAbbrev.unit, dwarf) == DebugAbbrev.entry);
21581447
2159 @memcpy(buf[offset..][0..content.len], content);1448 dwarf.debug_aranges.section.pad_to_ideal = false;
1449 dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size) * 2);
21601450
2161 {1451 dwarf.debug_line_str.section.pad_to_ideal = false;
2162 var padding_left = next_padding_size;1452 assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
2163 if (padding_left % 2 != 0) {1453 errdefer dwarf.debug_line_str.section.popUnit();
2164 buf[offset + content.len + padding_left ..][0..3].* = three_byte_nop;
2165 padding_left -= 3;
2166 }
21671454
2168 while (padding_left > 0) : (padding_left -= 1) {1455 dwarf.debug_str.section.pad_to_ideal = false;
2169 buf[offset + content.len + padding_left] = DW.LNS.negate_stmt;1456 assert(try dwarf.debug_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
2170 }1457 errdefer dwarf.debug_str.section.popUnit();
2171 }
2172}
21731458
2174/// Writes to the file a buffer, prefixed and suffixed by the specified number of1459 dwarf.debug_loclists.section.pad_to_ideal = false;
2175/// bytes of padding.
2176fn pwriteDbgInfoNops(
2177 file: fs.File,
2178 offset: u64,
2179 prev_padding_size: usize,
2180 buf: []const u8,
2181 next_padding_size: usize,
2182 trailing_zero: bool,
2183) !void {
2184 const tracy = trace(@src());
2185 defer tracy.end();
2186
2187 const page_of_nops = [1]u8{@intFromEnum(AbbrevCode.padding)} ** 4096;
2188 var vecs: [32]std.posix.iovec_const = undefined;
2189 var vec_index: usize = 0;
2190 {
2191 var padding_left = prev_padding_size;
2192 while (padding_left > page_of_nops.len) {
2193 vecs[vec_index] = .{
2194 .base = &page_of_nops,
2195 .len = page_of_nops.len,
2196 };
2197 vec_index += 1;
2198 padding_left -= page_of_nops.len;
2199 }
2200 if (padding_left > 0) {
2201 vecs[vec_index] = .{
2202 .base = &page_of_nops,
2203 .len = padding_left,
2204 };
2205 vec_index += 1;
2206 }
2207 }
22081460
2209 vecs[vec_index] = .{1461 dwarf.debug_rnglists.section.pad_to_ideal = false;
2210 .base = buf.ptr,1462}
2211 .len = buf.len,
2212 };
2213 if (buf.len > 0) vec_index += 1;
22141463
2215 {1464pub fn deinit(dwarf: *Dwarf) void {
2216 var padding_left = next_padding_size;1465 const gpa = dwarf.gpa;
2217 while (padding_left > page_of_nops.len) {1466 for (dwarf.mods.values()) |*mod_info| mod_info.deinit(gpa);
2218 vecs[vec_index] = .{1467 dwarf.mods.deinit(gpa);
2219 .base = &page_of_nops,1468 dwarf.types.deinit(gpa);
2220 .len = page_of_nops.len,1469 dwarf.navs.deinit(gpa);
2221 };1470 dwarf.debug_abbrev.section.deinit(gpa);
2222 vec_index += 1;1471 dwarf.debug_aranges.section.deinit(gpa);
2223 padding_left -= page_of_nops.len;1472 dwarf.debug_info.section.deinit(gpa);
2224 }1473 dwarf.debug_line.section.deinit(gpa);
2225 if (padding_left > 0) {1474 dwarf.debug_line_str.deinit(gpa);
2226 vecs[vec_index] = .{1475 dwarf.debug_loclists.section.deinit(gpa);
2227 .base = &page_of_nops,1476 dwarf.debug_rnglists.section.deinit(gpa);
2228 .len = padding_left,1477 dwarf.debug_str.deinit(gpa);
2229 };1478 dwarf.* = undefined;
2230 vec_index += 1;1479}
2231 }
2232 }
22331480
2234 if (trailing_zero) {1481fn getUnit(dwarf: *Dwarf, mod: *Module) UpdateError!Unit.Index {
2235 var zbuf = [1]u8{0};1482 const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod);
2236 vecs[vec_index] = .{1483 const unit: Unit.Index = @enumFromInt(mod_gop.index);
2237 .base = &zbuf,1484 if (!mod_gop.found_existing) {
2238 .len = zbuf.len,1485 errdefer _ = dwarf.mods.pop();
1486 mod_gop.value_ptr.* = .{
1487 .root_dir_path = undefined,
1488 .dirs = .{},
1489 .files = .{},
2239 };1490 };
2240 vec_index += 1;1491 errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa);
1492 try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {});
1493 assert(try dwarf.debug_aranges.section.addUnit(
1494 DebugAranges.headerBytes(dwarf),
1495 DebugAranges.trailerBytes(dwarf),
1496 dwarf,
1497 ) == unit);
1498 errdefer dwarf.debug_aranges.section.popUnit();
1499 assert(try dwarf.debug_info.section.addUnit(
1500 DebugInfo.headerBytes(dwarf),
1501 DebugInfo.trailer_bytes,
1502 dwarf,
1503 ) == unit);
1504 errdefer dwarf.debug_info.section.popUnit();
1505 assert(try dwarf.debug_line.section.addUnit(
1506 DebugLine.headerBytes(dwarf, 5, 25),
1507 DebugLine.trailer_bytes,
1508 dwarf,
1509 ) == unit);
1510 errdefer dwarf.debug_line.section.popUnit();
1511 assert(try dwarf.debug_loclists.section.addUnit(
1512 DebugLocLists.headerBytes(dwarf),
1513 DebugLocLists.trailer_bytes,
1514 dwarf,
1515 ) == unit);
1516 errdefer dwarf.debug_loclists.section.popUnit();
1517 assert(try dwarf.debug_rnglists.section.addUnit(
1518 DebugRngLists.headerBytes(dwarf),
1519 DebugRngLists.trailer_bytes,
1520 dwarf,
1521 ) == unit);
1522 errdefer dwarf.debug_rnglists.section.popUnit();
2241 }1523 }
22421524 return unit;
2243 try file.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
2244}1525}
22451526
2246fn writeDbgInfoNopsToArrayList(1527fn getUnitIfExists(dwarf: *const Dwarf, mod: *Module) ?Unit.Index {
2247 gpa: Allocator,1528 return @enumFromInt(dwarf.mods.getIndex(mod) orelse return null);
2248 buffer: *std.ArrayListUnmanaged(u8),
2249 offset: u32,
2250 prev_padding_size: usize,
2251 content: []const u8,
2252 next_padding_size: usize,
2253 trailing_zero: bool,
2254) Allocator.Error!void {
2255 try buffer.resize(gpa, @max(
2256 buffer.items.len,
2257 offset + content.len + next_padding_size + 1,
2258 ));
2259 @memset(buffer.items[offset - prev_padding_size .. offset], @intFromEnum(AbbrevCode.padding));
2260 @memcpy(buffer.items[offset..][0..content.len], content);
2261 @memset(buffer.items[offset + content.len ..][0..next_padding_size], @intFromEnum(AbbrevCode.padding));
2262
2263 if (trailing_zero) {
2264 buffer.items[offset + content.len + next_padding_size] = 0;
2265 }
2266}1529}
22671530
2268pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {1531fn getModInfo(dwarf: *Dwarf, unit: Unit.Index) *ModInfo {
2269 const comp = self.bin_file.comp;1532 return &dwarf.mods.values()[@intFromEnum(unit)];
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;
2342}1533}
23431534
2344pub fn writeDbgLineHeader(self: *Dwarf) !void {1535pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, sym_index: u32) UpdateError!?WipNav {
2345 const comp = self.bin_file.comp;1536 const zcu = pt.zcu;
2346 const gpa = self.allocator;1537 const ip = &zcu.intern_pool;
2347 const target = comp.root_mod.resolved_target.result;1538
2348 const target_endian = target.cpu.arch.endian();1539 const nav = ip.getNav(nav_index);
2349 const init_len_size: usize = switch (self.format) {1540 log.debug("initWipNav({})", .{nav.fqn.fmt(ip)});
2350 .dwarf32 => 4,1541
2351 .dwarf64 => 12,1542 const inst_info = nav.srcInst(ip).resolveFull(ip);
1543 const file = zcu.fileByIndex(inst_info.file);
1544
1545 const unit = try dwarf.getUnit(file.mod);
1546 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
1547 errdefer _ = dwarf.navs.pop();
1548 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
1549 const nav_val = zcu.navValue(nav_index);
1550 var wip_nav: WipNav = .{
1551 .dwarf = dwarf,
1552 .pt = pt,
1553 .unit = unit,
1554 .entry = nav_gop.value_ptr.*,
1555 .any_children = false,
1556 .func = .none,
1557 .func_high_reloc = undefined,
1558 .debug_info = .{},
1559 .debug_line = .{},
1560 .debug_loclists = .{},
1561 .pending_types = .{},
2352 };1562 };
1563 errdefer wip_nav.deinit();
23531564
2354 const dbg_line_prg_off = self.getDebugLineProgramOff() orelse return;1565 switch (ip.indexToKey(nav_val.toIntern())) {
2355 assert(self.getDebugLineProgramEnd().? != 0);1566 else => {
23561567 assert(file.zir_loaded);
2357 // Convert all input DI files into a set of include dirs and file names.1568 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
2358 var arena = std.heap.ArenaAllocator.init(gpa);1569 assert(decl_inst.tag == .declaration);
2359 defer arena.deinit();1570 const tree = try file.getTree(dwarf.gpa);
2360 const paths = try self.genIncludeDirsAndFileNames(arena.allocator());1571 const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
23611572 assert(loc.line == zcu.navSrcLine(nav_index));
2362 // The size of this header is variable, depending on the number of directories,1573
2363 // files, and padding. We have a function to compute the upper bound size, however,1574 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2364 // because it's needed for determining where to put the offset of the first `SrcFn`.1575 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index).data;
2365 const needed_bytes = self.dbgLineNeededHeaderBytes(paths.dirs, paths.files);1576 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2366 var di_buf = try std.ArrayList(u8).initCapacity(gpa, needed_bytes);1577 break :parent .{
2367 defer di_buf.deinit();1578 parent_namespace_ptr.owner_type,
23681579 switch (decl_extra.name) {
2369 if (self.format == .dwarf64) di_buf.appendNTimesAssumeCapacity(0xff, 4);1580 .@"comptime",
2370 self.writeOffsetAssumeCapacity(&di_buf, 0);1581 .@"usingnamespace",
23711582 .unnamed_test,
2372 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version1583 .decltest,
23731584 => DW.ACCESS.private,
2374 // Empirically, debug info consumers do not respect this field, or otherwise1585 _ => if (decl_extra.name.isNamedTest(file.zir))
2375 // consider it to be an error when it does not point exactly to the end of the header.1586 DW.ACCESS.private
2376 // Therefore we rely on the NOP jump at the beginning of the Line Number Program for1587 else if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
2377 // padding rather than this field.1588 DW.ACCESS.public
2378 const before_header_len = di_buf.items.len;1589 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
2379 self.writeOffsetAssumeCapacity(&di_buf, 0); // We will come back and write this.1590 DW.ACCESS.private
2380 const after_header_len = di_buf.items.len;1591 else
23811592 unreachable,
2382 assert(self.dbg_line_header.opcode_base == DW.LNS.set_isa + 1);1593 },
2383 di_buf.appendSliceAssumeCapacity(&[_]u8{1594 };
2384 self.dbg_line_header.minimum_instruction_length,1595 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
2385 self.dbg_line_header.maximum_operations_per_instruction,1596
2386 @intFromBool(self.dbg_line_header.default_is_stmt),1597 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2387 @bitCast(self.dbg_line_header.line_base),1598 try uleb128(diw, @intFromEnum(AbbrevCode.decl_var));
2388 self.dbg_line_header.line_range,1599 try wip_nav.refType(Type.fromInterned(parent_type));
2389 self.dbg_line_header.opcode_base,1600 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
23901601 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2391 // Standard opcode lengths. The number of items here is based on `opcode_base`.1602 try uleb128(diw, loc.column + 1);
2392 // The value is the number of LEB128 operands the instruction takes.1603 try diw.writeByte(accessibility);
2393 0, // `DW.LNS.copy`1604 try wip_nav.strp(nav.name.toSlice(ip));
2394 1, // `DW.LNS.advance_pc`1605 try wip_nav.strp(nav.fqn.toSlice(ip));
2395 1, // `DW.LNS.advance_line`1606 const ty = nav_val.typeOf(zcu);
2396 1, // `DW.LNS.set_file`1607 const ty_reloc_index = try wip_nav.refForward();
2397 1, // `DW.LNS.set_column`1608 try wip_nav.exprloc(.{ .addr = .{ .sym = sym_index } });
2398 0, // `DW.LNS.negate_stmt`1609 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
2399 0, // `DW.LNS.set_basic_block`1610 ty.abiAlignment(pt).toByteUnits().?);
2400 0, // `DW.LNS.const_add_pc`1611 const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() });
2401 1, // `DW.LNS.fixed_advance_pc`1612 try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index|
2402 0, // `DW.LNS.set_prologue_end`1613 zcu.all_exports.items[export_index..][0..1]
2403 0, // `DW.LNS.set_epilogue_begin`1614 else if (zcu.multi_exports.get(func_unit)) |export_range|
2404 1, // `DW.LNS.set_isa`1615 zcu.all_exports.items[export_range.index..][0..export_range.len]
2405 });1616 else
24061617 &.{}) |@"export"|
2407 for (paths.dirs, 0..) |dir, i| {1618 {
2408 log.debug("adding new include dir at {d} of '{s}'", .{ i + 1, dir });1619 if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true;
2409 di_buf.appendSliceAssumeCapacity(dir);1620 } else false));
2410 di_buf.appendAssumeCapacity(0);1621 wip_nav.finishForward(ty_reloc_index);
2411 }1622 try uleb128(diw, @intFromEnum(AbbrevCode.is_const));
2412 di_buf.appendAssumeCapacity(0); // include directories sentinel1623 try wip_nav.refType(ty);
24131624 },
2414 for (paths.files, 0..) |file, i| {1625 .variable => |variable| {
2415 const dir_index = paths.files_dirs_indexes[i];1626 assert(file.zir_loaded);
2416 log.debug("adding new file name at {d} of '{s}' referencing directory {d}", .{1627 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
2417 i + 1,1628 assert(decl_inst.tag == .declaration);
2418 file,1629 const tree = try file.getTree(dwarf.gpa);
2419 dir_index + 1,1630 const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
2420 });1631 assert(loc.line == zcu.navSrcLine(nav_index));
2421 di_buf.appendSliceAssumeCapacity(file);1632
2422 di_buf.appendSliceAssumeCapacity(&[_]u8{1633 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2423 0, // null byte for the relative path name1634 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index).data;
2424 @intCast(dir_index), // directory_index1635 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2425 0, // mtime (TODO supply this)1636 break :parent .{
2426 0, // file size bytes (TODO supply this)1637 parent_namespace_ptr.owner_type,
2427 });1638 switch (decl_extra.name) {
2428 }1639 .@"comptime",
2429 di_buf.appendAssumeCapacity(0); // file names sentinel1640 .@"usingnamespace",
1641 .unnamed_test,
1642 .decltest,
1643 => DW.ACCESS.private,
1644 _ => if (decl_extra.name.isNamedTest(file.zir))
1645 DW.ACCESS.private
1646 else if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
1647 DW.ACCESS.public
1648 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
1649 DW.ACCESS.private
1650 else
1651 unreachable,
1652 },
1653 };
1654 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
1655
1656 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1657 try uleb128(diw, @intFromEnum(AbbrevCode.decl_var));
1658 try wip_nav.refType(Type.fromInterned(parent_type));
1659 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1660 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1661 try uleb128(diw, loc.column + 1);
1662 try diw.writeByte(accessibility);
1663 try wip_nav.strp(nav.name.toSlice(ip));
1664 try wip_nav.strp(nav.fqn.toSlice(ip));
1665 const ty = Type.fromInterned(variable.ty);
1666 try wip_nav.refType(ty);
1667 const addr: Loc = .{ .addr = .{ .sym = sym_index } };
1668 try wip_nav.exprloc(if (variable.is_threadlocal) .{ .form_tls_address = &addr } else addr);
1669 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
1670 ty.abiAlignment(pt).toByteUnits().?);
1671 const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() });
1672 try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index|
1673 zcu.all_exports.items[export_index..][0..1]
1674 else if (zcu.multi_exports.get(func_unit)) |export_range|
1675 zcu.all_exports.items[export_range.index..][0..export_range.len]
1676 else
1677 &.{}) |@"export"|
1678 {
1679 if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true;
1680 } else false));
1681 },
1682 .func => |func| {
1683 assert(file.zir_loaded);
1684 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
1685 assert(decl_inst.tag == .declaration);
1686 const tree = try file.getTree(dwarf.gpa);
1687 const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
1688 assert(loc.line == zcu.navSrcLine(nav_index));
1689
1690 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
1691 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index).data;
1692 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
1693 break :parent .{
1694 parent_namespace_ptr.owner_type,
1695 switch (decl_extra.name) {
1696 .@"comptime",
1697 .@"usingnamespace",
1698 .unnamed_test,
1699 .decltest,
1700 => DW.ACCESS.private,
1701 _ => if (decl_extra.name.isNamedTest(file.zir))
1702 DW.ACCESS.private
1703 else if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
1704 DW.ACCESS.public
1705 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
1706 DW.ACCESS.private
1707 else
1708 unreachable,
1709 },
1710 };
1711 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
1712
1713 const func_type = ip.indexToKey(func.ty).func_type;
1714 wip_nav.func = nav_val.toIntern();
1715
1716 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1717 try uleb128(diw, @intFromEnum(AbbrevCode.decl_func));
1718 try wip_nav.refType(Type.fromInterned(parent_type));
1719 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1720 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1721 try uleb128(diw, loc.column + 1);
1722 try diw.writeByte(accessibility);
1723 try wip_nav.strp(nav.name.toSlice(ip));
1724 try wip_nav.strp(nav.fqn.toSlice(ip));
1725 try wip_nav.refType(Type.fromInterned(func_type.return_type));
1726 const external_relocs = &dwarf.debug_info.section.getUnit(unit).external_relocs;
1727 try external_relocs.append(dwarf.gpa, .{
1728 .source_entry = wip_nav.entry,
1729 .source_off = @intCast(wip_nav.debug_info.items.len),
1730 .target_sym = sym_index,
1731 });
1732 try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
1733 wip_nav.func_high_reloc = @intCast(external_relocs.items.len);
1734 try external_relocs.append(dwarf.gpa, .{
1735 .source_entry = wip_nav.entry,
1736 .source_off = @intCast(wip_nav.debug_info.items.len),
1737 .target_sym = sym_index,
1738 });
1739 try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
1740 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
1741 target_info.defaultFunctionAlignment(file.mod.resolved_target.result).toByteUnits().?);
1742 const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() });
1743 try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index|
1744 zcu.all_exports.items[export_index..][0..1]
1745 else if (zcu.multi_exports.get(func_unit)) |export_range|
1746 zcu.all_exports.items[export_range.index..][0..export_range.len]
1747 else
1748 &.{}) |@"export"|
1749 {
1750 if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true;
1751 } else false));
1752 try diw.writeByte(@intFromBool(func_type.return_type == .noreturn_type));
1753
1754 const dlw = wip_nav.debug_line.writer(dwarf.gpa);
1755 try dlw.writeByte(DW.LNS.extended_op);
1756 if (dwarf.incremental()) {
1757 try uleb128(dlw, 1 + dwarf.sectionOffsetBytes());
1758 try dlw.writeByte(DW.LNE.ZIG_set_decl);
1759 try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{
1760 .source_entry = wip_nav.entry.toOptional(),
1761 .source_off = @intCast(wip_nav.debug_line.items.len),
1762 .target_sec = .debug_info,
1763 .target_unit = wip_nav.unit,
1764 .target_entry = wip_nav.entry.toOptional(),
1765 });
1766 try dlw.writeByteNTimes(0, dwarf.sectionOffsetBytes());
24301767
2431 const header_len = di_buf.items.len - after_header_len;1768 try dlw.writeByte(DW.LNS.set_column);
2432 switch (self.format) {1769 try uleb128(dlw, func.lbrace_column + 1);
2433 .dwarf32 => mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(header_len), target_endian),
2434 .dwarf64 => mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian),
2435 }
24361770
2437 assert(needed_bytes == di_buf.items.len);1771 try wip_nav.advancePCAndLine(func.lbrace_line, 0);
1772 } else {
1773 try uleb128(dlw, 1 + @intFromEnum(dwarf.address_size));
1774 try dlw.writeByte(DW.LNE.set_address);
1775 try dwarf.debug_line.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{
1776 .source_entry = wip_nav.entry,
1777 .source_off = @intCast(wip_nav.debug_line.items.len),
1778 .target_sym = sym_index,
1779 });
1780 try dlw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
24381781
2439 if (di_buf.items.len > dbg_line_prg_off) {1782 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
2440 const needed_with_padding = padToIdeal(needed_bytes);1783 try dlw.writeByte(DW.LNS.set_file);
2441 const delta = needed_with_padding - dbg_line_prg_off;1784 try uleb128(dlw, file_gop.index);
24421785
2443 const first_fn_index = self.src_fn_first_index.?;1786 try dlw.writeByte(DW.LNS.set_column);
2444 const first_fn = self.getAtom(.src_fn, first_fn_index);1787 try uleb128(dlw, func.lbrace_column + 1);
2445 const last_fn_index = self.src_fn_last_index.?;
2446 const last_fn = self.getAtom(.src_fn, last_fn_index);
24471788
2448 var src_fn_index = first_fn_index;1789 try wip_nav.advancePCAndLine(@intCast(loc.line + func.lbrace_line), 0);
1790 }
1791 },
1792 }
1793 return wip_nav;
1794}
24491795
2450 const buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - first_fn.off);1796pub fn finishWipNav(
2451 defer gpa.free(buffer);1797 dwarf: *Dwarf,
1798 pt: Zcu.PerThread,
1799 nav_index: InternPool.Nav.Index,
1800 sym: struct { index: u32, addr: u64, size: u64 },
1801 wip_nav: *WipNav,
1802) UpdateError!void {
1803 const zcu = pt.zcu;
1804 const ip = &zcu.intern_pool;
1805 const nav = ip.getNav(nav_index);
1806 log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)});
1807
1808 if (wip_nav.func != .none) {
1809 dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size;
1810 if (wip_nav.any_children) {
1811 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1812 try uleb128(diw, @intFromEnum(AbbrevCode.null));
1813 } else std.leb.writeUnsignedFixed(
1814 AbbrevCode.decl_bytes,
1815 wip_nav.debug_info.items[0..AbbrevCode.decl_bytes],
1816 @intFromEnum(AbbrevCode.decl_func_empty),
1817 );
24521818
2453 if (self.bin_file.cast(.elf)) |elf_file| {1819 var aranges_entry = [1]u8{0} ** (8 + 8);
2454 const shdr_index = elf_file.debug_line_section_index.?;1820 try dwarf.debug_aranges.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{
2455 const needed_size = elf_file.shdrs.items[shdr_index].sh_size + delta;1821 .source_entry = wip_nav.entry,
2456 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);1822 .target_sym = sym.index,
2457 const file_pos = elf_file.shdrs.items[shdr_index].sh_offset + first_fn.off;1823 });
1824 dwarf.writeInt(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0);
1825 dwarf.writeInt(aranges_entry[@intFromEnum(dwarf.address_size)..][0..@intFromEnum(dwarf.address_size)], sym.size);
1826
1827 @memset(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0);
1828 try dwarf.debug_aranges.section.replaceEntry(
1829 wip_nav.unit,
1830 wip_nav.entry,
1831 dwarf,
1832 aranges_entry[0 .. @intFromEnum(dwarf.address_size) * 2],
1833 );
24581834
2459 const amt = try elf_file.base.file.?.preadAll(buffer, file_pos);1835 try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).external_relocs.appendSlice(dwarf.gpa, &.{
2460 if (amt != buffer.len) return error.InputOutput;1836 .{
1837 .source_entry = wip_nav.entry,
1838 .source_off = 1,
1839 .target_sym = sym.index,
1840 },
1841 .{
1842 .source_entry = wip_nav.entry,
1843 .source_off = 1 + @intFromEnum(dwarf.address_size),
1844 .target_sym = sym.index,
1845 .target_off = sym.size,
1846 },
1847 });
1848 try dwarf.debug_rnglists.section.replaceEntry(
1849 wip_nav.unit,
1850 wip_nav.entry,
1851 dwarf,
1852 ([1]u8{DW.RLE.start_end} ++ [1]u8{0} ** (8 + 8))[0 .. 1 + @intFromEnum(dwarf.address_size) + @intFromEnum(dwarf.address_size)],
1853 );
1854 }
24611855
2462 try elf_file.base.file.?.pwriteAll(buffer, file_pos + delta);1856 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2463 } else if (self.bin_file.cast(.macho)) |macho_file| {1857 if (wip_nav.debug_line.items.len > 0) {
2464 if (macho_file.base.isRelocatable()) {1858 const dlw = wip_nav.debug_line.writer(dwarf.gpa);
2465 const sect_index = macho_file.debug_line_sect_index.?;1859 try dlw.writeByte(DW.LNS.extended_op);
2466 const needed_size: u32 = @intCast(macho_file.sections.items(.header)[sect_index].size + delta);1860 try uleb128(dlw, 1);
2467 try macho_file.growSection(sect_index, needed_size);1861 try dlw.writeByte(DW.LNE.end_sequence);
2468 const file_pos = macho_file.sections.items(.header)[sect_index].offset + first_fn.off;1862 try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.items);
1863 }
1864 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items);
24691865
2470 const amt = try macho_file.base.file.?.preadAll(buffer, file_pos);1866 try wip_nav.flush();
2471 if (amt != buffer.len) return error.InputOutput;1867}
24721868
2473 try macho_file.base.file.?.pwriteAll(buffer, file_pos + delta);1869pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateError!void {
2474 } else {1870 const zcu = pt.zcu;
2475 const d_sym = macho_file.getDebugSymbols().?;1871 const ip = &zcu.intern_pool;
2476 const sect_index = d_sym.debug_line_section_index.?;1872 const nav_val = zcu.navValue(nav_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;
24801873
2481 const amt = try d_sym.file.preadAll(buffer, file_pos);1874 const nav = ip.getNav(nav_index);
2482 if (amt != buffer.len) return error.InputOutput;1875 log.debug("updateComptimeNav({})", .{nav.fqn.fmt(ip)});
1876
1877 const inst_info = nav.srcInst(ip).resolveFull(ip);
1878 const file = zcu.fileByIndex(inst_info.file);
1879 assert(file.zir_loaded);
1880 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
1881 assert(decl_inst.tag == .declaration);
1882 const tree = try file.getTree(dwarf.gpa);
1883 const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
1884 assert(loc.line == zcu.navSrcLine(nav_index));
1885
1886 const unit = try dwarf.getUnit(file.mod);
1887 var wip_nav: WipNav = .{
1888 .dwarf = dwarf,
1889 .pt = pt,
1890 .unit = unit,
1891 .entry = undefined,
1892 .any_children = false,
1893 .func = .none,
1894 .func_high_reloc = undefined,
1895 .debug_info = .{},
1896 .debug_line = .{},
1897 .debug_loclists = .{},
1898 .pending_types = .{},
1899 };
1900 defer wip_nav.deinit();
1901
1902 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
1903 errdefer _ = dwarf.navs.pop();
1904 switch (ip.indexToKey(nav_val.toIntern())) {
1905 .struct_type => done: {
1906 const loaded_struct = ip.loadStructType(nav_val.toIntern());
1907
1908 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
1909 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
1910 break :parent .{
1911 parent_namespace_ptr.owner_type,
1912 if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
1913 DW.ACCESS.public
1914 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
1915 DW.ACCESS.private
1916 else
1917 unreachable,
1918 };
1919 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
1920
1921 decl_struct: {
1922 if (loaded_struct.zir_index == .none) break :decl_struct;
1923
1924 const value_inst = value_inst: {
1925 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index);
1926 const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
1927 const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
1928 if (break_inst.tag != .break_inline) break :value_inst null;
1929 assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
1930 var value_inst = break_inst.data.@"break".operand.toIndex();
1931 while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
1932 else => break,
1933 .as_node => value_inst = file.zir.extraData(
1934 Zir.Inst.As,
1935 file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
1936 ).data.operand.toIndex(),
1937 };
1938 break :value_inst value_inst;
1939 };
1940 const type_inst_info = loaded_struct.zir_index.unwrap().?.resolveFull(ip);
1941 if (type_inst_info.inst != value_inst) break :decl_struct;
24831942
2484 try d_sym.file.pwriteAll(buffer, file_pos + delta);1943 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
1944 if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
1945 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
1946 type_gop.value_ptr.* = nav_gop.value_ptr.*;
1947 }
1948 wip_nav.entry = nav_gop.value_ptr.*;
1949 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1950
1951 switch (loaded_struct.layout) {
1952 .auto, .@"extern" => {
1953 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0)
1954 .decl_namespace_struct
1955 else
1956 .decl_struct)));
1957 try wip_nav.refType(Type.fromInterned(parent_type));
1958 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1959 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1960 try uleb128(diw, loc.column + 1);
1961 try diw.writeByte(accessibility);
1962 try wip_nav.strp(nav.name.toSlice(ip));
1963 if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
1964 try uleb128(diw, nav_val.toType().abiSize(pt));
1965 try uleb128(diw, nav_val.toType().abiAlignment(pt).toByteUnits().?);
1966 for (0..loaded_struct.field_types.len) |field_index| {
1967 const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
1968 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
1969 if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
1970 const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
1971 defer dwarf.gpa.free(field_name);
1972 try wip_nav.strp(field_name);
1973 }
1974 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1975 try wip_nav.refType(field_type);
1976 if (!is_comptime) {
1977 try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
1978 try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
1979 field_type.abiAlignment(pt).toByteUnits().?);
1980 }
1981 }
1982 try uleb128(diw, @intFromEnum(AbbrevCode.null));
1983 }
1984 },
1985 .@"packed" => {
1986 try uleb128(diw, @intFromEnum(AbbrevCode.decl_packed_struct));
1987 try wip_nav.refType(Type.fromInterned(parent_type));
1988 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
1989 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
1990 try uleb128(diw, loc.column + 1);
1991 try diw.writeByte(accessibility);
1992 try wip_nav.strp(nav.name.toSlice(ip));
1993 try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
1994 var field_bit_offset: u16 = 0;
1995 for (0..loaded_struct.field_types.len) |field_index| {
1996 try uleb128(diw, @intFromEnum(@as(AbbrevCode, .packed_struct_field)));
1997 try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip));
1998 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1999 try wip_nav.refType(field_type);
2000 try uleb128(diw, field_bit_offset);
2001 field_bit_offset += @intCast(field_type.bitSize(pt));
2002 }
2003 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2004 },
2005 }
2006 break :done;
2485 }2007 }
2486 } else if (self.bin_file.cast(.wasm)) |wasm_file| {
2487 _ = wasm_file;
2488 // const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
2489 // {
2490 // const src = debug_line.items[first_fn.off..];
2491 // @memcpy(buffer[0..src.len], src);
2492 // }
2493 // try debug_line.resize(self.allocator, debug_line.items.len + delta);
2494 // @memcpy(debug_line.items[first_fn.off + delta ..][0..buffer.len], buffer);
2495 } else unreachable;
2496
2497 while (true) {
2498 const src_fn = self.getAtomPtr(.src_fn, src_fn_index);
2499 src_fn.off += delta;
2500
2501 if (src_fn.next_index) |next_index| {
2502 src_fn_index = next_index;
2503 } else break;
2504 }
2505 }
25062008
2507 // Backpatch actual length of the debug line program2009 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2508 const init_len = self.getDebugLineProgramEnd().? - init_len_size;2010 wip_nav.entry = nav_gop.value_ptr.*;
2509 switch (self.format) {2011 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2510 .dwarf32 => {2012 try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
2511 mem.writeInt(u32, di_buf.items[0..4], @intCast(init_len), target_endian);2013 try wip_nav.refType(Type.fromInterned(parent_type));
2512 },2014 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2513 .dwarf64 => {2015 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2514 mem.writeInt(u64, di_buf.items[4..][0..8], init_len, target_endian);2016 try uleb128(diw, loc.column + 1);
2017 try diw.writeByte(accessibility);
2018 try wip_nav.strp(nav.name.toSlice(ip));
2019 try wip_nav.refType(nav_val.toType());
2515 },2020 },
2516 }2021 .enum_type => done: {
2022 const loaded_enum = ip.loadEnumType(nav_val.toIntern());
2023
2024 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2025 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2026 break :parent .{
2027 parent_namespace_ptr.owner_type,
2028 if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
2029 DW.ACCESS.public
2030 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
2031 DW.ACCESS.private
2032 else
2033 unreachable,
2034 };
2035 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
2036
2037 decl_enum: {
2038 if (loaded_enum.zir_index == .none) break :decl_enum;
2039
2040 const value_inst = value_inst: {
2041 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index);
2042 const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
2043 const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
2044 if (break_inst.tag != .break_inline) break :value_inst null;
2045 assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
2046 var value_inst = break_inst.data.@"break".operand.toIndex();
2047 while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
2048 else => break,
2049 .as_node => value_inst = file.zir.extraData(
2050 Zir.Inst.As,
2051 file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
2052 ).data.operand.toIndex(),
2053 };
2054 break :value_inst value_inst;
2055 };
2056 const type_inst_info = loaded_enum.zir_index.unwrap().?.resolveFull(ip);
2057 if (type_inst_info.inst != value_inst) break :decl_enum;
25172058
2518 // We use NOPs because consumers empirically do not respect the header length field.2059 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
2519 const jmp_amt = self.getDebugLineProgramOff().? - di_buf.items.len;2060 if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
2520 if (self.bin_file.cast(.elf)) |elf_file| {2061 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2521 const debug_line_sect = &elf_file.shdrs.items[elf_file.debug_line_section_index.?];2062 type_gop.value_ptr.* = nav_gop.value_ptr.*;
2522 const file_pos = debug_line_sect.sh_offset;2063 }
2523 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);2064 wip_nav.entry = nav_gop.value_ptr.*;
2524 } else if (self.bin_file.cast(.macho)) |macho_file| {2065 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2525 if (macho_file.base.isRelocatable()) {2066 try uleb128(diw, @intFromEnum(AbbrevCode.decl_enum));
2526 const debug_line_sect = macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?];2067 try wip_nav.refType(Type.fromInterned(parent_type));
2527 const file_pos = debug_line_sect.offset;2068 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2528 try pwriteDbgLineNops(macho_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);2069 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2529 } else {2070 try uleb128(diw, loc.column + 1);
2530 const d_sym = macho_file.getDebugSymbols().?;2071 try diw.writeByte(accessibility);
2531 const debug_line_sect = d_sym.getSection(d_sym.debug_line_section_index.?);2072 try wip_nav.strp(nav.name.toSlice(ip));
2532 const file_pos = debug_line_sect.offset;2073 try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
2533 try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt);2074 for (0..loaded_enum.names.len) |field_index| {
2534 }2075 try wip_nav.enumConstValue(loaded_enum, .{
2535 } else if (self.bin_file.cast(.wasm)) |wasm_file| {2076 .signed = .signed_enum_field,
2536 _ = wasm_file;2077 .unsigned = .unsigned_enum_field,
2537 // const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;2078 }, field_index);
2538 // writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);2079 try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
2539 } else unreachable;2080 }
2540}2081 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2082 break :done;
2083 }
25412084
2542fn getDebugInfoOff(self: Dwarf) ?u32 {2085 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2543 const first_index = self.di_atom_first_index orelse return null;2086 wip_nav.entry = nav_gop.value_ptr.*;
2544 const first = self.getAtom(.di_atom, first_index);2087 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2545 return first.off;2088 try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
2546}2089 try wip_nav.refType(Type.fromInterned(parent_type));
2090 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2091 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2092 try uleb128(diw, loc.column + 1);
2093 try diw.writeByte(accessibility);
2094 try wip_nav.strp(nav.name.toSlice(ip));
2095 try wip_nav.refType(nav_val.toType());
2096 },
2097 .union_type => done: {
2098 const loaded_union = ip.loadUnionType(nav_val.toIntern());
2099
2100 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2101 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2102 break :parent .{
2103 parent_namespace_ptr.owner_type,
2104 if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
2105 DW.ACCESS.public
2106 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
2107 DW.ACCESS.private
2108 else
2109 unreachable,
2110 };
2111 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
2112
2113 decl_union: {
2114 const value_inst = value_inst: {
2115 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index);
2116 const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
2117 const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
2118 if (break_inst.tag != .break_inline) break :value_inst null;
2119 assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
2120 var value_inst = break_inst.data.@"break".operand.toIndex();
2121 while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
2122 else => break,
2123 .as_node => value_inst = file.zir.extraData(
2124 Zir.Inst.As,
2125 file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
2126 ).data.operand.toIndex(),
2127 };
2128 break :value_inst value_inst;
2129 };
2130 const type_inst_info = loaded_union.zir_index.resolveFull(ip);
2131 if (type_inst_info.inst != value_inst) break :decl_union;
25472132
2548fn getDebugInfoEnd(self: Dwarf) ?u32 {2133 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
2549 const last_index = self.di_atom_last_index orelse return null;2134 if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
2550 const last = self.getAtom(.di_atom, last_index);2135 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2551 return last.off + last.len;2136 type_gop.value_ptr.* = nav_gop.value_ptr.*;
2552}2137 }
2138 wip_nav.entry = nav_gop.value_ptr.*;
2139 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2140 try uleb128(diw, @intFromEnum(AbbrevCode.decl_union));
2141 try wip_nav.refType(Type.fromInterned(parent_type));
2142 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2143 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2144 try uleb128(diw, loc.column + 1);
2145 try diw.writeByte(accessibility);
2146 try wip_nav.strp(nav.name.toSlice(ip));
2147 const union_layout = pt.getUnionLayout(loaded_union);
2148 try uleb128(diw, union_layout.abi_size);
2149 try uleb128(diw, union_layout.abi_align.toByteUnits().?);
2150 const loaded_tag = loaded_union.loadTagType(ip);
2151 if (loaded_union.hasTag(ip)) {
2152 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
2153 try wip_nav.infoSectionOffset(
2154 .debug_info,
2155 wip_nav.unit,
2156 wip_nav.entry,
2157 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2158 );
2159 {
2160 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2161 try wip_nav.strp("tag");
2162 try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty));
2163 try uleb128(diw, union_layout.tagOffset());
2164
2165 for (0..loaded_union.field_types.len) |field_index| {
2166 try wip_nav.enumConstValue(loaded_tag, .{
2167 .signed = .signed_tagged_union_field,
2168 .unsigned = .unsigned_tagged_union_field,
2169 }, field_index);
2170 {
2171 try uleb128(diw, @intFromEnum(AbbrevCode.struct_field));
2172 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
2173 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
2174 try wip_nav.refType(field_type);
2175 try uleb128(diw, union_layout.payloadOffset());
2176 try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
2177 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(pt).toByteUnits().?);
2178 }
2179 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2180 }
2181 }
2182 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2183
2184 if (ip.indexToKey(loaded_union.enum_tag_ty).enum_type == .generated_tag)
2185 try wip_nav.pending_types.append(dwarf.gpa, loaded_union.enum_tag_ty);
2186 } else for (0..loaded_union.field_types.len) |field_index| {
2187 try uleb128(diw, @intFromEnum(AbbrevCode.untagged_union_field));
2188 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
2189 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
2190 try wip_nav.refType(field_type);
2191 try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
2192 field_type.abiAlignment(pt).toByteUnits().?);
2193 }
2194 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2195 break :done;
2196 }
25532197
2554fn getDebugLineProgramOff(self: Dwarf) ?u32 {2198 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2555 const first_index = self.src_fn_first_index orelse return null;2199 wip_nav.entry = nav_gop.value_ptr.*;
2556 const first = self.getAtom(.src_fn, first_index);2200 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2557 return first.off;2201 try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
2558}2202 try wip_nav.refType(Type.fromInterned(parent_type));
2203 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2204 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2205 try uleb128(diw, loc.column + 1);
2206 try diw.writeByte(accessibility);
2207 try wip_nav.strp(nav.name.toSlice(ip));
2208 try wip_nav.refType(nav_val.toType());
2209 },
2210 .opaque_type => done: {
2211 const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
2212
2213 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2214 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2215 break :parent .{
2216 parent_namespace_ptr.owner_type,
2217 if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
2218 DW.ACCESS.public
2219 else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
2220 DW.ACCESS.private
2221 else
2222 unreachable,
2223 };
2224 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
2225
2226 decl_opaque: {
2227 const value_inst = value_inst: {
2228 const decl_extra = file.zir.extraData(Zir.Inst.Declaration, decl_inst.data.declaration.payload_index);
2229 const decl_value_body = decl_extra.data.getBodies(@intCast(decl_extra.end), file.zir).value_body;
2230 const break_inst = file.zir.instructions.get(@intFromEnum(decl_value_body[decl_value_body.len - 1]));
2231 if (break_inst.tag != .break_inline) break :value_inst null;
2232 assert(file.zir.extraData(Zir.Inst.Break, break_inst.data.@"break".payload_index).data.block_inst == inst_info.inst);
2233 var value_inst = break_inst.data.@"break".operand.toIndex();
2234 while (value_inst) |value_inst_index| switch (file.zir.instructions.items(.tag)[@intFromEnum(value_inst_index)]) {
2235 else => break,
2236 .as_node => value_inst = file.zir.extraData(
2237 Zir.Inst.As,
2238 file.zir.instructions.items(.data)[@intFromEnum(value_inst_index)].pl_node.payload_index,
2239 ).data.operand.toIndex(),
2240 };
2241 break :value_inst value_inst;
2242 };
2243 const type_inst_info = loaded_opaque.zir_index.resolveFull(ip);
2244 if (type_inst_info.inst != value_inst) break :decl_opaque;
25592245
2560fn getDebugLineProgramEnd(self: Dwarf) ?u32 {2246 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
2561 const last_index = self.src_fn_last_index orelse return null;2247 if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
2562 const last = self.getAtom(.src_fn, last_index);2248 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2563 return last.off + last.len;2249 type_gop.value_ptr.* = nav_gop.value_ptr.*;
2564}2250 }
2251 wip_nav.entry = nav_gop.value_ptr.*;
2252 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2253 try uleb128(diw, @intFromEnum(AbbrevCode.decl_namespace_struct));
2254 try wip_nav.refType(Type.fromInterned(parent_type));
2255 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2256 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2257 try uleb128(diw, loc.column + 1);
2258 try diw.writeByte(accessibility);
2259 try wip_nav.strp(nav.name.toSlice(ip));
2260 try diw.writeByte(@intFromBool(false));
2261 break :done;
2262 }
25652263
2566/// Always 4 or 8 depending on whether this is 32-bit or 64-bit format.2264 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2567fn ptrWidthBytes(self: Dwarf) u8 {2265 wip_nav.entry = nav_gop.value_ptr.*;
2568 return switch (self.ptr_width) {2266 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2569 .p32 => 4,2267 try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
2570 .p64 => 8,2268 try wip_nav.refType(Type.fromInterned(parent_type));
2571 };2269 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
2270 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
2271 try uleb128(diw, loc.column + 1);
2272 try diw.writeByte(accessibility);
2273 try wip_nav.strp(nav.name.toSlice(ip));
2274 try wip_nav.refType(nav_val.toType());
2275 },
2276 else => {
2277 _ = dwarf.navs.pop();
2278 return;
2279 },
2280 }
2281 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2282 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items);
2283 try wip_nav.flush();
2572}2284}
25732285
2574fn dbgLineNeededHeaderBytes(self: Dwarf, dirs: []const []const u8, files: []const []const u8) u32 {2286fn updateType(
2575 var size: usize = switch (self.format) { // length field2287 dwarf: *Dwarf,
2576 .dwarf32 => 4,2288 pt: Zcu.PerThread,
2577 .dwarf64 => 12,2289 type_index: InternPool.Index,
2578 };2290 pending_types: *std.ArrayListUnmanaged(InternPool.Index),
2579 size += @sizeOf(u16); // version field2291) UpdateError!void {
2580 size += switch (self.format) { // offset to end-of-header2292 const zcu = pt.zcu;
2581 .dwarf32 => 4,2293 const ip = &zcu.intern_pool;
2582 .dwarf64 => 8,2294 const ty = Type.fromInterned(type_index);
2583 };2295 switch (type_index) {
2584 size += 18; // opcodes2296 .generic_poison_type => log.debug("updateType({s})", .{"anytype"}),
25852297 else => log.debug("updateType({})", .{ty.fmt(pt)}),
2586 for (dirs) |dir| { // include dirs
2587 size += dir.len + 1;
2588 }2298 }
2589 size += 1; // include dirs sentinel
25902299
2591 for (files) |file| { // file names2300 var wip_nav: WipNav = .{
2592 size += file.len + 1 + 1 + 1 + 1;2301 .dwarf = dwarf,
2302 .pt = pt,
2303 .unit = .main,
2304 .entry = dwarf.types.get(type_index).?,
2305 .any_children = false,
2306 .func = .none,
2307 .func_high_reloc = undefined,
2308 .debug_info = .{},
2309 .debug_line = .{},
2310 .debug_loclists = .{},
2311 .pending_types = pending_types.*,
2312 };
2313 defer {
2314 pending_types.* = wip_nav.pending_types;
2315 wip_nav.pending_types = .{};
2316 wip_nav.deinit();
2593 }2317 }
2594 size += 1; // file names sentinel2318 const diw = wip_nav.debug_info.writer(dwarf.gpa);
25952319 const name = switch (type_index) {
2596 return @intCast(size);2320 .generic_poison_type => "",
2597}2321 else => try std.fmt.allocPrint(dwarf.gpa, "{}", .{ty.fmt(pt)}),
2322 };
2323 defer dwarf.gpa.free(name);
2324
2325 switch (ip.indexToKey(type_index)) {
2326 .int_type => |int_type| {
2327 try uleb128(diw, @intFromEnum(AbbrevCode.numeric_type));
2328 try wip_nav.strp(name);
2329 try diw.writeByte(switch (int_type.signedness) {
2330 inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)),
2331 });
2332 try uleb128(diw, int_type.bits);
2333 try uleb128(diw, ty.abiSize(pt));
2334 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2335 },
2336 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
2337 .One, .Many, .C => {
2338 const ptr_child_type = Type.fromInterned(ptr_type.child);
2339 try uleb128(diw, @intFromEnum(AbbrevCode.ptr_type));
2340 try wip_nav.strp(name);
2341 try diw.writeByte(@intFromBool(ptr_type.flags.is_allowzero));
2342 try uleb128(diw, ptr_type.flags.alignment.toByteUnits() orelse
2343 ptr_child_type.abiAlignment(pt).toByteUnits().?);
2344 try diw.writeByte(@intFromEnum(ptr_type.flags.address_space));
2345 if (ptr_type.flags.is_const or ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
2346 .debug_info,
2347 wip_nav.unit,
2348 wip_nav.entry,
2349 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2350 ) else try wip_nav.refType(ptr_child_type);
2351 if (ptr_type.flags.is_const) {
2352 try uleb128(diw, @intFromEnum(AbbrevCode.is_const));
2353 if (ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
2354 .debug_info,
2355 wip_nav.unit,
2356 wip_nav.entry,
2357 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2358 ) else try wip_nav.refType(ptr_child_type);
2359 }
2360 if (ptr_type.flags.is_volatile) {
2361 try uleb128(diw, @intFromEnum(AbbrevCode.is_volatile));
2362 try wip_nav.refType(ptr_child_type);
2363 }
2364 },
2365 .Slice => {
2366 try uleb128(diw, @intFromEnum(AbbrevCode.struct_type));
2367 try wip_nav.strp(name);
2368 try uleb128(diw, ty.abiSize(pt));
2369 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2370 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2371 try wip_nav.strp("ptr");
2372 const ptr_field_type = ty.slicePtrFieldType(zcu);
2373 try wip_nav.refType(ptr_field_type);
2374 try uleb128(diw, 0);
2375 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2376 try wip_nav.strp("len");
2377 const len_field_type = Type.usize;
2378 try wip_nav.refType(len_field_type);
2379 try uleb128(diw, len_field_type.abiAlignment(pt).forward(ptr_field_type.abiSize(pt)));
2380 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2381 },
2382 },
2383 inline .array_type, .vector_type => |array_type, ty_tag| {
2384 try uleb128(diw, @intFromEnum(AbbrevCode.array_type));
2385 try wip_nav.strp(name);
2386 try wip_nav.refType(Type.fromInterned(array_type.child));
2387 try diw.writeByte(@intFromBool(ty_tag == .vector_type));
2388 try uleb128(diw, @intFromEnum(AbbrevCode.array_index));
2389 try wip_nav.refType(Type.usize);
2390 try uleb128(diw, array_type.len);
2391 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2392 },
2393 .opt_type => |opt_child_type_index| {
2394 const opt_child_type = Type.fromInterned(opt_child_type_index);
2395 try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
2396 try wip_nav.strp(name);
2397 try uleb128(diw, ty.abiSize(pt));
2398 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2399 if (opt_child_type.isNoReturn(zcu)) {
2400 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2401 try wip_nav.strp("null");
2402 try wip_nav.refType(Type.null);
2403 try uleb128(diw, 0);
2404 } else {
2405 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
2406 try wip_nav.infoSectionOffset(
2407 .debug_info,
2408 wip_nav.unit,
2409 wip_nav.entry,
2410 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2411 );
2412 {
2413 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2414 try wip_nav.strp("has_value");
2415 const repr: enum { unpacked, error_set, pointer } = switch (opt_child_type_index) {
2416 .anyerror_type => .error_set,
2417 else => switch (ip.indexToKey(opt_child_type_index)) {
2418 else => .unpacked,
2419 .error_set_type, .inferred_error_set_type => .error_set,
2420 .ptr_type => |ptr_type| if (ptr_type.flags.is_allowzero) .unpacked else .pointer,
2421 },
2422 };
2423 switch (repr) {
2424 .unpacked => {
2425 try wip_nav.refType(Type.bool);
2426 try uleb128(diw, if (opt_child_type.hasRuntimeBits(pt))
2427 opt_child_type.abiSize(pt)
2428 else
2429 0);
2430 },
2431 .error_set => {
2432 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
2433 .signedness = .unsigned,
2434 .bits = pt.zcu.errorSetBits(),
2435 } })));
2436 try uleb128(diw, 0);
2437 },
2438 .pointer => {
2439 try wip_nav.refType(Type.usize);
2440 try uleb128(diw, 0);
2441 },
2442 }
25982443
2599/// The reloc offset for the line offset of a function from the previous function's line.2444 try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_tagged_union_field));
2600/// It's a fixed-size 4-byte ULEB128.2445 try uleb128(diw, 0);
2601fn getRelocDbgLineOff(self: Dwarf) usize {2446 {
2602 return dbg_line_vaddr_reloc_index + self.ptrWidthBytes() + 1;2447 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2603}2448 try wip_nav.strp("null");
2449 try wip_nav.refType(Type.null);
2450 try uleb128(diw, 0);
2451 }
2452 try uleb128(diw, @intFromEnum(AbbrevCode.null));
26042453
2605fn getRelocDbgFileIndex(self: Dwarf) usize {2454 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union_default_field));
2606 return self.getRelocDbgLineOff() + 5;2455 {
2607}2456 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2457 try wip_nav.strp("?");
2458 try wip_nav.refType(opt_child_type);
2459 try uleb128(diw, 0);
2460 }
2461 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2462 }
2463 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2464 }
2465 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2466 },
2467 .anyframe_type => unreachable,
2468 .error_union_type => |error_union_type| {
2469 const error_union_error_set_type = Type.fromInterned(error_union_type.error_set_type);
2470 const error_union_payload_type = Type.fromInterned(error_union_type.payload_type);
2471 const error_union_error_set_offset = codegen.errUnionErrorOffset(error_union_payload_type, pt);
2472 const error_union_payload_offset = codegen.errUnionPayloadOffset(error_union_payload_type, pt);
2473
2474 try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
2475 try wip_nav.strp(name);
2476 try uleb128(diw, ty.abiSize(pt));
2477 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2478 {
2479 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
2480 try wip_nav.infoSectionOffset(
2481 .debug_info,
2482 wip_nav.unit,
2483 wip_nav.entry,
2484 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2485 );
2486 {
2487 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2488 try wip_nav.strp("is_error");
2489 const is_error_field_type = Type.fromInterned(try pt.intern(.{
2490 .opt_type = error_union_type.error_set_type,
2491 }));
2492 try wip_nav.refType(is_error_field_type);
2493 try uleb128(diw, error_union_error_set_offset);
2494
2495 try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_tagged_union_field));
2496 try uleb128(diw, 0);
2497 {
2498 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2499 try wip_nav.strp("value");
2500 try wip_nav.refType(error_union_payload_type);
2501 try uleb128(diw, error_union_payload_offset);
2502 }
2503 try uleb128(diw, @intFromEnum(AbbrevCode.null));
26082504
2609fn getRelocDbgInfoSubprogramHighPC(self: Dwarf) u32 {2505 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union_default_field));
2610 return dbg_info_low_pc_reloc_index + self.ptrWidthBytes();2506 {
2611}2507 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2508 try wip_nav.strp("error");
2509 try wip_nav.refType(error_union_error_set_type);
2510 try uleb128(diw, error_union_error_set_offset);
2511 }
2512 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2513 }
2514 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2515 }
2516 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2517 },
2518 .simple_type => |simple_type| switch (simple_type) {
2519 .f16,
2520 .f32,
2521 .f64,
2522 .f80,
2523 .f128,
2524 .usize,
2525 .isize,
2526 .c_char,
2527 .c_short,
2528 .c_ushort,
2529 .c_int,
2530 .c_uint,
2531 .c_long,
2532 .c_ulong,
2533 .c_longlong,
2534 .c_ulonglong,
2535 .c_longdouble,
2536 .bool,
2537 => {
2538 try uleb128(diw, @intFromEnum(AbbrevCode.numeric_type));
2539 try wip_nav.strp(name);
2540 try diw.writeByte(if (type_index == .bool_type)
2541 DW.ATE.boolean
2542 else if (ty.isRuntimeFloat())
2543 DW.ATE.float
2544 else if (ty.isSignedInt(zcu))
2545 DW.ATE.signed
2546 else if (ty.isUnsignedInt(zcu))
2547 DW.ATE.unsigned
2548 else
2549 unreachable);
2550 try uleb128(diw, ty.bitSize(pt));
2551 try uleb128(diw, ty.abiSize(pt));
2552 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2553 },
2554 .anyopaque,
2555 .void,
2556 .type,
2557 .comptime_int,
2558 .comptime_float,
2559 .noreturn,
2560 .null,
2561 .undefined,
2562 .enum_literal,
2563 .generic_poison,
2564 => {
2565 try uleb128(diw, @intFromEnum(AbbrevCode.void_type));
2566 try wip_nav.strp(if (type_index == .generic_poison_type) "anytype" else name);
2567 },
2568 .anyerror => return, // delay until flush
2569 .atomic_order,
2570 .atomic_rmw_op,
2571 .calling_convention,
2572 .address_space,
2573 .float_mode,
2574 .reduce_op,
2575 .call_modifier,
2576 .prefetch_options,
2577 .export_options,
2578 .extern_options,
2579 .type_info,
2580 .adhoc_inferred_error_set,
2581 => unreachable,
2582 },
2583 .struct_type,
2584 .union_type,
2585 .opaque_type,
2586 => unreachable,
2587 .anon_struct_type => |anon_struct_type| {
2588 try uleb128(diw, @intFromEnum(AbbrevCode.struct_type));
2589 try wip_nav.strp(name);
2590 try uleb128(diw, ty.abiSize(pt));
2591 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2592 var field_byte_offset: u64 = 0;
2593 for (0..anon_struct_type.types.len) |field_index| {
2594 const comptime_value = anon_struct_type.values.get(ip)[field_index];
2595 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (comptime_value != .none) .struct_field_comptime else .struct_field)));
2596 if (anon_struct_type.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
2597 const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
2598 defer dwarf.gpa.free(field_name);
2599 try wip_nav.strp(field_name);
2600 }
2601 const field_type = Type.fromInterned(anon_struct_type.types.get(ip)[field_index]);
2602 try wip_nav.refType(field_type);
2603 if (comptime_value == .none) {
2604 const field_align = field_type.abiAlignment(pt);
2605 field_byte_offset = field_align.forward(field_byte_offset);
2606 try uleb128(diw, field_byte_offset);
2607 try uleb128(diw, field_type.abiAlignment(pt).toByteUnits().?);
2608 field_byte_offset += field_type.abiSize(pt);
2609 }
2610 }
2611 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2612 },
2613 .enum_type => {
2614 const loaded_enum = ip.loadEnumType(type_index);
2615 try uleb128(diw, @intFromEnum(AbbrevCode.enum_type));
2616 try wip_nav.strp(name);
2617 try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
2618 for (0..loaded_enum.names.len) |field_index| {
2619 try wip_nav.enumConstValue(loaded_enum, .{
2620 .signed = .signed_enum_field,
2621 .unsigned = .unsigned_enum_field,
2622 }, field_index);
2623 try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
2624 }
2625 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2626 },
2627 .func_type => |func_type| {
2628 const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
2629 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_nullary) .nullary_func_type else .func_type)));
2630 try wip_nav.strp(name);
2631 try diw.writeByte(@intFromEnum(@as(DW.CC, switch (func_type.cc) {
2632 .Unspecified, .C => .normal,
2633 .Naked, .Async, .Inline => .nocall,
2634 .Interrupt, .Signal => .nocall,
2635 .Stdcall => .BORLAND_stdcall,
2636 .Fastcall => .BORLAND_fastcall,
2637 .Vectorcall => .LLVM_vectorcall,
2638 .Thiscall => .BORLAND_thiscall,
2639 .APCS => .nocall,
2640 .AAPCS => .LLVM_AAPCS,
2641 .AAPCSVFP => .LLVM_AAPCS_VFP,
2642 .SysV => .LLVM_X86_64SysV,
2643 .Win64 => .LLVM_Win64,
2644 .Kernel, .Fragment, .Vertex => .nocall,
2645 })));
2646 try wip_nav.refType(Type.fromInterned(func_type.return_type));
2647 if (!is_nullary) {
2648 for (0..func_type.param_types.len) |param_index| {
2649 try uleb128(diw, @intFromEnum(AbbrevCode.func_type_param));
2650 try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index]));
2651 }
2652 if (func_type.is_var_args) try uleb128(diw, @intFromEnum(AbbrevCode.is_var_args));
2653 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2654 }
2655 },
2656 .error_set_type => |error_set_type| {
2657 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (error_set_type.names.len > 0) .enum_type else .empty_enum_type)));
2658 try wip_nav.strp(name);
2659 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
2660 .signedness = .unsigned,
2661 .bits = pt.zcu.errorSetBits(),
2662 } })));
2663 for (0..error_set_type.names.len) |field_index| {
2664 const field_name = error_set_type.names.get(ip)[field_index];
2665 try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_enum_field));
2666 try uleb128(diw, ip.getErrorValueIfExists(field_name).?);
2667 try wip_nav.strp(field_name.toSlice(ip));
2668 }
2669 if (error_set_type.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
2670 },
2671 .inferred_error_set_type => |func| {
2672 try uleb128(diw, @intFromEnum(AbbrevCode.inferred_error_set_type));
2673 try wip_nav.strp(name);
2674 try wip_nav.refType(Type.fromInterned(ip.funcIesResolvedUnordered(func)));
2675 },
26122676
2613fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {2677 // values, not types
2614 return actual_size +| (actual_size / ideal_factor);2678 .undef,
2679 .simple_value,
2680 .variable,
2681 .@"extern",
2682 .func,
2683 .int,
2684 .err,
2685 .error_union,
2686 .enum_literal,
2687 .enum_tag,
2688 .empty_enum_value,
2689 .float,
2690 .ptr,
2691 .slice,
2692 .opt,
2693 .aggregate,
2694 .un,
2695 // memoization, not types
2696 .memoized_call,
2697 => unreachable,
2698 }
2699 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2615}2700}
26162701
2617pub fn flushModule(self: *Dwarf, pt: Zcu.PerThread) !void {2702pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternPool.Index) UpdateError!void {
2618 const comp = self.bin_file.comp;2703 const zcu = pt.zcu;
2619 const target = comp.root_mod.resolved_target.result;2704 const ip = &zcu.intern_pool;
26202705 const ty = Type.fromInterned(type_index);
2621 if (self.global_abbrev_relocs.items.len > 0) {2706 log.debug("updateContainerType({}({d}))", .{ ty.fmt(pt), @intFromEnum(type_index) });
2622 const gpa = self.allocator;2707
2623 var arena_alloc = std.heap.ArenaAllocator.init(gpa);2708 const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip);
2624 defer arena_alloc.deinit();2709 const file = zcu.fileByIndex(inst_info.file);
2625 const arena = arena_alloc.allocator();2710 if (inst_info.inst == .main_struct_inst) {
26262711 const unit = try dwarf.getUnit(file.mod);
2627 var dbg_info_buffer = std.ArrayList(u8).init(arena);2712 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
2628 try addDbgInfoErrorSetNames(2713 if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2629 pt,2714 var wip_nav: WipNav = .{
2630 Type.anyerror,2715 .dwarf = dwarf,
2631 pt.zcu.intern_pool.global_error_set.getNamesFromMainThread(),2716 .pt = pt,
2632 target,2717 .unit = unit,
2633 &dbg_info_buffer,2718 .entry = type_gop.value_ptr.*,
2634 );2719 .any_children = false,
26352720 .func = .none,
2636 const di_atom_index = try self.createAtom(.di_atom);2721 .func_high_reloc = undefined,
2637 log.debug("updateNavDebugInfoAllocation in flushModule", .{});2722 .debug_info = .{},
2638 try self.updateNavDebugInfoAllocation(di_atom_index, @intCast(dbg_info_buffer.items.len));2723 .debug_line = .{},
2639 log.debug("writeNavDebugInfo in flushModule", .{});2724 .debug_loclists = .{},
2640 try self.writeNavDebugInfo(di_atom_index, dbg_info_buffer.items);2725 .pending_types = .{},
26412726 };
2642 const file_pos = if (self.bin_file.cast(.elf)) |elf_file| pos: {2727 defer wip_nav.deinit();
2643 const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?];2728
2644 break :pos debug_info_sect.sh_offset;2729 const loaded_struct = ip.loadStructType(type_index);
2645 } else if (self.bin_file.cast(.macho)) |macho_file| pos: {2730
2646 if (macho_file.base.isRelocatable()) {2731 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2647 const debug_info_sect = &macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?];2732 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0) .namespace_file else .file)));
2648 break :pos debug_info_sect.offset;2733 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
2649 } else {2734 try uleb128(diw, file_gop.index);
2650 const d_sym = macho_file.getDebugSymbols().?;2735 try wip_nav.strp(loaded_struct.name.toSlice(ip));
2651 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);2736 if (loaded_struct.field_types.len > 0) {
2652 break :pos debug_info_sect.offset;2737 try uleb128(diw, ty.abiSize(pt));
2738 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2739 for (0..loaded_struct.field_types.len) |field_index| {
2740 const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
2741 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
2742 if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
2743 const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
2744 defer dwarf.gpa.free(field_name);
2745 try wip_nav.strp(field_name);
2746 }
2747 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
2748 try wip_nav.refType(field_type);
2749 if (!is_comptime) {
2750 try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
2751 try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
2752 field_type.abiAlignment(pt).toByteUnits().?);
2753 }
2653 }2754 }
2654 } else if (self.bin_file.cast(.wasm)) |_|2755 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2655 // for wasm, the offset is always 0 as we write to memory first2756 }
2656 0
2657 else
2658 unreachable;
26592757
2660 var buf: [@sizeOf(u32)]u8 = undefined;2758 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2661 mem.writeInt(u32, &buf, self.getAtom(.di_atom, di_atom_index).off, target.cpu.arch.endian());2759 try wip_nav.flush();
26622760 } else {
2663 while (self.global_abbrev_relocs.popOrNull()) |reloc| {2761 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
2664 const atom = self.getAtom(.di_atom, reloc.atom_index);2762 assert(decl_inst.tag == .extended);
2665 if (self.bin_file.cast(.elf)) |elf_file| {2763 if (switch (decl_inst.data.extended.opcode) {
2666 try elf_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset);2764 .struct_decl => @as(Zir.Inst.StructDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
2667 } else if (self.bin_file.cast(.macho)) |macho_file| {2765 .enum_decl => @as(Zir.Inst.EnumDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
2668 if (macho_file.base.isRelocatable()) {2766 .union_decl => @as(Zir.Inst.UnionDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
2669 try macho_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset);2767 .opaque_decl => @as(Zir.Inst.OpaqueDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
2670 } else {2768 .reify => @as(Zir.Inst.NameStrategy, @enumFromInt(decl_inst.data.extended.small)),
2671 const d_sym = macho_file.getDebugSymbols().?;2769 else => unreachable,
2672 try d_sym.file.pwriteAll(&buf, file_pos + atom.off + reloc.offset);2770 } == .parent) return;
2771
2772 const unit = try dwarf.getUnit(file.mod);
2773 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
2774 if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2775 var wip_nav: WipNav = .{
2776 .dwarf = dwarf,
2777 .pt = pt,
2778 .unit = unit,
2779 .entry = type_gop.value_ptr.*,
2780 .any_children = false,
2781 .func = .none,
2782 .func_high_reloc = undefined,
2783 .debug_info = .{},
2784 .debug_line = .{},
2785 .debug_loclists = .{},
2786 .pending_types = .{},
2787 };
2788 defer wip_nav.deinit();
2789 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2790 const name = try std.fmt.allocPrint(dwarf.gpa, "{}", .{ty.fmt(pt)});
2791 defer dwarf.gpa.free(name);
2792
2793 switch (ip.indexToKey(type_index)) {
2794 .struct_type => {
2795 const loaded_struct = ip.loadStructType(type_index);
2796 switch (loaded_struct.layout) {
2797 .auto, .@"extern" => {
2798 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0)
2799 .namespace_struct_type
2800 else
2801 .struct_type)));
2802 try wip_nav.strp(name);
2803 if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
2804 try uleb128(diw, ty.abiSize(pt));
2805 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
2806 for (0..loaded_struct.field_types.len) |field_index| {
2807 const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
2808 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
2809 if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
2810 const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
2811 defer dwarf.gpa.free(field_name);
2812 try wip_nav.strp(field_name);
2813 }
2814 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
2815 try wip_nav.refType(field_type);
2816 if (!is_comptime) {
2817 try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]);
2818 try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
2819 field_type.abiAlignment(pt).toByteUnits().?);
2820 }
2821 }
2822 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2823 }
2824 },
2825 .@"packed" => {
2826 try uleb128(diw, @intFromEnum(AbbrevCode.packed_struct_type));
2827 try wip_nav.strp(name);
2828 try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
2829 var field_bit_offset: u16 = 0;
2830 for (0..loaded_struct.field_types.len) |field_index| {
2831 try uleb128(diw, @intFromEnum(@as(AbbrevCode, .packed_struct_field)));
2832 try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip));
2833 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
2834 try wip_nav.refType(field_type);
2835 try uleb128(diw, field_bit_offset);
2836 field_bit_offset += @intCast(field_type.bitSize(pt));
2837 }
2838 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2839 },
2840 }
2841 },
2842 .enum_type => {
2843 const loaded_enum = ip.loadEnumType(type_index);
2844 try uleb128(diw, @intFromEnum(AbbrevCode.enum_type));
2845 try wip_nav.strp(name);
2846 try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
2847 for (0..loaded_enum.names.len) |field_index| {
2848 try wip_nav.enumConstValue(loaded_enum, .{
2849 .signed = .signed_enum_field,
2850 .unsigned = .unsigned_enum_field,
2851 }, field_index);
2852 try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
2673 }2853 }
2674 } else if (self.bin_file.cast(.wasm)) |wasm_file| {2854 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2675 _ = wasm_file;2855 },
2676 // const debug_info = wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;2856 .union_type => {
2677 // debug_info.items[atom.off + reloc.offset ..][0..buf.len].* = buf;2857 const loaded_union = ip.loadUnionType(type_index);
2678 } else unreachable;2858 try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
2859 try wip_nav.strp(name);
2860 const union_layout = pt.getUnionLayout(loaded_union);
2861 try uleb128(diw, union_layout.abi_size);
2862 try uleb128(diw, union_layout.abi_align.toByteUnits().?);
2863 const loaded_tag = loaded_union.loadTagType(ip);
2864 if (loaded_union.hasTag(ip)) {
2865 try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
2866 try wip_nav.infoSectionOffset(
2867 .debug_info,
2868 wip_nav.unit,
2869 wip_nav.entry,
2870 @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
2871 );
2872 {
2873 try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
2874 try wip_nav.strp("tag");
2875 try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty));
2876 try uleb128(diw, union_layout.tagOffset());
2877
2878 for (0..loaded_union.field_types.len) |field_index| {
2879 try wip_nav.enumConstValue(loaded_tag, .{
2880 .signed = .signed_tagged_union_field,
2881 .unsigned = .unsigned_tagged_union_field,
2882 }, field_index);
2883 {
2884 try uleb128(diw, @intFromEnum(AbbrevCode.struct_field));
2885 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
2886 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
2887 try wip_nav.refType(field_type);
2888 try uleb128(diw, union_layout.payloadOffset());
2889 try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
2890 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(pt).toByteUnits().?);
2891 }
2892 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2893 }
2894 }
2895 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2896
2897 if (ip.indexToKey(loaded_union.enum_tag_ty).enum_type == .generated_tag)
2898 try wip_nav.pending_types.append(dwarf.gpa, loaded_union.enum_tag_ty);
2899 } else for (0..loaded_union.field_types.len) |field_index| {
2900 try uleb128(diw, @intFromEnum(AbbrevCode.untagged_union_field));
2901 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
2902 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
2903 try wip_nav.refType(field_type);
2904 try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
2905 field_type.abiAlignment(pt).toByteUnits().?);
2906 }
2907 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2908 },
2909 .opaque_type => {
2910 try uleb128(diw, @intFromEnum(AbbrevCode.namespace_struct_type));
2911 try wip_nav.strp(name);
2912 try diw.writeByte(@intFromBool(true));
2913 },
2914 else => unreachable,
2679 }2915 }
2916 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2917 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items);
2918 try wip_nav.flush();
2680 }2919 }
2681}2920}
26822921
2683fn addDIFile(self: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !u28 {2922pub fn updateNavLineNumber(dwarf: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.Index) UpdateError!void {
2684 const file_scope = zcu.navFileScope(nav_index);2923 const ip = &zcu.intern_pool;
2685 const gop = try self.di_files.getOrPut(self.allocator, file_scope);2924
2686 if (!gop.found_existing) {2925 const zir_index = ip.getCau(ip.getNav(nav_index).analysis_owner.unwrap() orelse return).zir_index;
2687 if (self.bin_file.cast(.elf)) |elf_file| {2926 const inst_info = zir_index.resolveFull(ip);
2688 elf_file.markDirty(elf_file.debug_line_section_index.?);2927 assert(inst_info.inst != .main_struct_inst);
2689 } else if (self.bin_file.cast(.macho)) |macho_file| {2928 const file = zcu.fileByIndex(inst_info.file);
2690 if (macho_file.base.isRelocatable()) {2929
2691 macho_file.markDirty(macho_file.debug_line_sect_index.?);2930 const inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
2692 } else {2931 assert(inst.tag == .declaration);
2693 const d_sym = macho_file.getDebugSymbols().?;2932 const line = file.zir.extraData(Zir.Inst.Declaration, inst.data.declaration.payload_index).data.src_line;
2694 d_sym.markDirty(d_sym.debug_line_section_index.?, macho_file);2933 var line_buf: [4]u8 = undefined;
2695 }2934 std.mem.writeInt(u32, &line_buf, line, dwarf.endian);
2696 } else if (self.bin_file.cast(.wasm)) |_| {} else unreachable;2935
2697 }2936 const unit = dwarf.debug_line.section.getUnit(dwarf.mods.get(file.mod).?);
2698 return @intCast(gop.index + 1);2937 const entry = unit.getEntry(dwarf.navs.get(nav_index).?);
2938 try dwarf.getFile().?.pwriteAll(&line, dwarf.debug_line.section.off + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf));
2699}2939}
27002940
2701fn genIncludeDirsAndFileNames(self: *Dwarf, arena: Allocator) !struct {2941pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void {
2702 dirs: []const []const u8,2942 _ = dwarf;
2703 files: []const []const u8,2943 _ = nav_index;
2704 files_dirs_indexes: []u28,2944}
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;
27252945
2726 const dir_index: u28 = index: {2946pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
2727 const dirs_gop = dirs.getOrPutAssumeCapacity(try arena.dupe(u8, resolved));2947 const ip = &pt.zcu.intern_pool;
2728 break :index @intCast(dirs_gop.index + 1);2948 if (dwarf.types.get(.anyerror_type)) |entry| {
2949 var wip_nav: WipNav = .{
2950 .dwarf = dwarf,
2951 .pt = pt,
2952 .unit = .main,
2953 .entry = entry,
2954 .any_children = false,
2955 .func = .none,
2956 .func_high_reloc = undefined,
2957 .debug_info = .{},
2958 .debug_line = .{},
2959 .debug_loclists = .{},
2960 .pending_types = .{},
2729 };2961 };
2962 defer wip_nav.deinit();
2963 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2964 const global_error_set_names = ip.global_error_set.getNamesFromMainThread();
2965 try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (global_error_set_names.len > 0) .enum_type else .empty_enum_type)));
2966 try wip_nav.strp("anyerror");
2967 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
2968 .signedness = .unsigned,
2969 .bits = pt.zcu.errorSetBits(),
2970 } })));
2971 for (global_error_set_names, 1..) |name, value| {
2972 try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_enum_field));
2973 try uleb128(diw, value);
2974 try wip_nav.strp(name.toSlice(ip));
2975 }
2976 if (global_error_set_names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
2977 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2978 }
27302979
2731 files_dir_indexes.appendAssumeCapacity(dir_index);2980 {
2732 files.appendAssumeCapacity(sub_file_path);2981 const cwd = try std.process.getCwdAlloc(dwarf.gpa);
2982 defer dwarf.gpa.free(cwd);
2983 for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {
2984 const root_dir_path = try std.fs.path.resolve(dwarf.gpa, &.{
2985 cwd,
2986 mod.root.root_dir.path orelse "",
2987 mod.root.sub_path,
2988 });
2989 defer dwarf.gpa.free(root_dir_path);
2990 mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);
2991 }
2733 }2992 }
27342993
2735 return .{2994 var header = std.ArrayList(u8).init(dwarf.gpa);
2736 .dirs = dirs.keys(),2995 defer header.deinit();
2737 .files = files.items,2996 if (dwarf.debug_abbrev.section.dirty) {
2738 .files_dirs_indexes = files_dir_indexes.items,2997 for (1.., &AbbrevCode.abbrevs) |code, *abbrev| {
2739 };2998 try uleb128(header.writer(), code);
2999 try uleb128(header.writer(), @intFromEnum(abbrev.tag));
3000 try header.append(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no);
3001 for (abbrev.attrs) |*attr| {
3002 try uleb128(header.writer(), @intFromEnum(attr[0]));
3003 try uleb128(header.writer(), @intFromEnum(attr[1]));
3004 }
3005 try header.appendSlice(&.{ 0, 0 });
3006 }
3007 try header.append(@intFromEnum(AbbrevCode.null));
3008 try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, DebugAbbrev.entry, dwarf, header.items);
3009 dwarf.debug_abbrev.section.dirty = false;
3010 }
3011 if (dwarf.debug_aranges.section.dirty) {
3012 for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| {
3013 const unit: Unit.Index = @enumFromInt(unit_index);
3014 try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 1);
3015 header.clearRetainingCapacity();
3016 try header.ensureTotalCapacity(unit_ptr.header_len);
3017 const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
3018 dwarf.debug_aranges.section.getUnit(next_unit).off
3019 else
3020 dwarf.debug_aranges.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
3021 switch (dwarf.format) {
3022 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3023 .@"64" => {
3024 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3025 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3026 },
3027 }
3028 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 2, dwarf.endian);
3029 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3030 .source_off = @intCast(header.items.len),
3031 .target_sec = .debug_info,
3032 .target_unit = unit,
3033 });
3034 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3035 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
3036 header.appendNTimesAssumeCapacity(0, unit_ptr.header_len - header.items.len);
3037 try unit_ptr.replaceHeader(&dwarf.debug_aranges.section, dwarf, header.items);
3038 try unit_ptr.writeTrailer(&dwarf.debug_aranges.section, dwarf);
3039 }
3040 dwarf.debug_aranges.section.dirty = false;
3041 }
3042 if (dwarf.debug_info.section.dirty) {
3043 for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| {
3044 const unit: Unit.Index = @enumFromInt(unit_index);
3045 try unit_ptr.cross_unit_relocs.ensureUnusedCapacity(dwarf.gpa, 1);
3046 try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 7);
3047 header.clearRetainingCapacity();
3048 try header.ensureTotalCapacity(unit_ptr.header_len);
3049 const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
3050 dwarf.debug_info.section.getUnit(next_unit).off
3051 else
3052 dwarf.debug_info.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
3053 switch (dwarf.format) {
3054 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3055 .@"64" => {
3056 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3057 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3058 },
3059 }
3060 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
3061 header.appendSliceAssumeCapacity(&.{ DW.UT.compile, @intFromEnum(dwarf.address_size) });
3062 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3063 .source_off = @intCast(header.items.len),
3064 .target_sec = .debug_abbrev,
3065 .target_unit = DebugAbbrev.unit,
3066 .target_entry = DebugAbbrev.entry.toOptional(),
3067 });
3068 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3069 const compile_unit_off: u32 = @intCast(header.items.len);
3070 uleb128(header.fixedWriter(), @intFromEnum(AbbrevCode.compile_unit)) catch unreachable;
3071 header.appendAssumeCapacity(DW.LANG.Zig);
3072 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3073 .source_off = @intCast(header.items.len),
3074 .target_sec = .debug_line_str,
3075 .target_unit = StringSection.unit,
3076 .target_entry = (try dwarf.debug_line_str.addString(dwarf, "zig " ++ @import("build_options").version)).toOptional(),
3077 });
3078 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3079 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3080 .source_off = @intCast(header.items.len),
3081 .target_sec = .debug_line_str,
3082 .target_unit = StringSection.unit,
3083 .target_entry = mod_info.root_dir_path.toOptional(),
3084 });
3085 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3086 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3087 .source_off = @intCast(header.items.len),
3088 .target_sec = .debug_line_str,
3089 .target_unit = StringSection.unit,
3090 .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod.root_src_path)).toOptional(),
3091 });
3092 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3093 unit_ptr.cross_unit_relocs.appendAssumeCapacity(.{
3094 .source_off = @intCast(header.items.len),
3095 .target_unit = .main,
3096 .target_off = compile_unit_off,
3097 });
3098 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3099 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3100 .source_off = @intCast(header.items.len),
3101 .target_sec = .debug_line,
3102 .target_unit = unit,
3103 });
3104 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3105 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3106 .source_off = @intCast(header.items.len),
3107 .target_sec = .debug_rnglists,
3108 .target_unit = unit,
3109 .target_off = DebugRngLists.baseOffset(dwarf),
3110 });
3111 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3112 uleb128(header.fixedWriter(), 0) catch unreachable;
3113 uleb128(header.fixedWriter(), @intFromEnum(AbbrevCode.module)) catch unreachable;
3114 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3115 .source_off = @intCast(header.items.len),
3116 .target_sec = .debug_str,
3117 .target_unit = StringSection.unit,
3118 .target_entry = (try dwarf.debug_str.addString(dwarf, mod.fully_qualified_name)).toOptional(),
3119 });
3120 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3121 uleb128(header.fixedWriter(), 0) catch unreachable;
3122 try unit_ptr.replaceHeader(&dwarf.debug_info.section, dwarf, header.items);
3123 try unit_ptr.writeTrailer(&dwarf.debug_info.section, dwarf);
3124 }
3125 dwarf.debug_info.section.dirty = false;
3126 }
3127 if (dwarf.debug_str.section.dirty) {
3128 const contents = dwarf.debug_str.contents.items;
3129 try dwarf.debug_str.section.resize(dwarf, contents.len);
3130 try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_str.section.off);
3131 dwarf.debug_str.section.dirty = false;
3132 }
3133 if (dwarf.debug_line.section.dirty) {
3134 for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit|
3135 try unit.resizeHeader(&dwarf.debug_line.section, dwarf, DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count())));
3136 for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| {
3137 try unit.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 2 * (1 + mod_info.files.count()));
3138 header.clearRetainingCapacity();
3139 try header.ensureTotalCapacity(unit.header_len);
3140 const unit_len = (if (unit.next.unwrap()) |next_unit|
3141 dwarf.debug_line.section.getUnit(next_unit).off
3142 else
3143 dwarf.debug_line.section.len) - unit.off - dwarf.unitLengthBytes();
3144 switch (dwarf.format) {
3145 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3146 .@"64" => {
3147 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3148 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3149 },
3150 }
3151 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
3152 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
3153 switch (dwarf.format) {
3154 inline .@"32", .@"64" => |format| std.mem.writeInt(
3155 SectionOffset(format),
3156 header.addManyAsArrayAssumeCapacity(@sizeOf(SectionOffset(format))),
3157 @intCast(unit.header_len - header.items.len),
3158 dwarf.endian,
3159 ),
3160 }
3161 const StandardOpcode = DeclValEnum(DW.LNS);
3162 header.appendSliceAssumeCapacity(&[_]u8{
3163 dwarf.debug_line.header.minimum_instruction_length,
3164 dwarf.debug_line.header.maximum_operations_per_instruction,
3165 @intFromBool(dwarf.debug_line.header.default_is_stmt),
3166 @bitCast(dwarf.debug_line.header.line_base),
3167 dwarf.debug_line.header.line_range,
3168 dwarf.debug_line.header.opcode_base,
3169 });
3170 header.appendSliceAssumeCapacity(std.enums.EnumArray(StandardOpcode, u8).init(.{
3171 .extended_op = undefined,
3172 .copy = 0,
3173 .advance_pc = 1,
3174 .advance_line = 1,
3175 .set_file = 1,
3176 .set_column = 1,
3177 .negate_stmt = 0,
3178 .set_basic_block = 0,
3179 .const_add_pc = 0,
3180 .fixed_advance_pc = 1,
3181 .set_prologue_end = 0,
3182 .set_epilogue_begin = 0,
3183 .set_isa = 1,
3184 }).values[1..dwarf.debug_line.header.opcode_base]);
3185 header.appendAssumeCapacity(1);
3186 uleb128(header.fixedWriter(), DW.LNCT.path) catch unreachable;
3187 uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable;
3188 uleb128(header.fixedWriter(), mod_info.dirs.count()) catch unreachable;
3189 for (mod_info.dirs.keys()) |dir_unit| {
3190 unit.cross_section_relocs.appendAssumeCapacity(.{
3191 .source_off = @intCast(header.items.len),
3192 .target_sec = .debug_line_str,
3193 .target_unit = StringSection.unit,
3194 .target_entry = dwarf.getModInfo(dir_unit).root_dir_path.toOptional(),
3195 });
3196 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3197 }
3198 const dir_index_info = DebugLine.dirIndexInfo(@intCast(mod_info.dirs.count()));
3199 header.appendAssumeCapacity(3);
3200 uleb128(header.fixedWriter(), DW.LNCT.path) catch unreachable;
3201 uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable;
3202 uleb128(header.fixedWriter(), DW.LNCT.directory_index) catch unreachable;
3203 uleb128(header.fixedWriter(), @intFromEnum(dir_index_info.form)) catch unreachable;
3204 uleb128(header.fixedWriter(), DW.LNCT.LLVM_source) catch unreachable;
3205 uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable;
3206 uleb128(header.fixedWriter(), mod_info.files.count()) catch unreachable;
3207 for (mod_info.files.keys()) |file_index| {
3208 const file = pt.zcu.fileByIndex(file_index);
3209 unit.cross_section_relocs.appendAssumeCapacity(.{
3210 .source_off = @intCast(header.items.len),
3211 .target_sec = .debug_line_str,
3212 .target_unit = StringSection.unit,
3213 .target_entry = (try dwarf.debug_line_str.addString(dwarf, file.sub_file_path)).toOptional(),
3214 });
3215 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3216 dwarf.writeInt(
3217 header.addManyAsSliceAssumeCapacity(dir_index_info.bytes),
3218 mod_info.dirs.getIndex(dwarf.getUnitIfExists(file.mod).?).?,
3219 );
3220 unit.cross_section_relocs.appendAssumeCapacity(.{
3221 .source_off = @intCast(header.items.len),
3222 .target_sec = .debug_line_str,
3223 .target_unit = StringSection.unit,
3224 .target_entry = (try dwarf.debug_line_str.addString(
3225 dwarf,
3226 if (file.mod.builtin_file == file) file.source else "",
3227 )).toOptional(),
3228 });
3229 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
3230 }
3231 try unit.replaceHeader(&dwarf.debug_line.section, dwarf, header.items);
3232 try unit.writeTrailer(&dwarf.debug_line.section, dwarf);
3233 }
3234 dwarf.debug_line.section.dirty = false;
3235 }
3236 if (dwarf.debug_line_str.section.dirty) {
3237 const contents = dwarf.debug_line_str.contents.items;
3238 try dwarf.debug_line_str.section.resize(dwarf, contents.len);
3239 try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off);
3240 dwarf.debug_line_str.section.dirty = false;
3241 }
3242 if (dwarf.debug_rnglists.section.dirty) {
3243 for (dwarf.debug_rnglists.section.units.items) |*unit| {
3244 header.clearRetainingCapacity();
3245 try header.ensureTotalCapacity(unit.header_len);
3246 const unit_len = (if (unit.next.unwrap()) |next_unit|
3247 dwarf.debug_rnglists.section.getUnit(next_unit).off
3248 else
3249 dwarf.debug_rnglists.section.len) - unit.off - dwarf.unitLengthBytes();
3250 switch (dwarf.format) {
3251 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3252 .@"64" => {
3253 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3254 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3255 },
3256 }
3257 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
3258 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
3259 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), 1, dwarf.endian);
3260 switch (dwarf.format) {
3261 inline .@"32", .@"64" => |format| std.mem.writeInt(
3262 SectionOffset(format),
3263 header.addManyAsArrayAssumeCapacity(@sizeOf(SectionOffset(format))),
3264 @sizeOf(SectionOffset(format)),
3265 dwarf.endian,
3266 ),
3267 }
3268 try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header.items);
3269 try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf);
3270 }
3271 dwarf.debug_rnglists.section.dirty = false;
3272 }
2740}3273}
27413274
2742fn addDbgInfoErrorSet(3275pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void {
2743 pt: Zcu.PerThread,3276 for ([_]*Section{
2744 ty: Type,3277 &dwarf.debug_abbrev.section,
2745 target: std.Target,3278 &dwarf.debug_aranges.section,
2746 dbg_info_buffer: *std.ArrayList(u8),3279 &dwarf.debug_info.section,
2747) !void {3280 &dwarf.debug_line.section,
2748 return addDbgInfoErrorSetNames(pt, ty, ty.errorSetNames(pt.zcu).get(&pt.zcu.intern_pool), target, dbg_info_buffer);3281 &dwarf.debug_line_str.section,
3282 &dwarf.debug_loclists.section,
3283 &dwarf.debug_rnglists.section,
3284 &dwarf.debug_str.section,
3285 }) |sec| try sec.resolveRelocs(dwarf);
2749}3286}
27503287
2751fn addDbgInfoErrorSetNames(3288fn DeclValEnum(comptime T: type) type {
2752 pt: Zcu.PerThread,3289 const decls = @typeInfo(T).Struct.decls;
2753 /// Used for printing the type name only.3290 @setEvalBranchQuota(7 * decls.len);
2754 ty: Type,3291 var fields: [decls.len]std.builtin.Type.EnumField = undefined;
2755 error_names: []const InternPool.NullTerminatedString,3292 var fields_len = 0;
2756 target: std.Target,3293 var min_value: ?comptime_int = null;
2757 dbg_info_buffer: *std.ArrayList(u8),3294 var max_value: ?comptime_int = null;
2758) !void {3295 for (decls) |decl| {
2759 const target_endian = target.cpu.arch.endian();3296 if (std.mem.startsWith(u8, decl.name, "HP_") or std.mem.endsWith(u8, decl.name, "_user")) continue;
27603297 const value = @field(T, decl.name);
2761 // DW.AT.enumeration_type3298 fields[fields_len] = .{ .name = decl.name, .value = value };
2762 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.enum_type));3299 fields_len += 1;
2763 // DW.AT.byte_size, DW.FORM.udata3300 if (min_value == null or min_value.? > value) min_value = value;
2764 const abi_size = Type.anyerror.abiSize(pt);3301 if (max_value == null or max_value.? < value) max_value = value;
2765 try leb128.writeUleb128(dbg_info_buffer.writer(), abi_size);3302 }
2766 // DW.AT.name, DW.FORM.string3303 return @Type(.{ .Enum = .{
2767 try ty.print(dbg_info_buffer.writer(), pt);3304 .tag_type = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0),
2768 try dbg_info_buffer.append(0);3305 .fields = fields[0..fields_len],
27693306 .decls = &.{},
2770 // DW.AT.enumerator3307 .is_exhaustive = true,
2771 const no_error = "(no error)";3308 } });
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);
2794}3309}
27953310
2796const Kind = enum { src_fn, di_atom };3311const AbbrevCode = enum(u8) {
3312 null,
3313 // padding codes must be one byte uleb128 values to function
3314 pad_1,
3315 pad_n,
3316 // decl codes are assumed to all have the same uleb128 length
3317 decl_alias,
3318 decl_enum,
3319 decl_namespace_struct,
3320 decl_struct,
3321 decl_packed_struct,
3322 decl_union,
3323 decl_var,
3324 decl_func,
3325 decl_func_empty,
3326 // the rest are unrestricted
3327 compile_unit,
3328 module,
3329 namespace_file,
3330 file,
3331 signed_enum_field,
3332 unsigned_enum_field,
3333 generated_field,
3334 struct_field,
3335 struct_field_comptime,
3336 packed_struct_field,
3337 untagged_union_field,
3338 tagged_union,
3339 signed_tagged_union_field,
3340 unsigned_tagged_union_field,
3341 tagged_union_default_field,
3342 void_type,
3343 numeric_type,
3344 inferred_error_set_type,
3345 ptr_type,
3346 is_const,
3347 is_volatile,
3348 array_type,
3349 array_index,
3350 nullary_func_type,
3351 func_type,
3352 func_type_param,
3353 is_var_args,
3354 enum_type,
3355 empty_enum_type,
3356 namespace_struct_type,
3357 struct_type,
3358 packed_struct_type,
3359 union_type,
3360 local_arg,
3361 local_var,
27973362
2798fn createAtom(self: *Dwarf, comptime kind: Kind) !Atom.Index {3363 const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_func_empty));
2799 const index = blk: {3364
2800 switch (kind) {3365 const Attr = struct {
2801 .src_fn => {3366 DeclValEnum(DW.AT),
2802 const index: Atom.Index = @intCast(self.src_fns.items.len);3367 DeclValEnum(DW.FORM),
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 }
2812 };3368 };
2813 const atom = self.getAtomPtr(kind, index);3369 const decl_abbrev_common_attrs = &[_]Attr{
2814 atom.* = .{3370 .{ .ZIG_parent, .ref_addr },
2815 .off = 0,3371 .{ .decl_line, .data4 },
2816 .len = 0,3372 .{ .decl_column, .udata },
2817 .prev_index = null,3373 .{ .accessibility, .data1 },
2818 .next_index = null,3374 .{ .name, .strp },
2819 };3375 };
2820 return index;3376 const abbrevs = std.EnumArray(AbbrevCode, struct {
2821}3377 tag: DeclValEnum(DW.TAG),
28223378 children: bool = false,
2823fn getOrCreateAtomForNav(self: *Dwarf, comptime kind: Kind, nav_index: InternPool.Nav.Index) !Atom.Index {3379 attrs: []const Attr = &.{},
2824 switch (kind) {3380 }).init(.{
2825 .src_fn => {3381 .pad_1 = .{
2826 const gop = try self.src_fn_navs.getOrPut(self.allocator, nav_index);3382 .tag = .ZIG_padding,
2827 if (!gop.found_existing) {
2828 gop.value_ptr.* = try self.createAtom(kind);
2829 }
2830 return gop.value_ptr.*;
2831 },3383 },
2832 .di_atom => {3384 .pad_n = .{
2833 const gop = try self.di_atom_navs.getOrPut(self.allocator, nav_index);3385 .tag = .ZIG_padding,
2834 if (!gop.found_existing) {3386 .attrs = &.{
2835 gop.value_ptr.* = try self.createAtom(kind);3387 .{ .ZIG_padding, .block },
2836 }3388 },
2837 return gop.value_ptr.*;3389 },
3390 .decl_alias = .{
3391 .tag = .imported_declaration,
3392 .attrs = decl_abbrev_common_attrs ++ .{
3393 .{ .import, .ref_addr },
3394 },
3395 },
3396 .decl_enum = .{
3397 .tag = .enumeration_type,
3398 .children = true,
3399 .attrs = decl_abbrev_common_attrs ++ .{
3400 .{ .type, .ref_addr },
3401 },
3402 },
3403 .decl_namespace_struct = .{
3404 .tag = .structure_type,
3405 .attrs = decl_abbrev_common_attrs ++ .{
3406 .{ .declaration, .flag },
3407 },
3408 },
3409 .decl_struct = .{
3410 .tag = .structure_type,
3411 .children = true,
3412 .attrs = decl_abbrev_common_attrs ++ .{
3413 .{ .byte_size, .udata },
3414 .{ .alignment, .udata },
3415 },
3416 },
3417 .decl_packed_struct = .{
3418 .tag = .structure_type,
3419 .children = true,
3420 .attrs = decl_abbrev_common_attrs ++ .{
3421 .{ .type, .ref_addr },
3422 },
3423 },
3424 .decl_union = .{
3425 .tag = .union_type,
3426 .children = true,
3427 .attrs = decl_abbrev_common_attrs ++ .{
3428 .{ .byte_size, .udata },
3429 .{ .alignment, .udata },
3430 },
3431 },
3432 .decl_var = .{
3433 .tag = .variable,
3434 .attrs = decl_abbrev_common_attrs ++ .{
3435 .{ .linkage_name, .strp },
3436 .{ .type, .ref_addr },
3437 .{ .location, .exprloc },
3438 .{ .alignment, .udata },
3439 .{ .external, .flag },
3440 },
3441 },
3442 .decl_func = .{
3443 .tag = .subprogram,
3444 .children = true,
3445 .attrs = decl_abbrev_common_attrs ++ .{
3446 .{ .linkage_name, .strp },
3447 .{ .type, .ref_addr },
3448 .{ .low_pc, .addr },
3449 .{ .high_pc, .addr },
3450 .{ .alignment, .udata },
3451 .{ .external, .flag },
3452 .{ .noreturn, .flag },
3453 },
3454 },
3455 .decl_func_empty = .{
3456 .tag = .subprogram,
3457 .attrs = decl_abbrev_common_attrs ++ .{
3458 .{ .linkage_name, .strp },
3459 .{ .type, .ref_addr },
3460 .{ .low_pc, .addr },
3461 .{ .high_pc, .addr },
3462 .{ .alignment, .udata },
3463 .{ .external, .flag },
3464 .{ .noreturn, .flag },
3465 },
3466 },
3467 .compile_unit = .{
3468 .tag = .compile_unit,
3469 .children = true,
3470 .attrs = &.{
3471 .{ .language, .data1 },
3472 .{ .producer, .line_strp },
3473 .{ .comp_dir, .line_strp },
3474 .{ .name, .line_strp },
3475 .{ .base_types, .ref_addr },
3476 .{ .stmt_list, .sec_offset },
3477 .{ .rnglists_base, .sec_offset },
3478 .{ .ranges, .rnglistx },
3479 },
3480 },
3481 .module = .{
3482 .tag = .module,
3483 .children = true,
3484 .attrs = &.{
3485 .{ .name, .strp },
3486 .{ .ranges, .rnglistx },
3487 },
3488 },
3489 .namespace_file = .{
3490 .tag = .structure_type,
3491 .attrs = &.{
3492 .{ .decl_file, .udata },
3493 .{ .name, .strp },
3494 },
3495 },
3496 .file = .{
3497 .tag = .structure_type,
3498 .children = true,
3499 .attrs = &.{
3500 .{ .decl_file, .udata },
3501 .{ .name, .strp },
3502 .{ .byte_size, .udata },
3503 .{ .alignment, .udata },
3504 },
3505 },
3506 .signed_enum_field = .{
3507 .tag = .enumerator,
3508 .attrs = &.{
3509 .{ .const_value, .sdata },
3510 .{ .name, .strp },
3511 },
3512 },
3513 .unsigned_enum_field = .{
3514 .tag = .enumerator,
3515 .attrs = &.{
3516 .{ .const_value, .udata },
3517 .{ .name, .strp },
3518 },
3519 },
3520 .generated_field = .{
3521 .tag = .member,
3522 .attrs = &.{
3523 .{ .name, .strp },
3524 .{ .type, .ref_addr },
3525 .{ .data_member_location, .udata },
3526 .{ .artificial, .flag_present },
3527 },
3528 },
3529 .struct_field = .{
3530 .tag = .member,
3531 .attrs = &.{
3532 .{ .name, .strp },
3533 .{ .type, .ref_addr },
3534 .{ .data_member_location, .udata },
3535 .{ .alignment, .udata },
3536 },
3537 },
3538 .struct_field_comptime = .{
3539 .tag = .member,
3540 .attrs = &.{
3541 .{ .name, .strp },
3542 .{ .type, .ref_addr },
3543 .{ .const_expr, .flag_present },
3544 },
3545 },
3546 .packed_struct_field = .{
3547 .tag = .member,
3548 .attrs = &.{
3549 .{ .name, .strp },
3550 .{ .type, .ref_addr },
3551 .{ .data_bit_offset, .udata },
3552 },
3553 },
3554 .untagged_union_field = .{
3555 .tag = .member,
3556 .attrs = &.{
3557 .{ .name, .strp },
3558 .{ .type, .ref_addr },
3559 .{ .alignment, .udata },
3560 },
3561 },
3562 .tagged_union = .{
3563 .tag = .variant_part,
3564 .children = true,
3565 .attrs = &.{
3566 .{ .discr, .ref_addr },
3567 },
3568 },
3569 .signed_tagged_union_field = .{
3570 .tag = .variant,
3571 .children = true,
3572 .attrs = &.{
3573 .{ .discr_value, .sdata },
3574 },
3575 },
3576 .unsigned_tagged_union_field = .{
3577 .tag = .variant,
3578 .children = true,
3579 .attrs = &.{
3580 .{ .discr_value, .udata },
3581 },
3582 },
3583 .tagged_union_default_field = .{
3584 .tag = .variant,
3585 .children = true,
3586 .attrs = &.{},
3587 },
3588 .void_type = .{
3589 .tag = .unspecified_type,
3590 .attrs = &.{
3591 .{ .name, .strp },
3592 },
3593 },
3594 .numeric_type = .{
3595 .tag = .base_type,
3596 .attrs = &.{
3597 .{ .name, .strp },
3598 .{ .encoding, .data1 },
3599 .{ .bit_size, .udata },
3600 .{ .byte_size, .udata },
3601 .{ .alignment, .udata },
3602 },
3603 },
3604 .inferred_error_set_type = .{
3605 .tag = .typedef,
3606 .attrs = &.{
3607 .{ .name, .strp },
3608 .{ .type, .ref_addr },
3609 },
3610 },
3611 .ptr_type = .{
3612 .tag = .pointer_type,
3613 .attrs = &.{
3614 .{ .name, .strp },
3615 .{ .ZIG_is_allowzero, .flag },
3616 .{ .alignment, .udata },
3617 .{ .address_class, .data1 },
3618 .{ .type, .ref_addr },
3619 },
3620 },
3621 .is_const = .{
3622 .tag = .const_type,
3623 .attrs = &.{
3624 .{ .type, .ref_addr },
3625 },
3626 },
3627 .is_volatile = .{
3628 .tag = .volatile_type,
3629 .attrs = &.{
3630 .{ .type, .ref_addr },
3631 },
3632 },
3633 .array_type = .{
3634 .tag = .array_type,
3635 .children = true,
3636 .attrs = &.{
3637 .{ .name, .strp },
3638 .{ .type, .ref_addr },
3639 .{ .GNU_vector, .flag },
3640 },
3641 },
3642 .array_index = .{
3643 .tag = .subrange_type,
3644 .attrs = &.{
3645 .{ .type, .ref_addr },
3646 .{ .count, .udata },
3647 },
3648 },
3649 .nullary_func_type = .{
3650 .tag = .subroutine_type,
3651 .attrs = &.{
3652 .{ .name, .strp },
3653 .{ .calling_convention, .data1 },
3654 .{ .type, .ref_addr },
3655 },
3656 },
3657 .func_type = .{
3658 .tag = .subroutine_type,
3659 .children = true,
3660 .attrs = &.{
3661 .{ .name, .strp },
3662 .{ .calling_convention, .data1 },
3663 .{ .type, .ref_addr },
3664 },
2838 },3665 },
3666 .func_type_param = .{
3667 .tag = .formal_parameter,
3668 .attrs = &.{
3669 .{ .type, .ref_addr },
3670 },
3671 },
3672 .is_var_args = .{
3673 .tag = .unspecified_parameters,
3674 },
3675 .enum_type = .{
3676 .tag = .enumeration_type,
3677 .children = true,
3678 .attrs = &.{
3679 .{ .name, .strp },
3680 .{ .type, .ref_addr },
3681 },
3682 },
3683 .empty_enum_type = .{
3684 .tag = .enumeration_type,
3685 .attrs = &.{
3686 .{ .name, .strp },
3687 .{ .type, .ref_addr },
3688 },
3689 },
3690 .namespace_struct_type = .{
3691 .tag = .structure_type,
3692 .attrs = &.{
3693 .{ .name, .strp },
3694 .{ .declaration, .flag },
3695 },
3696 },
3697 .struct_type = .{
3698 .tag = .structure_type,
3699 .children = true,
3700 .attrs = &.{
3701 .{ .name, .strp },
3702 .{ .byte_size, .udata },
3703 .{ .alignment, .udata },
3704 },
3705 },
3706 .packed_struct_type = .{
3707 .tag = .structure_type,
3708 .children = true,
3709 .attrs = &.{
3710 .{ .name, .strp },
3711 .{ .type, .ref_addr },
3712 },
3713 },
3714 .union_type = .{
3715 .tag = .union_type,
3716 .children = true,
3717 .attrs = &.{
3718 .{ .name, .strp },
3719 .{ .byte_size, .udata },
3720 .{ .alignment, .udata },
3721 },
3722 },
3723 .local_arg = .{
3724 .tag = .formal_parameter,
3725 .attrs = &.{
3726 .{ .name, .strp },
3727 .{ .type, .ref_addr },
3728 .{ .location, .exprloc },
3729 },
3730 },
3731 .local_var = .{
3732 .tag = .variable,
3733 .attrs = &.{
3734 .{ .name, .strp },
3735 .{ .type, .ref_addr },
3736 .{ .location, .exprloc },
3737 },
3738 },
3739 .null = undefined,
3740 }).values[1..].*;
3741};
3742
3743fn getFile(dwarf: *Dwarf) ?std.fs.File {
3744 if (dwarf.bin_file.cast(.macho)) |macho_file| if (macho_file.d_sym) |*d_sym| return d_sym.file;
3745 return dwarf.bin_file.file;
3746}
3747
3748fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {
3749 const entry = try dwarf.debug_aranges.section.addEntry(unit, dwarf);
3750 assert(try dwarf.debug_info.section.addEntry(unit, dwarf) == entry);
3751 assert(try dwarf.debug_line.section.addEntry(unit, dwarf) == entry);
3752 assert(try dwarf.debug_loclists.section.addEntry(unit, dwarf) == entry);
3753 assert(try dwarf.debug_rnglists.section.addEntry(unit, dwarf) == entry);
3754 return entry;
3755}
3756
3757fn writeInt(dwarf: *Dwarf, buf: []u8, int: u64) void {
3758 switch (buf.len) {
3759 inline 0...8 => |len| std.mem.writeInt(@Type(.{ .Int = .{
3760 .signedness = .unsigned,
3761 .bits = len * 8,
3762 } }), buf[0..len], @intCast(int), dwarf.endian),
3763 else => unreachable,
2839 }3764 }
2840}3765}
28413766
2842fn getAtom(self: *const Dwarf, comptime kind: Kind, index: Atom.Index) Atom {3767fn resolveReloc(dwarf: *Dwarf, source: u64, target: u64, size: u32) RelocError!void {
2843 return switch (kind) {3768 var buf: [8]u8 = undefined;
2844 .src_fn => self.src_fns.items[index],3769 dwarf.writeInt(buf[0..size], target);
2845 .di_atom => self.di_atoms.items[index],3770 try dwarf.getFile().?.pwriteAll(buf[0..size], source);
2846 };
2847}3771}
28483772
2849fn getAtomPtr(self: *Dwarf, comptime kind: Kind, index: Atom.Index) *Atom {3773fn unitLengthBytes(dwarf: *Dwarf) u32 {
2850 return switch (kind) {3774 return switch (dwarf.format) {
2851 .src_fn => &self.src_fns.items[index],3775 .@"32" => 4,
2852 .di_atom => &self.di_atoms.items[index],3776 .@"64" => 4 + 8,
2853 };3777 };
2854}3778}
28553779
2856pub const Format = enum {3780fn sectionOffsetBytes(dwarf: *Dwarf) u32 {
2857 dwarf32,3781 return switch (dwarf.format) {
2858 dwarf64,3782 .@"32" => 4,
2859};3783 .@"64" => 8,
3784 };
3785}
28603786
2861const Dwarf = @This();3787fn SectionOffset(comptime format: DW.Format) type {
3788 return switch (format) {
3789 .@"32" => u32,
3790 .@"64" => u64,
3791 };
3792}
28623793
2863const std = @import("std");3794fn uleb128Bytes(value: anytype) u32 {
2864const builtin = @import("builtin");3795 var cw = std.io.countingWriter(std.io.null_writer);
2865const assert = std.debug.assert;3796 try uleb128(cw.writer(), value);
2866const fs = std.fs;3797 return @intCast(cw.bytes_written);
2867const leb128 = std.leb;3798}
2868const log = std.log.scoped(.dwarf);
2869const mem = std.mem;
28703799
2871const link = @import("../link.zig");3800/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
2872const trace = @import("../tracy.zig").trace;3801const force_incremental = false;
3802inline fn incremental(dwarf: Dwarf) bool {
3803 return force_incremental or dwarf.bin_file.comp.incremental;
3804}
28733805
2874const Allocator = mem.Allocator;
2875const DW = std.dwarf;3806const DW = std.dwarf;
2876const File = link.File;3807const Dwarf = @This();
2877const LinkBlock = File.LinkBlock;
2878const LinkFn = File.LinkFn;
2879const LinkerLoad = @import("../codegen.zig").LinkerLoad;
2880const Zcu = @import("../Zcu.zig");
2881const InternPool = @import("../InternPool.zig");3808const InternPool = @import("../InternPool.zig");
2882const StringTable = @import("StringTable.zig");3809const Module = @import("../Package.zig").Module;
2883const Type = @import("../Type.zig");3810const Type = @import("../Type.zig");
2884const Value = @import("../Value.zig");3811const Zcu = @import("../Zcu.zig");
3812const Zir = std.zig.Zir;
3813const assert = std.debug.assert;
3814const codegen = @import("../codegen.zig");
3815const link = @import("../link.zig");
3816const log = std.log.scoped(.dwarf);
3817const sleb128 = std.leb.writeIleb128;
3818const std = @import("std");
3819const target_info = @import("../target.zig");
3820const uleb128 = std.leb.writeUleb128;
src/link/Elf.zig+138-94
...@@ -143,6 +143,9 @@ debug_abbrev_section_index: ?u32 = null,...@@ -143,6 +143,9 @@ debug_abbrev_section_index: ?u32 = null,
143debug_str_section_index: ?u32 = null,143debug_str_section_index: ?u32 = null,
144debug_aranges_section_index: ?u32 = null,144debug_aranges_section_index: ?u32 = null,
145debug_line_section_index: ?u32 = null,145debug_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
147copy_rel_section_index: ?u32 = null,150copy_rel_section_index: ?u32 = null,
148dynamic_section_index: ?u32 = null,151dynamic_section_index: ?u32 = null,
...@@ -492,12 +495,13 @@ pub fn getUavVAddr(self: *Elf, uav: InternPool.Index, reloc_info: link.File.Relo...@@ -492,12 +495,13 @@ pub fn getUavVAddr(self: *Elf, uav: InternPool.Index, reloc_info: link.File.Relo
492}495}
493496
494/// Returns end pos of collision, if any.497/// 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 {
496 const small_ptr = self.ptr_width == .p32;499 const small_ptr = self.ptr_width == .p32;
497 const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr);500 const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr);
498 if (start < ehdr_size)501 if (start < ehdr_size)
499 return ehdr_size;502 return ehdr_size;
500503
504 var at_end = true;
501 const end = start + padToIdeal(size);505 const end = start + padToIdeal(size);
502506
503 if (self.shdr_table_offset) |off| {507 if (self.shdr_table_offset) |off| {
...@@ -505,8 +509,9 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {...@@ -505,8 +509,9 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
505 const tight_size = self.shdrs.items.len * shdr_size;509 const tight_size = self.shdrs.items.len * shdr_size;
506 const increased_size = padToIdeal(tight_size);510 const increased_size = padToIdeal(tight_size);
507 const test_end = off +| increased_size;511 const test_end = off +| increased_size;
508 if (end > off and start < test_end) {512 if (start < test_end) {
509 return test_end;513 if (end > off) return test_end;
514 if (test_end < std.math.maxInt(u64)) at_end = false;
510 }515 }
511 }516 }
512517
...@@ -514,8 +519,9 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {...@@ -514,8 +519,9 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
514 if (shdr.sh_type == elf.SHT_NOBITS) continue;519 if (shdr.sh_type == elf.SHT_NOBITS) continue;
515 const increased_size = padToIdeal(shdr.sh_size);520 const increased_size = padToIdeal(shdr.sh_size);
516 const test_end = shdr.sh_offset +| increased_size;521 const test_end = shdr.sh_offset +| increased_size;
517 if (end > shdr.sh_offset and start < test_end) {522 if (start < test_end) {
518 return test_end;523 if (end > shdr.sh_offset) return test_end;
524 if (test_end < std.math.maxInt(u64)) at_end = false;
519 }525 }
520 }526 }
521527
...@@ -523,11 +529,13 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {...@@ -523,11 +529,13 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
523 if (phdr.p_type != elf.PT_LOAD) continue;529 if (phdr.p_type != elf.PT_LOAD) continue;
524 const increased_size = padToIdeal(phdr.p_filesz);530 const increased_size = padToIdeal(phdr.p_filesz);
525 const test_end = phdr.p_offset +| increased_size;531 const test_end = phdr.p_offset +| increased_size;
526 if (end > phdr.p_offset and start < test_end) {532 if (start < test_end) {
527 return test_end;533 if (end > phdr.p_offset) return test_end;
534 if (test_end < std.math.maxInt(u64)) at_end = false;
528 }535 }
529 }536 }
530537
538 if (at_end) try self.base.file.?.setEndPos(end);
531 return null;539 return null;
532}540}
533541
...@@ -558,9 +566,9 @@ fn allocatedVirtualSize(self: *Elf, start: u64) u64 {...@@ -558,9 +566,9 @@ fn allocatedVirtualSize(self: *Elf, start: u64) u64 {
558 return min_pos - start;566 return min_pos - start;
559}567}
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 {
562 var start: u64 = 0;570 var start: u64 = 0;
563 while (self.detectAllocCollision(start, object_size)) |item_end| {571 while (try self.detectAllocCollision(start, object_size)) |item_end| {
564 start = mem.alignForward(u64, item_end, min_alignment);572 start = mem.alignForward(u64, item_end, min_alignment);
565 }573 }
566 return start;574 return start;
...@@ -580,9 +588,9 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -580,9 +588,9 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
580 const zig_object = self.zigObjectPtr().?;588 const zig_object = self.zigObjectPtr().?;
581589
582 const fillSection = struct {590 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 {
584 if (elf_file.base.isRelocatable()) {592 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);
586 shdr.sh_offset = off;594 shdr.sh_offset = off;
587 shdr.sh_size = size;595 shdr.sh_size = size;
588 } else {596 } else {
...@@ -599,7 +607,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -599,7 +607,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
599 if (!self.base.isRelocatable()) {607 if (!self.base.isRelocatable()) {
600 if (self.phdr_zig_load_re_index == null) {608 if (self.phdr_zig_load_re_index == null) {
601 const filesz = options.program_code_size_hint;609 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);
603 self.phdr_zig_load_re_index = try self.addPhdr(.{611 self.phdr_zig_load_re_index = try self.addPhdr(.{
604 .type = elf.PT_LOAD,612 .type = elf.PT_LOAD,
605 .offset = off,613 .offset = off,
...@@ -614,7 +622,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -614,7 +622,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
614 if (self.phdr_zig_load_ro_index == null) {622 if (self.phdr_zig_load_ro_index == null) {
615 const alignment = self.page_size;623 const alignment = self.page_size;
616 const filesz: u64 = 1024;624 const filesz: u64 = 1024;
617 const off = self.findFreeSpace(filesz, alignment);625 const off = try self.findFreeSpace(filesz, alignment);
618 self.phdr_zig_load_ro_index = try self.addPhdr(.{626 self.phdr_zig_load_ro_index = try self.addPhdr(.{
619 .type = elf.PT_LOAD,627 .type = elf.PT_LOAD,
620 .offset = off,628 .offset = off,
...@@ -629,7 +637,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -629,7 +637,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
629 if (self.phdr_zig_load_rw_index == null) {637 if (self.phdr_zig_load_rw_index == null) {
630 const alignment = self.page_size;638 const alignment = self.page_size;
631 const filesz: u64 = 1024;639 const filesz: u64 = 1024;
632 const off = self.findFreeSpace(filesz, alignment);640 const off = try self.findFreeSpace(filesz, alignment);
633 self.phdr_zig_load_rw_index = try self.addPhdr(.{641 self.phdr_zig_load_rw_index = try self.addPhdr(.{
634 .type = elf.PT_LOAD,642 .type = elf.PT_LOAD,
635 .offset = off,643 .offset = off,
...@@ -662,7 +670,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -662,7 +670,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
662 .offset = std.math.maxInt(u64),670 .offset = std.math.maxInt(u64),
663 });671 });
664 const shdr = &self.shdrs.items[self.zig_text_section_index.?];672 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);
666 if (self.base.isRelocatable()) {674 if (self.base.isRelocatable()) {
667 const rela_shndx = try self.addRelaShdr(try self.insertShString(".rela.text.zig"), self.zig_text_section_index.?);675 const rela_shndx = try self.addRelaShdr(try self.insertShString(".rela.text.zig"), self.zig_text_section_index.?);
668 try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{676 try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{
...@@ -688,7 +696,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -688,7 +696,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
688 .offset = std.math.maxInt(u64),696 .offset = std.math.maxInt(u64),
689 });697 });
690 const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];698 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);
692 if (self.base.isRelocatable()) {700 if (self.base.isRelocatable()) {
693 const rela_shndx = try self.addRelaShdr(701 const rela_shndx = try self.addRelaShdr(
694 try self.insertShString(".rela.data.rel.ro.zig"),702 try self.insertShString(".rela.data.rel.ro.zig"),
...@@ -717,7 +725,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -717,7 +725,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
717 .offset = std.math.maxInt(u64),725 .offset = std.math.maxInt(u64),
718 });726 });
719 const shdr = &self.shdrs.items[self.zig_data_section_index.?];727 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);
721 if (self.base.isRelocatable()) {729 if (self.base.isRelocatable()) {
722 const rela_shndx = try self.addRelaShdr(730 const rela_shndx = try self.addRelaShdr(
723 try self.insertShString(".rela.data.zig"),731 try self.insertShString(".rela.data.zig"),
...@@ -758,24 +766,16 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -758,24 +766,16 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
758 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});766 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
759 }767 }
760768
761 if (zig_object.dwarf) |*dw| {769 if (zig_object.dwarf) |*dwarf| {
762 if (self.debug_str_section_index == null) {770 if (self.debug_str_section_index == null) {
763 assert(dw.strtab.buffer.items.len == 0);
764 try dw.strtab.buffer.append(gpa, 0);
765 self.debug_str_section_index = try self.addSection(.{771 self.debug_str_section_index = try self.addSection(.{
766 .name = try self.insertShString(".debug_str"),772 .name = try self.insertShString(".debug_str"),
767 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,773 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
768 .entsize = 1,774 .entsize = 1,
769 .type = elf.SHT_PROGBITS,775 .type = elf.SHT_PROGBITS,
770 .addralign = 1,776 .addralign = 1,
771 .offset = std.math.maxInt(u64),
772 });777 });
773 const shdr = &self.shdrs.items[self.debug_str_section_index.?];778 zig_object.debug_str_section_dirty = true;
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;
779 try self.output_sections.putNoClobber(gpa, self.debug_str_section_index.?, .{});779 try self.output_sections.putNoClobber(gpa, self.debug_str_section_index.?, .{});
780 }780 }
781781
...@@ -784,14 +784,8 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -784,14 +784,8 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
784 .name = try self.insertShString(".debug_info"),784 .name = try self.insertShString(".debug_info"),
785 .type = elf.SHT_PROGBITS,785 .type = elf.SHT_PROGBITS,
786 .addralign = 1,786 .addralign = 1,
787 .offset = std.math.maxInt(u64),
788 });787 });
789 const shdr = &self.shdrs.items[self.debug_info_section_index.?];788 zig_object.debug_info_section_dirty = true;
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;
795 try self.output_sections.putNoClobber(gpa, self.debug_info_section_index.?, .{});789 try self.output_sections.putNoClobber(gpa, self.debug_info_section_index.?, .{});
796 }790 }
797791
...@@ -800,13 +794,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -800,13 +794,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
800 .name = try self.insertShString(".debug_abbrev"),794 .name = try self.insertShString(".debug_abbrev"),
801 .type = elf.SHT_PROGBITS,795 .type = elf.SHT_PROGBITS,
802 .addralign = 1,796 .addralign = 1,
803 .offset = std.math.maxInt(u64),
804 });797 });
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;
810 zig_object.debug_abbrev_section_dirty = true;798 zig_object.debug_abbrev_section_dirty = true;
811 try self.output_sections.putNoClobber(gpa, self.debug_abbrev_section_index.?, .{});799 try self.output_sections.putNoClobber(gpa, self.debug_abbrev_section_index.?, .{});
812 }800 }
...@@ -816,13 +804,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -816,13 +804,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
816 .name = try self.insertShString(".debug_aranges"),804 .name = try self.insertShString(".debug_aranges"),
817 .type = elf.SHT_PROGBITS,805 .type = elf.SHT_PROGBITS,
818 .addralign = 16,806 .addralign = 16,
819 .offset = std.math.maxInt(u64),
820 });807 });
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;
826 zig_object.debug_aranges_section_dirty = true;808 zig_object.debug_aranges_section_dirty = true;
827 try self.output_sections.putNoClobber(gpa, self.debug_aranges_section_index.?, .{});809 try self.output_sections.putNoClobber(gpa, self.debug_aranges_section_index.?, .{});
828 }810 }
...@@ -832,62 +814,83 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -832,62 +814,83 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
832 .name = try self.insertShString(".debug_line"),814 .name = try self.insertShString(".debug_line"),
833 .type = elf.SHT_PROGBITS,815 .type = elf.SHT_PROGBITS,
834 .addralign = 1,816 .addralign = 1,
835 .offset = std.math.maxInt(u64),
836 });817 });
837 const shdr = &self.shdrs.items[self.debug_line_section_index.?];818 zig_object.debug_line_section_dirty = true;
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;
843 try self.output_sections.putNoClobber(gpa, self.debug_line_section_index.?, .{});819 try self.output_sections.putNoClobber(gpa, self.debug_line_section_index.?, .{});
844 }820 }
845 }
846821
847 // We need to find current max assumed file offset, and actually write to file to make it a reality.822 if (self.debug_line_str_section_index == null) {
848 var end_pos: u64 = 0;823 self.debug_line_str_section_index = try self.addSection(.{
849 for (self.shdrs.items) |shdr| {824 .name = try self.insertShString(".debug_line_str"),
850 if (shdr.sh_offset == std.math.maxInt(u64)) continue;825 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
851 end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size);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();
852 }855 }
853 try self.base.file.?.pwriteAll(&[1]u8{0}, end_pos);
854}856}
855857
856pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {858pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
857 const shdr = &self.shdrs.items[shdr_index];859 const shdr = &self.shdrs.items[shdr_index];
858 const maybe_phdr = if (self.phdr_to_shdr_table.get(shdr_index)) |phndx| &self.phdrs.items[phndx] else null;860 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;
860 log.debug("allocated size {x} of {s}, needed size {x}", .{861 log.debug("allocated size {x} of {s}, needed size {x}", .{
861 self.allocatedSize(shdr.sh_offset),862 self.allocatedSize(shdr.sh_offset),
862 self.getShString(shdr.sh_name),863 self.getShString(shdr.sh_name),
863 needed_size,864 needed_size,
864 });865 });
865866
866 if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) {867 if (shdr.sh_type != elf.SHT_NOBITS) {
867 const existing_size = shdr.sh_size;868 const allocated_size = self.allocatedSize(shdr.sh_offset);
868 shdr.sh_size = 0;869 if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
869 // Must move the entire section.870 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
870 const alignment = if (maybe_phdr) |phdr| phdr.p_align else shdr.sh_addralign;871 } else if (needed_size > allocated_size) {
871 const new_offset = self.findFreeSpace(needed_size, alignment);872 const existing_size = shdr.sh_size;
872873 shdr.sh_size = 0;
873 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{874 // Must move the entire section.
874 self.getShString(shdr.sh_name),875 const alignment = if (maybe_phdr) |phdr| phdr.p_align else shdr.sh_addralign;
875 new_offset,876 const new_offset = try self.findFreeSpace(needed_size, alignment);
876 new_offset + existing_size,
877 });
878877
879 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, existing_size);878 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
880 // TODO figure out what to about this error condition - how to communicate it up.879 self.getShString(shdr.sh_name),
881 if (amt != existing_size) return error.InputOutput;880 new_offset,
881 new_offset + existing_size,
882 });
882883
883 shdr.sh_offset = new_offset;884 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, existing_size);
884 if (maybe_phdr) |phdr| phdr.p_offset = new_offset;885 // TODO figure out what to about this error condition - how to communicate it up.
885 }886 if (amt != existing_size) return error.InputOutput;
886887
887 shdr.sh_size = needed_size;888 shdr.sh_offset = new_offset;
888 if (!is_zerofill) {889 if (maybe_phdr) |phdr| phdr.p_offset = new_offset;
890 }
889 if (maybe_phdr) |phdr| phdr.p_filesz = needed_size;891 if (maybe_phdr) |phdr| phdr.p_filesz = needed_size;
890 }892 }
893 shdr.sh_size = needed_size;
891894
892 if (maybe_phdr) |phdr| {895 if (maybe_phdr) |phdr| {
893 const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr);896 const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr);
...@@ -915,11 +918,14 @@ pub fn growNonAllocSection(...@@ -915,11 +918,14 @@ pub fn growNonAllocSection(
915) !void {918) !void {
916 const shdr = &self.shdrs.items[shdr_index];919 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) {
919 const existing_size = shdr.sh_size;925 const existing_size = shdr.sh_size;
920 shdr.sh_size = 0;926 shdr.sh_size = 0;
921 // Move all the symbols to a new file location.927 // 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
924 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{930 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
925 self.getShString(shdr.sh_name),931 self.getShString(shdr.sh_name),
...@@ -939,7 +945,6 @@ pub fn growNonAllocSection(...@@ -939,7 +945,6 @@ pub fn growNonAllocSection(
939945
940 shdr.sh_offset = new_offset;946 shdr.sh_offset = new_offset;
941 }947 }
942
943 shdr.sh_size = needed_size;948 shdr.sh_size = needed_size;
944949
945 self.markDirty(shdr_index);950 self.markDirty(shdr_index);
...@@ -949,15 +954,21 @@ pub fn markDirty(self: *Elf, shdr_index: u32) void {...@@ -949,15 +954,21 @@ pub fn markDirty(self: *Elf, shdr_index: u32) void {
949 const zig_object = self.zigObjectPtr().?;954 const zig_object = self.zigObjectPtr().?;
950 if (zig_object.dwarf) |_| {955 if (zig_object.dwarf) |_| {
951 if (self.debug_info_section_index.? == shdr_index) {956 if (self.debug_info_section_index.? == shdr_index) {
952 zig_object.debug_info_header_dirty = true;957 zig_object.debug_info_section_dirty = true;
953 } else if (self.debug_line_section_index.? == shdr_index) {
954 zig_object.debug_line_header_dirty = true;
955 } else if (self.debug_abbrev_section_index.? == shdr_index) {958 } else if (self.debug_abbrev_section_index.? == shdr_index) {
956 zig_object.debug_abbrev_section_dirty = true;959 zig_object.debug_abbrev_section_dirty = true;
957 } else if (self.debug_str_section_index.? == shdr_index) {960 } else if (self.debug_str_section_index.? == shdr_index) {
958 zig_object.debug_strtab_dirty = true;961 zig_object.debug_str_section_dirty = true;
959 } else if (self.debug_aranges_section_index.? == shdr_index) {962 } else if (self.debug_aranges_section_index.? == shdr_index) {
960 zig_object.debug_aranges_section_dirty = true;963 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;
961 }972 }
962 }973 }
963}974}
...@@ -1306,6 +1317,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -1306,6 +1317,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1306 try self.base.file.?.pwriteAll(code, file_offset);1317 try self.base.file.?.pwriteAll(code, file_offset);
1307 }1318 }
13081319
1320 if (zo.dwarf) |*dwarf| try dwarf.resolveRelocs();
1321
1309 if (has_reloc_errors) return error.FlushFailure;1322 if (has_reloc_errors) return error.FlushFailure;
1310 }1323 }
13111324
...@@ -2667,7 +2680,7 @@ pub fn writeShdrTable(self: *Elf) !void {...@@ -2667,7 +2680,7 @@ pub fn writeShdrTable(self: *Elf) !void {
26672680
2668 if (needed_size > self.allocatedSize(shoff)) {2681 if (needed_size > self.allocatedSize(shoff)) {
2669 self.shdr_table_offset = null;2682 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);
2671 }2684 }
26722685
2673 log.debug("writing section headers from 0x{x} to 0x{x}", .{2686 log.debug("writing section headers from 0x{x} to 0x{x}", .{
...@@ -2900,6 +2913,18 @@ pub fn updateNav(...@@ -2900,6 +2913,18 @@ pub fn updateNav(
2900 return self.zigObjectPtr().?.updateNav(self, pt, nav);2913 return self.zigObjectPtr().?.updateNav(self, pt, nav);
2901}2914}
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
2903pub fn updateExports(2928pub fn updateExports(
2904 self: *Elf,2929 self: *Elf,
2905 pt: Zcu.PerThread,2930 pt: Zcu.PerThread,
...@@ -3658,11 +3683,14 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {...@@ -3658,11 +3683,14 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {
3658 &self.zig_data_rel_ro_section_index,3683 &self.zig_data_rel_ro_section_index,
3659 &self.zig_data_section_index,3684 &self.zig_data_section_index,
3660 &self.zig_bss_section_index,3685 &self.zig_bss_section_index,
3661 &self.debug_str_section_index,
3662 &self.debug_info_section_index,3686 &self.debug_info_section_index,
3663 &self.debug_abbrev_section_index,3687 &self.debug_abbrev_section_index,
3688 &self.debug_str_section_index,
3664 &self.debug_aranges_section_index,3689 &self.debug_aranges_section_index,
3665 &self.debug_line_section_index,3690 &self.debug_line_section_index,
3691 &self.debug_line_str_section_index,
3692 &self.debug_loclists_section_index,
3693 &self.debug_rnglists_section_index,
3666 }) |maybe_index| {3694 }) |maybe_index| {
3667 if (maybe_index.*) |*index| {3695 if (maybe_index.*) |*index| {
3668 index.* = backlinks[index.*];3696 index.* = backlinks[index.*];
...@@ -3787,6 +3815,7 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {...@@ -3787,6 +3815,7 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {
3787 const atom_ptr = zo.atom(atom_index) orelse continue;3815 const atom_ptr = zo.atom(atom_index) orelse continue;
3788 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];3816 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
3789 }3817 }
3818 if (zo.dwarf) |*dwarf| dwarf.reloadSectionMetadata();
3790 }3819 }
37913820
3792 for (self.output_rela_sections.keys(), self.output_rela_sections.values()) |shndx, sec| {3821 for (self.output_rela_sections.keys(), self.output_rela_sections.values()) |shndx, sec| {
...@@ -3992,7 +4021,7 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {...@@ -3992,7 +4021,7 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {
39924021
3993/// Allocates alloc sections and creates load segments for sections4022/// Allocates alloc sections and creates load segments for sections
3994/// extracted from input object files.4023/// extracted from input object files.
3995pub fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {4024pub fn allocateAllocSections(self: *Elf) !void {
3996 // We use this struct to track maximum alignment of all TLS sections.4025 // We use this struct to track maximum alignment of all TLS sections.
3997 // According to https://github.com/rui314/mold/commit/bd46edf3f0fe9e1a787ea453c4657d535622e61f in mold,4026 // According to https://github.com/rui314/mold/commit/bd46edf3f0fe9e1a787ea453c4657d535622e61f in mold,
3998 // in-file offsets have to be aligned against the start of TLS program header.4027 // 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 {...@@ -4112,7 +4141,7 @@ pub fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
4112 }4141 }
41134142
4114 const first = self.shdrs.items[cover.items[0]];4143 const first = self.shdrs.items[cover.items[0]];
4115 var off = self.findFreeSpace(filesz, @"align");4144 var off = try self.findFreeSpace(filesz, @"align");
4116 const phndx = try self.addPhdr(.{4145 const phndx = try self.addPhdr(.{
4117 .type = elf.PT_LOAD,4146 .type = elf.PT_LOAD,
4118 .offset = off,4147 .offset = off,
...@@ -4147,7 +4176,7 @@ pub fn allocateNonAllocSections(self: *Elf) !void {...@@ -4147,7 +4176,7 @@ pub fn allocateNonAllocSections(self: *Elf) !void {
4147 const needed_size = shdr.sh_size;4176 const needed_size = shdr.sh_size;
4148 if (needed_size > self.allocatedSize(shdr.sh_offset)) {4177 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
4149 shdr.sh_size = 0;4178 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
4152 if (self.isDebugSection(@intCast(shndx))) {4181 if (self.isDebugSection(@intCast(shndx))) {
4153 log.debug("moving {s} from 0x{x} to 0x{x}", .{4182 log.debug("moving {s} from 0x{x} to 0x{x}", .{
...@@ -4167,6 +4196,12 @@ pub fn allocateNonAllocSections(self: *Elf) !void {...@@ -4167,6 +4196,12 @@ pub fn allocateNonAllocSections(self: *Elf) !void {
4167 break :blk zig_object.debug_aranges_section_zig_size;4196 break :blk zig_object.debug_aranges_section_zig_size;
4168 if (shndx == self.debug_line_section_index.?)4197 if (shndx == self.debug_line_section_index.?)
4169 break :blk zig_object.debug_line_section_zig_size;4198 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;
4170 unreachable;4205 unreachable;
4171 };4206 };
4172 const amt = try self.base.file.?.copyRangeAll(4207 const amt = try self.base.file.?.copyRangeAll(
...@@ -4275,6 +4310,12 @@ fn writeAtoms(self: *Elf) !void {...@@ -4275,6 +4310,12 @@ fn writeAtoms(self: *Elf) !void {
4275 break :blk zig_object.debug_aranges_section_zig_size;4310 break :blk zig_object.debug_aranges_section_zig_size;
4276 if (shndx == self.debug_line_section_index.?)4311 if (shndx == self.debug_line_section_index.?)
4277 break :blk zig_object.debug_line_section_zig_size;4312 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;
4278 unreachable;4319 unreachable;
4279 } else 0;4320 } else 0;
4280 const sh_offset = shdr.sh_offset + base_offset;4321 const sh_offset = shdr.sh_offset + base_offset;
...@@ -5044,6 +5085,9 @@ pub fn isDebugSection(self: Elf, shndx: u32) bool {...@@ -5044,6 +5085,9 @@ pub fn isDebugSection(self: Elf, shndx: u32) bool {
5044 self.debug_str_section_index,5085 self.debug_str_section_index,
5045 self.debug_aranges_section_index,5086 self.debug_aranges_section_index,
5046 self.debug_line_section_index,5087 self.debug_line_section_index,
5088 self.debug_line_str_section_index,
5089 self.debug_loclists_section_index,
5090 self.debug_rnglists_section_index,
5047 }) |maybe_index| {5091 }) |maybe_index| {
5048 if (maybe_index) |index| {5092 if (maybe_index) |index| {
5049 if (index == shndx) return true;5093 if (index == shndx) return true;
...@@ -5109,7 +5153,7 @@ pub const AddSectionOpts = struct {...@@ -5109,7 +5153,7 @@ pub const AddSectionOpts = struct {
51095153
5110pub fn addSection(self: *Elf, opts: AddSectionOpts) !u32 {5154pub fn addSection(self: *Elf, opts: AddSectionOpts) !u32 {
5111 const gpa = self.base.comp.gpa;5155 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);
5113 const shdr = try self.shdrs.addOne(gpa);5157 const shdr = try self.shdrs.addOne(gpa);
5114 shdr.* = .{5158 shdr.* = .{
5115 .sh_name = opts.name,5159 .sh_name = opts.name,
src/link/Elf/Atom.zig+2-1
...@@ -201,11 +201,12 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -201,11 +201,12 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
201 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address201 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
202 // range of the compilation unit. When we expand the text section, this range changes,202 // range of the compilation unit. When we expand the text section, this range changes,
203 // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.203 // 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;
205 // This becomes dirty for the same reason. We could potentially make this more205 // This becomes dirty for the same reason. We could potentially make this more
206 // fine-grained with the addition of support for more compilation units. It is planned to206 // fine-grained with the addition of support for more compilation units. It is planned to
207 // model each package as a different compilation unit.207 // model each package as a different compilation unit.
208 zig_object.debug_aranges_section_dirty = true;208 zig_object.debug_aranges_section_dirty = true;
209 zig_object.debug_rnglists_section_dirty = true;
209 }210 }
210 }211 }
211 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnits().?);212 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnits().?);
src/link/Elf/ZigObject.zig+104-102
...@@ -41,11 +41,14 @@ tls_variables: TlsTable = .{},...@@ -41,11 +41,14 @@ tls_variables: TlsTable = .{},
41/// Table of tracked `Uav`s.41/// Table of tracked `Uav`s.
42uavs: UavTable = .{},42uavs: UavTable = .{},
4343
44debug_strtab_dirty: bool = false,44debug_info_section_dirty: bool = false,
45debug_abbrev_section_dirty: bool = false,45debug_abbrev_section_dirty: bool = false,
46debug_aranges_section_dirty: bool = false,46debug_aranges_section_dirty: bool = false,
47debug_info_header_dirty: bool = false,47debug_str_section_dirty: bool = false,
48debug_line_header_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
50/// Size contribution of Zig's metadata to each debug section.53/// Size contribution of Zig's metadata to each debug section.
51/// Used to track start of metadata from input object files.54/// Used to track start of metadata from input object files.
...@@ -54,6 +57,9 @@ debug_abbrev_section_zig_size: u64 = 0,...@@ -54,6 +57,9 @@ debug_abbrev_section_zig_size: u64 = 0,
54debug_str_section_zig_size: u64 = 0,57debug_str_section_zig_size: u64 = 0,
55debug_aranges_section_zig_size: u64 = 0,58debug_aranges_section_zig_size: u64 = 0,
56debug_line_section_zig_size: u64 = 0,59debug_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
58pub const global_symbol_bit: u32 = 0x80000000;64pub const global_symbol_bit: u32 = 0x80000000;
59pub const symbol_mask: u32 = 0x7fffffff;65pub const symbol_mask: u32 = 0x7fffffff;
...@@ -76,10 +82,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -76,10 +82,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
7682
77 switch (comp.config.debug_format) {83 switch (comp.config.debug_format) {
78 .strip => {},84 .strip => {},
79 .dwarf => |v| {85 .dwarf => |v| self.dwarf = Dwarf.init(&elf_file.base, v),
80 assert(v == .@"32");
81 self.dwarf = Dwarf.init(&elf_file.base, .dwarf32);
82 },
83 .code_view => unreachable,86 .code_view => unreachable,
84 }87 }
85}88}
...@@ -119,8 +122,8 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {...@@ -119,8 +122,8 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
119 }122 }
120 self.tls_variables.deinit(allocator);123 self.tls_variables.deinit(allocator);
121124
122 if (self.dwarf) |*dw| {125 if (self.dwarf) |*dwarf| {
123 dw.deinit();126 dwarf.deinit();
124 }127 }
125}128}
126129
...@@ -165,44 +168,14 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi...@@ -165,44 +168,14 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
165 }168 }
166 }169 }
167170
168 if (self.dwarf) |*dw| {171 if (self.dwarf) |*dwarf| {
169 const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };172 const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };
170 try dw.flushModule(pt);173 try dwarf.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 }
192174
193 if (self.debug_line_header_dirty) {175 self.debug_abbrev_section_dirty = false;
194 try dw.writeDbgLineHeader();176 self.debug_aranges_section_dirty = false;
195 self.debug_line_header_dirty = false;177 self.debug_rnglists_section_dirty = false;
196 }178 self.debug_str_section_dirty = false;
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 }
206179
207 self.saveDebugSectionsSizes(elf_file);180 self.saveDebugSectionsSizes(elf_file);
208 }181 }
...@@ -213,7 +186,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi...@@ -213,7 +186,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
213 // such as debug_line_header_dirty and debug_info_header_dirty.186 // such as debug_line_header_dirty and debug_info_header_dirty.
214 assert(!self.debug_abbrev_section_dirty);187 assert(!self.debug_abbrev_section_dirty);
215 assert(!self.debug_aranges_section_dirty);188 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);
217}191}
218192
219fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {193fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {
...@@ -232,6 +206,15 @@ fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {...@@ -232,6 +206,15 @@ fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {
232 if (elf_file.debug_line_section_index) |shndx| {206 if (elf_file.debug_line_section_index) |shndx| {
233 self.debug_line_section_zig_size = elf_file.shdrs.items[shndx].sh_size;207 self.debug_line_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
234 }208 }
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 }
235}218}
236219
237fn newSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, st_bind: u4) !Symbol.Index {220fn 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...@@ -783,8 +766,8 @@ pub fn freeNav(self: *ZigObject, elf_file: *Elf, nav_index: InternPool.Nav.Index
783 kv.value.exports.deinit(gpa);766 kv.value.exports.deinit(gpa);
784 }767 }
785768
786 if (self.dwarf) |*dw| {769 if (self.dwarf) |*dwarf| {
787 dw.freeNav(nav_index);770 dwarf.freeNav(nav_index);
788 }771 }
789}772}
790773
...@@ -1034,8 +1017,8 @@ pub fn updateFunc(...@@ -1034,8 +1017,8 @@ pub fn updateFunc(
1034 var code_buffer = std.ArrayList(u8).init(gpa);1017 var code_buffer = std.ArrayList(u8).init(gpa);
1035 defer code_buffer.deinit();1018 defer code_buffer.deinit();
10361019
1037 var dwarf_state = if (self.dwarf) |*dw| try dw.initNavState(pt, func.owner_nav) else null;1020 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null;
1038 defer if (dwarf_state) |*ds| ds.deinit();1021 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
10391022
1040 const res = try codegen.generateFunction(1023 const res = try codegen.generateFunction(
1041 &elf_file.base,1024 &elf_file.base,
...@@ -1045,7 +1028,7 @@ pub fn updateFunc(...@@ -1045,7 +1028,7 @@ pub fn updateFunc(
1045 air,1028 air,
1046 liveness,1029 liveness,
1047 &code_buffer,1030 &code_buffer,
1048 if (dwarf_state) |*ds| .{ .dwarf = ds } else .none,1031 if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none,
1049 );1032 );
10501033
1051 const code = switch (res) {1034 const code = switch (res) {
...@@ -1072,14 +1055,17 @@ pub fn updateFunc(...@@ -1072,14 +1055,17 @@ pub fn updateFunc(
1072 break :blk .{ atom_ptr.value, atom_ptr.alignment };1055 break :blk .{ atom_ptr.value, atom_ptr.alignment };
1073 };1056 };
10741057
1075 if (dwarf_state) |*ds| {1058 if (debug_wip_nav) |*wip_nav| {
1076 const sym = self.symbol(sym_index);1059 const sym = self.symbol(sym_index);
1077 try self.dwarf.?.commitNavState(1060 try self.dwarf.?.finishWipNav(
1078 pt,1061 pt,
1079 func.owner_nav,1062 func.owner_nav,
1080 @intCast(sym.address(.{}, elf_file)),1063 .{
1081 sym.atom(elf_file).?.size,1064 .index = sym_index,
1082 ds,1065 .addr = @intCast(sym.address(.{}, elf_file)),
1066 .size = sym.atom(elf_file).?.size,
1067 },
1068 wip_nav,
1083 );1069 );
1084 }1070 }
10851071
...@@ -1152,59 +1138,75 @@ pub fn updateNav(...@@ -1152,59 +1138,75 @@ pub fn updateNav(
1152 else => nav_val,1138 else => nav_val,
1153 };1139 };
11541140
1155 const sym_index = try self.getOrCreateMetadataForNav(elf_file, nav_index);1141 if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
1156 self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);1142 const sym_index = try self.getOrCreateMetadataForNav(elf_file, nav_index);
11571143 self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
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 );
11741144
1175 const code = switch (res) {1145 var code_buffer = std.ArrayList(u8).init(zcu.gpa);
1176 .ok => code_buffer.items,1146 defer code_buffer.deinit();
1177 .fail => |em| {
1178 try zcu.failed_codegen.put(zcu.gpa, nav_index, em);
1179 return;
1180 },
1181 };
11821147
1183 const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code);1148 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null;
1184 log.debug("setting shdr({x},{s}) for {}", .{1149 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
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);
11931150
1194 if (nav_state) |*ns| {1151 // TODO implement .debug_info for global variables
1195 const sym = self.symbol(sym_index);1152 const res = try codegen.generateSymbol(
1196 try self.dwarf.?.commitNavState(1153 &elf_file.base,
1197 pt,1154 pt,
1198 nav_index,1155 zcu.navSrcLoc(nav_index),
1199 @intCast(sym.address(.{}, elf_file)),1156 nav_init,
1200 sym.atom(elf_file).?.size,1157 &code_buffer,
1201 ns,1158 if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
1159 .{ .parent_atom_index = sym_index },
1202 );1160 );
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
1205 // Exports will be updated by `Zcu.processExports` after the update.1196 // Exports will be updated by `Zcu.processExports` after the update.
1206}1197}
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
1208fn updateLazySymbol(1210fn updateLazySymbol(
1209 self: *ZigObject,1211 self: *ZigObject,
1210 elf_file: *Elf,1212 elf_file: *Elf,
...@@ -1441,8 +1443,8 @@ pub fn updateNavLineNumber(...@@ -1441,8 +1443,8 @@ pub fn updateNavLineNumber(
14411443
1442 log.debug("updateNavLineNumber {}({d})", .{ nav.fqn.fmt(ip), nav_index });1444 log.debug("updateNavLineNumber {}({d})", .{ nav.fqn.fmt(ip), nav_index });
14431445
1444 if (self.dwarf) |*dw| {1446 if (self.dwarf) |*dwarf| {
1445 try dw.updateNavLineNumber(pt.zcu, nav_index);1447 try dwarf.updateNavLineNumber(pt.zcu, nav_index);
1446 }1448 }
1447}1449}
14481450
src/link/Elf/relocatable.zig+7-1
...@@ -401,7 +401,7 @@ fn allocateAllocSections(elf_file: *Elf) !void {...@@ -401,7 +401,7 @@ fn allocateAllocSections(elf_file: *Elf) !void {
401 const needed_size = shdr.sh_size;401 const needed_size = shdr.sh_size;
402 if (needed_size > elf_file.allocatedSize(shdr.sh_offset)) {402 if (needed_size > elf_file.allocatedSize(shdr.sh_offset)) {
403 shdr.sh_size = 0;403 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);
405 shdr.sh_offset = new_offset;405 shdr.sh_offset = new_offset;
406 shdr.sh_size = needed_size;406 shdr.sh_size = needed_size;
407 }407 }
...@@ -434,6 +434,12 @@ fn writeAtoms(elf_file: *Elf) !void {...@@ -434,6 +434,12 @@ fn writeAtoms(elf_file: *Elf) !void {
434 break :blk zig_object.debug_aranges_section_zig_size;434 break :blk zig_object.debug_aranges_section_zig_size;
435 if (shndx == elf_file.debug_line_section_index.?)435 if (shndx == elf_file.debug_line_section_index.?)
436 break :blk zig_object.debug_line_section_zig_size;436 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;
437 unreachable;443 unreachable;
438 } else 0;444 } else 0;
439 const sh_offset = shdr.sh_offset + base_offset;445 const sh_offset = shdr.sh_offset + base_offset;
src/link/MachO.zig+128-121
...@@ -94,6 +94,9 @@ debug_abbrev_sect_index: ?u8 = null,...@@ -94,6 +94,9 @@ debug_abbrev_sect_index: ?u8 = null,
94debug_str_sect_index: ?u8 = null,94debug_str_sect_index: ?u8 = null,
95debug_aranges_sect_index: ?u8 = null,95debug_aranges_sect_index: ?u8 = null,
96debug_line_sect_index: ?u8 = null,96debug_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
98has_tlv: AtomicBool = AtomicBool.init(false),101has_tlv: AtomicBool = AtomicBool.init(false),
99binds_to_weak: AtomicBool = AtomicBool.init(false),102binds_to_weak: AtomicBool = AtomicBool.init(false),
...@@ -1789,12 +1792,42 @@ pub fn sortSections(self: *MachO) !void {...@@ -1789,12 +1792,42 @@ pub fn sortSections(self: *MachO) !void {
1789 self.sections.appendAssumeCapacity(slice.get(sorted.index));1792 self.sections.appendAssumeCapacity(slice.get(sorted.index));
1790 }1793 }
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
1792 if (self.getZigObject()) |zo| {1824 if (self.getZigObject()) |zo| {
1793 for (zo.getAtoms()) |atom_index| {1825 for (zo.getAtoms()) |atom_index| {
1794 const atom = zo.getAtom(atom_index) orelse continue;1826 const atom = zo.getAtom(atom_index) orelse continue;
1795 if (!atom.isAlive()) continue;1827 if (!atom.isAlive()) continue;
1796 atom.out_n_sect = backlinks[atom.out_n_sect];1828 atom.out_n_sect = backlinks[atom.out_n_sect];
1797 }1829 }
1830 if (zo.dwarf) |*dwarf| dwarf.reloadSectionMetadata();
1798 }1831 }
17991832
1800 for (self.objects.items) |index| {1833 for (self.objects.items) |index| {
...@@ -1813,32 +1846,6 @@ pub fn sortSections(self: *MachO) !void {...@@ -1813,32 +1846,6 @@ pub fn sortSections(self: *MachO) !void {
1813 atom.out_n_sect = backlinks[atom.out_n_sect];1846 atom.out_n_sect = backlinks[atom.out_n_sect];
1814 }1847 }
1815 }1848 }
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 }
1842}1849}
18431850
1844pub fn addAtomsToSections(self: *MachO) !void {1851pub fn addAtomsToSections(self: *MachO) !void {
...@@ -2189,7 +2196,7 @@ fn allocateSections(self: *MachO) !void {...@@ -2189,7 +2196,7 @@ fn allocateSections(self: *MachO) !void {
2189 header.size = 0;2196 header.size = 0;
21902197
2191 // Must move the entire section.2198 // 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
2194 log.debug("moving '{s},{s}' from 0x{x} to 0x{x}", .{2201 log.debug("moving '{s},{s}' from 0x{x} to 0x{x}", .{
2195 header.segName(),2202 header.segName(),
...@@ -3066,32 +3073,36 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {...@@ -3066,32 +3073,36 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
3066 return actual_size +| (actual_size / ideal_factor);3073 return actual_size +| (actual_size / ideal_factor);
3067}3074}
30683075
3069fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {3076fn detectAllocCollision(self: *MachO, start: u64, size: u64) !?u64 {
3070 // Conservatively commit one page size as reserved space for the headers as we3077 // Conservatively commit one page size as reserved space for the headers as we
3071 // expect it to grow and everything else be moved in flush anyhow.3078 // expect it to grow and everything else be moved in flush anyhow.
3072 const header_size = self.getPageSize();3079 const header_size = self.getPageSize();
3073 if (start < header_size)3080 if (start < header_size)
3074 return header_size;3081 return header_size;
30753082
3083 var at_end = true;
3076 const end = start + padToIdeal(size);3084 const end = start + padToIdeal(size);
30773085
3078 for (self.sections.items(.header)) |header| {3086 for (self.sections.items(.header)) |header| {
3079 if (header.isZerofill()) continue;3087 if (header.isZerofill()) continue;
3080 const increased_size = padToIdeal(header.size);3088 const increased_size = padToIdeal(header.size);
3081 const test_end = header.offset +| increased_size;3089 const test_end = header.offset +| increased_size;
3082 if (end > header.offset and start < test_end) {3090 if (start < test_end) {
3083 return test_end;3091 if (end > header.offset) return test_end;
3092 if (test_end < std.math.maxInt(u64)) at_end = false;
3084 }3093 }
3085 }3094 }
30863095
3087 for (self.segments.items) |seg| {3096 for (self.segments.items) |seg| {
3088 const increased_size = padToIdeal(seg.filesize);3097 const increased_size = padToIdeal(seg.filesize);
3089 const test_end = seg.fileoff +| increased_size;3098 const test_end = seg.fileoff +| increased_size;
3090 if (end > seg.fileoff and start < test_end) {3099 if (start < test_end) {
3091 return test_end;3100 if (end > seg.fileoff) return test_end;
3101 if (test_end < std.math.maxInt(u64)) at_end = false;
3092 }3102 }
3093 }3103 }
30943104
3105 if (at_end) try self.base.file.?.setEndPos(end);
3095 return null;3106 return null;
3096}3107}
30973108
...@@ -3159,9 +3170,9 @@ pub fn allocatedSizeVirtual(self: *MachO, start: u64) u64 {...@@ -3159,9 +3170,9 @@ pub fn allocatedSizeVirtual(self: *MachO, start: u64) u64 {
3159 return min_pos - start;3170 return min_pos - start;
3160}3171}
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 {
3163 var start: u64 = 0;3174 var start: u64 = 0;
3164 while (self.detectAllocCollision(start, object_size)) |item_end| {3175 while (try self.detectAllocCollision(start, object_size)) |item_end| {
3165 start = mem.alignForward(u64, item_end, min_alignment);3176 start = mem.alignForward(u64, item_end, min_alignment);
3166 }3177 }
3167 return start;3178 return start;
...@@ -3210,7 +3221,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3210,7 +3221,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
32103221
3211 {3222 {
3212 const filesize = options.program_code_size_hint;3223 const filesize = options.program_code_size_hint;
3213 const off = self.findFreeSpace(filesize, self.getPageSize());3224 const off = try self.findFreeSpace(filesize, self.getPageSize());
3214 self.zig_text_seg_index = try self.addSegment("__TEXT_ZIG", .{3225 self.zig_text_seg_index = try self.addSegment("__TEXT_ZIG", .{
3215 .fileoff = off,3226 .fileoff = off,
3216 .filesize = filesize,3227 .filesize = filesize,
...@@ -3222,7 +3233,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3222,7 +3233,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
32223233
3223 {3234 {
3224 const filesize = options.symbol_count_hint * @sizeOf(u64);3235 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());
3226 self.zig_got_seg_index = try self.addSegment("__GOT_ZIG", .{3237 self.zig_got_seg_index = try self.addSegment("__GOT_ZIG", .{
3227 .fileoff = off,3238 .fileoff = off,
3228 .filesize = filesize,3239 .filesize = filesize,
...@@ -3234,7 +3245,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3234,7 +3245,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
32343245
3235 {3246 {
3236 const filesize: u64 = 1024;3247 const filesize: u64 = 1024;
3237 const off = self.findFreeSpace(filesize, self.getPageSize());3248 const off = try self.findFreeSpace(filesize, self.getPageSize());
3238 self.zig_const_seg_index = try self.addSegment("__CONST_ZIG", .{3249 self.zig_const_seg_index = try self.addSegment("__CONST_ZIG", .{
3239 .fileoff = off,3250 .fileoff = off,
3240 .filesize = filesize,3251 .filesize = filesize,
...@@ -3246,7 +3257,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3246,7 +3257,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
32463257
3247 {3258 {
3248 const filesize: u64 = 1024;3259 const filesize: u64 = 1024;
3249 const off = self.findFreeSpace(filesize, self.getPageSize());3260 const off = try self.findFreeSpace(filesize, self.getPageSize());
3250 self.zig_data_seg_index = try self.addSegment("__DATA_ZIG", .{3261 self.zig_data_seg_index = try self.addSegment("__DATA_ZIG", .{
3251 .fileoff = off,3262 .fileoff = off,
3252 .filesize = filesize,3263 .filesize = filesize,
...@@ -3265,7 +3276,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3265,7 +3276,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3265 });3276 });
3266 }3277 }
32673278
3268 if (options.zo.dwarf) |_| {3279 if (options.zo.dwarf) |*dwarf| {
3269 // Create dSYM bundle.3280 // Create dSYM bundle.
3270 log.debug("creating {s}.dSYM bundle", .{options.emit.sub_path});3281 log.debug("creating {s}.dSYM bundle", .{options.emit.sub_path});
32713282
...@@ -3288,6 +3299,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3288,6 +3299,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
32883299
3289 self.d_sym = .{ .allocator = gpa, .file = d_sym_file };3300 self.d_sym = .{ .allocator = gpa, .file = d_sym_file };
3290 try self.d_sym.?.initMetadata(self);3301 try self.d_sym.?.initMetadata(self);
3302 try dwarf.initMetadata();
3291 }3303 }
3292 }3304 }
32933305
...@@ -3307,7 +3319,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3307,7 +3319,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3307 const sect = &macho_file.sections.items(.header)[sect_id];3319 const sect = &macho_file.sections.items(.header)[sect_id];
3308 const alignment = try math.powi(u32, 2, sect.@"align");3320 const alignment = try math.powi(u32, 2, sect.@"align");
3309 if (!sect.isZerofill()) {3321 if (!sect.isZerofill()) {
3310 sect.offset = math.cast(u32, macho_file.findFreeSpace(size, alignment)) orelse3322 sect.offset = math.cast(u32, try macho_file.findFreeSpace(size, alignment)) orelse
3311 return error.Overflow;3323 return error.Overflow;
3312 }3324 }
3313 sect.addr = macho_file.findFreeSpaceVirtual(size, alignment);3325 sect.addr = macho_file.findFreeSpaceVirtual(size, alignment);
...@@ -3367,43 +3379,34 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3367,43 +3379,34 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3367 }3379 }
3368 }3380 }
33693381
3370 if (self.base.isRelocatable() and options.zo.dwarf != null) {3382 if (self.base.isRelocatable()) if (options.zo.dwarf) |*dwarf| {
3371 {3383 self.debug_str_sect_index = try self.addSection("__DWARF", "__debug_str", .{
3372 self.debug_str_sect_index = try self.addSection("__DWARF", "__debug_str", .{3384 .flags = macho.S_ATTR_DEBUG,
3373 .flags = macho.S_ATTR_DEBUG,3385 });
3374 });3386 self.debug_info_sect_index = try self.addSection("__DWARF", "__debug_info", .{
3375 try allocSect(self, self.debug_str_sect_index.?, 200);3387 .flags = macho.S_ATTR_DEBUG,
3376 }3388 });
33773389 self.debug_abbrev_sect_index = try self.addSection("__DWARF", "__debug_abbrev", .{
3378 {3390 .flags = macho.S_ATTR_DEBUG,
3379 self.debug_info_sect_index = try self.addSection("__DWARF", "__debug_info", .{3391 });
3380 .flags = macho.S_ATTR_DEBUG,3392 self.debug_aranges_sect_index = try self.addSection("__DWARF", "__debug_aranges", .{
3381 });3393 .alignment = 4,
3382 try allocSect(self, self.debug_info_sect_index.?, 200);3394 .flags = macho.S_ATTR_DEBUG,
3383 }3395 });
33843396 self.debug_line_sect_index = try self.addSection("__DWARF", "__debug_line", .{
3385 {3397 .flags = macho.S_ATTR_DEBUG,
3386 self.debug_abbrev_sect_index = try self.addSection("__DWARF", "__debug_abbrev", .{3398 });
3387 .flags = macho.S_ATTR_DEBUG,3399 self.debug_line_str_sect_index = try self.addSection("__DWARF", "__debug_line_str", .{
3388 });3400 .flags = macho.S_ATTR_DEBUG,
3389 try allocSect(self, self.debug_abbrev_sect_index.?, 128);3401 });
3390 }3402 self.debug_loclists_sect_index = try self.addSection("__DWARF", "__debug_loclists", .{
33913403 .flags = macho.S_ATTR_DEBUG,
3392 {3404 });
3393 self.debug_aranges_sect_index = try self.addSection("__DWARF", "__debug_aranges", .{3405 self.debug_rnglists_sect_index = try self.addSection("__DWARF", "__debug_rnglists", .{
3394 .alignment = 4,3406 .flags = macho.S_ATTR_DEBUG,
3395 .flags = macho.S_ATTR_DEBUG,3407 });
3396 });3408 try dwarf.initMetadata();
3397 try allocSect(self, self.debug_aranges_sect_index.?, 160);3409 };
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 }
3407}3410}
34083411
3409pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {3412pub 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 {...@@ -3417,35 +3420,36 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
3417fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void {3420fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void {
3418 const sect = &self.sections.items(.header)[sect_index];3421 const sect = &self.sections.items(.header)[sect_index];
34193422
3420 if (needed_size > self.allocatedSize(sect.offset) and !sect.isZerofill()) {3423 const seg_id = self.sections.items(.segment_id)[sect_index];
3421 const existing_size = sect.size;3424 const seg = &self.segments.items[seg_id];
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 });
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);3434 // Must move the entire section.
3438 }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];3445 try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);
3443 const seg = &self.segments.items[seg_id];
3444 seg.fileoff = sect.offset;
34453446
3446 if (!sect.isZerofill()) {3447 sect.offset = @intCast(new_offset);
3448 }
3447 seg.filesize = needed_size;3449 seg.filesize = needed_size;
3448 }3450 }
3451 sect.size = needed_size;
3452 seg.fileoff = sect.offset;
34493453
3450 const mem_capacity = self.allocatedSizeVirtual(seg.vmaddr);3454 const mem_capacity = self.allocatedSizeVirtual(seg.vmaddr);
3451 if (needed_size > mem_capacity) {3455 if (needed_size > mem_capacity) {
...@@ -3464,30 +3468,34 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo...@@ -3464,30 +3468,34 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
3464fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void {3468fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void {
3465 const sect = &self.sections.items(.header)[sect_index];3469 const sect = &self.sections.items(.header)[sect_index];
34663470
3467 if (needed_size > self.allocatedSize(sect.offset) and !sect.isZerofill()) {3471 if (!sect.isZerofill()) {
3468 const existing_size = sect.size;3472 const allocated_size = self.allocatedSize(sect.offset);
3469 sect.size = 0;3473 if (sect.offset + allocated_size == std.math.maxInt(u64)) {
34703474 try self.base.file.?.setEndPos(sect.offset + needed_size);
3471 // Must move the entire section.3475 } else if (needed_size > allocated_size) {
3472 const alignment = try math.powi(u32, 2, sect.@"align");3476 const existing_size = sect.size;
3473 const new_offset = self.findFreeSpace(needed_size, alignment);3477 sect.size = 0;
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 });
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);3484 log.debug("new '{s},{s}' file offset 0x{x} to 0x{x} (0x{x} - 0x{x})", .{
3488 sect.addr = new_addr;3485 sect.segName(),
3489 }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 }
3491 sect.size = needed_size;3499 sect.size = needed_size;
3492}3500}
34933501
...@@ -4591,7 +4599,6 @@ const std = @import("std");...@@ -4591,7 +4599,6 @@ const std = @import("std");
4591const build_options = @import("build_options");4599const build_options = @import("build_options");
4592const builtin = @import("builtin");4600const builtin = @import("builtin");
4593const assert = std.debug.assert;4601const assert = std.debug.assert;
4594const dwarf = std.dwarf;
4595const fs = std.fs;4602const fs = std.fs;
4596const log = std.log.scoped(.link);4603const log = std.log.scoped(.link);
4597const state_log = std.log.scoped(.link_state);4604const state_log = std.log.scoped(.link_state);
src/link/MachO/DebugSymbols.zig+36-31
...@@ -15,6 +15,9 @@ debug_abbrev_section_index: ?u8 = null,...@@ -15,6 +15,9 @@ debug_abbrev_section_index: ?u8 = null,
15debug_str_section_index: ?u8 = null,15debug_str_section_index: ?u8 = null,
16debug_aranges_section_index: ?u8 = null,16debug_aranges_section_index: ?u8 = null,
17debug_line_section_index: ?u8 = null,17debug_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
19relocs: std.ArrayListUnmanaged(Reloc) = .{},22relocs: std.ArrayListUnmanaged(Reloc) = .{},
2023
...@@ -56,13 +59,16 @@ pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -56,13 +59,16 @@ pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {
56 });59 });
57 }60 }
5861
59 self.debug_str_section_index = try self.allocateSection("__debug_str", 200, 0);62 self.debug_str_section_index = try self.createSection("__debug_str", 0);
60 self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0);63 self.debug_info_section_index = try self.createSection("__debug_info", 0);
61 self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0);64 self.debug_abbrev_section_index = try self.createSection("__debug_abbrev", 0);
62 self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4);65 self.debug_aranges_section_index = try self.createSection("__debug_aranges", 4);
63 self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0);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);
66 try self.segments.append(self.allocator, .{72 try self.segments.append(self.allocator, .{
67 .segname = makeStaticString("__LINKEDIT"),73 .segname = makeStaticString("__LINKEDIT"),
68 .maxprot = macho.PROT.READ,74 .maxprot = macho.PROT.READ,
...@@ -71,27 +77,17 @@ pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -71,27 +77,17 @@ pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {
71 });77 });
72}78}
7379
74fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u8 {80fn createSection(self: *DebugSymbols, sectname: []const u8, alignment: u16) !u8 {
75 const segment = self.getDwarfSegmentPtr();81 const segment = self.getDwarfSegmentPtr();
76 var sect = macho.section_64{82 var sect = macho.section_64{
77 .sectname = makeStaticString(sectname),83 .sectname = makeStaticString(sectname),
78 .segname = segment.segname,84 .segname = segment.segname,
79 .size = @as(u32, @intCast(size)),
80 .@"align" = alignment,85 .@"align" = alignment,
81 };86 };
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);
95 try self.sections.append(self.allocator, sect);91 try self.sections.append(self.allocator, sect);
96 segment.cmdsize += @sizeOf(macho.section_64);92 segment.cmdsize += @sizeOf(macho.section_64);
97 segment.nsects += 1;93 segment.nsects += 1;
...@@ -102,16 +98,19 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme...@@ -102,16 +98,19 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
102pub fn growSection(98pub fn growSection(
103 self: *DebugSymbols,99 self: *DebugSymbols,
104 sect_index: u8,100 sect_index: u8,
105 needed_size: u32,101 needed_size: u64,
106 requires_file_copy: bool,102 requires_file_copy: bool,
107 macho_file: *MachO,103 macho_file: *MachO,
108) !void {104) !void {
109 const sect = self.getSectionPtr(sect_index);105 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) {
112 const existing_size = sect.size;111 const existing_size = sect.size;
113 sect.size = 0; // free the space112 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
116 log.debug("moving {s} section: {} bytes from 0x{x} to 0x{x}", .{115 log.debug("moving {s} section: {} bytes from 0x{x} to 0x{x}", .{
117 sect.sectName(),116 sect.sectName(),
...@@ -130,7 +129,7 @@ pub fn growSection(...@@ -130,7 +129,7 @@ pub fn growSection(
130 if (amt != existing_size) return error.InputOutput;129 if (amt != existing_size) return error.InputOutput;
131 }130 }
132131
133 sect.offset = @as(u32, @intCast(new_offset));132 sect.offset = @intCast(new_offset);
134 }133 }
135134
136 sect.size = needed_size;135 sect.size = needed_size;
...@@ -153,22 +152,27 @@ pub fn markDirty(self: *DebugSymbols, sect_index: u8, macho_file: *MachO) void {...@@ -153,22 +152,27 @@ pub fn markDirty(self: *DebugSymbols, sect_index: u8, macho_file: *MachO) void {
153 }152 }
154}153}
155154
156fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {155fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) !?u64 {
156 var at_end = true;
157 const end = start + padToIdeal(size);157 const end = start + padToIdeal(size);
158
158 for (self.sections.items) |section| {159 for (self.sections.items) |section| {
159 const increased_size = padToIdeal(section.size);160 const increased_size = padToIdeal(section.size);
160 const test_end = section.offset + increased_size;161 const test_end = section.offset + increased_size;
161 if (end > section.offset and start < test_end) {162 if (start < test_end) {
162 return test_end;163 if (end > section.offset) return test_end;
164 if (test_end < std.math.maxInt(u64)) at_end = false;
163 }165 }
164 }166 }
167
168 if (at_end) try self.file.setEndPos(end);
165 return null;169 return null;
166}170}
167171
168fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 {172fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) !u64 {
169 const segment = self.getDwarfSegmentPtr();173 const segment = self.getDwarfSegmentPtr();
170 var offset: u64 = segment.fileoff;174 var offset: u64 = segment.fileoff;
171 while (self.detectAllocCollision(offset, object_size)) |item_end| {175 while (try self.detectAllocCollision(offset, object_size)) |item_end| {
172 offset = mem.alignForward(u64, item_end, min_alignment);176 offset = mem.alignForward(u64, item_end, min_alignment);
173 }177 }
174 return offset;178 return offset;
...@@ -346,6 +350,7 @@ fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds...@@ -346,6 +350,7 @@ fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds
346}350}
347351
348fn allocatedSize(self: *DebugSymbols, start: u64) u64 {352fn allocatedSize(self: *DebugSymbols, start: u64) u64 {
353 if (start == 0) return 0;
349 const seg = self.getDwarfSegmentPtr();354 const seg = self.getDwarfSegmentPtr();
350 assert(start >= seg.fileoff);355 assert(start >= seg.fileoff);
351 var min_pos: u64 = std.math.maxInt(u64);356 var min_pos: u64 = std.math.maxInt(u64);
...@@ -413,9 +418,9 @@ pub fn writeStrtab(self: *DebugSymbols, off: u32) !u32 {...@@ -413,9 +418,9 @@ pub fn writeStrtab(self: *DebugSymbols, off: u32) !u32 {
413418
414pub fn getSectionIndexes(self: *DebugSymbols, segment_index: u8) struct { start: u8, end: u8 } {419pub fn getSectionIndexes(self: *DebugSymbols, segment_index: u8) struct { start: u8, end: u8 } {
415 var start: u8 = 0;420 var start: u8 = 0;
416 const nsects = for (self.segments.items, 0..) |seg, i| {421 const nsects: u8 = for (self.segments.items, 0..) |seg, i| {
417 if (i == segment_index) break @as(u8, @intCast(seg.nsects));422 if (i == segment_index) break @intCast(seg.nsects);
418 start += @as(u8, @intCast(seg.nsects));423 start += @intCast(seg.nsects);
419 } else 0;424 } else 0;
420 return .{ .start = start, .end = start + nsects };425 return .{ .start = start, .end = start + nsects };
421}426}
src/link/MachO/ZigObject.zig+64-99
...@@ -55,8 +55,7 @@ pub fn init(self: *ZigObject, macho_file: *MachO) !void {...@@ -55,8 +55,7 @@ pub fn init(self: *ZigObject, macho_file: *MachO) !void {
55 switch (comp.config.debug_format) {55 switch (comp.config.debug_format) {
56 .strip => {},56 .strip => {},
57 .dwarf => |v| {57 .dwarf => |v| {
58 assert(v == .@"32");58 self.dwarf = Dwarf.init(&macho_file.base, v);
59 self.dwarf = Dwarf.init(&macho_file.base, .dwarf32);
60 self.debug_strtab_dirty = true;59 self.debug_strtab_dirty = true;
61 self.debug_abbrev_dirty = true;60 self.debug_abbrev_dirty = true;
62 self.debug_aranges_dirty = true;61 self.debug_aranges_dirty = true;
...@@ -101,8 +100,8 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {...@@ -101,8 +100,8 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
101 }100 }
102 self.tlv_initializers.deinit(allocator);101 self.tlv_initializers.deinit(allocator);
103102
104 if (self.dwarf) |*dw| {103 if (self.dwarf) |*dwarf| {
105 dw.deinit();104 dwarf.deinit();
106 }105 }
107}106}
108107
...@@ -595,56 +594,13 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id)...@@ -595,56 +594,13 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id)
595 if (metadata.const_state != .unused) metadata.const_state = .flushed;594 if (metadata.const_state != .unused) metadata.const_state = .flushed;
596 }595 }
597596
598 if (self.dwarf) |*dw| {597 if (self.dwarf) |*dwarf| {
599 const pt: Zcu.PerThread = .{ .zcu = macho_file.base.comp.module.?, .tid = tid };598 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) {601 self.debug_abbrev_dirty = false;
603 try dw.writeDbgAbbrev();602 self.debug_aranges_dirty = false;
604 self.debug_abbrev_dirty = false;603 self.debug_strtab_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 }
648 }604 }
649605
650 // The point of flushModule() is to commit changes, so in theory, nothing should606 // The point of flushModule() is to commit changes, so in theory, nothing should
...@@ -816,8 +772,8 @@ pub fn updateFunc(...@@ -816,8 +772,8 @@ pub fn updateFunc(
816 var code_buffer = std.ArrayList(u8).init(gpa);772 var code_buffer = std.ArrayList(u8).init(gpa);
817 defer code_buffer.deinit();773 defer code_buffer.deinit();
818774
819 var dwarf_state = if (self.dwarf) |*dw| try dw.initNavState(pt, func.owner_nav) else null;775 var dwarf_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null;
820 defer if (dwarf_state) |*ds| ds.deinit();776 defer if (dwarf_wip_nav) |*wip_nav| wip_nav.deinit();
821777
822 const res = try codegen.generateFunction(778 const res = try codegen.generateFunction(
823 &macho_file.base,779 &macho_file.base,
...@@ -827,7 +783,7 @@ pub fn updateFunc(...@@ -827,7 +783,7 @@ pub fn updateFunc(
827 air,783 air,
828 liveness,784 liveness,
829 &code_buffer,785 &code_buffer,
830 if (dwarf_state) |*ds| .{ .dwarf = ds } else .none,786 if (dwarf_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
831 );787 );
832788
833 const code = switch (res) {789 const code = switch (res) {
...@@ -841,14 +797,17 @@ pub fn updateFunc(...@@ -841,14 +797,17 @@ pub fn updateFunc(
841 const sect_index = try self.getNavOutputSection(macho_file, zcu, func.owner_nav, code);797 const sect_index = try self.getNavOutputSection(macho_file, zcu, func.owner_nav, code);
842 try self.updateNavCode(macho_file, pt, func.owner_nav, sym_index, sect_index, code);798 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| {
845 const sym = self.symbols.items[sym_index];801 const sym = self.symbols.items[sym_index];
846 try self.dwarf.?.commitNavState(802 try self.dwarf.?.finishWipNav(
847 pt,803 pt,
848 func.owner_nav,804 func.owner_nav,
849 sym.getAddress(.{}, macho_file),805 .{
850 sym.getAtom(macho_file).?.size,806 .index = sym_index,
851 ds,807 .addr = sym.getAddress(.{}, macho_file),
808 .size = sym.getAtom(macho_file).?.size,
809 },
810 wip_nav,
852 );811 );
853 }812 }
854813
...@@ -866,6 +825,7 @@ pub fn updateNav(...@@ -866,6 +825,7 @@ pub fn updateNav(
866825
867 const zcu = pt.zcu;826 const zcu = pt.zcu;
868 const ip = &zcu.intern_pool;827 const ip = &zcu.intern_pool;
828
869 const nav_val = zcu.navValue(nav_index);829 const nav_val = zcu.navValue(nav_index);
870 const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {830 const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
871 .variable => |variable| Value.fromInterned(variable.init),831 .variable => |variable| Value.fromInterned(variable.init),
...@@ -882,48 +842,53 @@ pub fn updateNav(...@@ -882,48 +842,53 @@ pub fn updateNav(
882 else => nav_val,842 else => nav_val,
883 };843 };
884844
885 const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index);845 if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
886 self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);846 const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index);
887847 self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);
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();
893848
894 const res = try codegen.generateSymbol(849 var code_buffer = std.ArrayList(u8).init(zcu.gpa);
895 &macho_file.base,850 defer code_buffer.deinit();
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 );
903851
904 const code = switch (res) {852 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null;
905 .ok => code_buffer.items,853 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
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);
916854
917 if (nav_state) |*ns| {855 const res = try codegen.generateSymbol(
918 const sym = self.symbols.items[sym_index];856 &macho_file.base,
919 try self.dwarf.?.commitNavState(
920 pt,857 pt,
921 nav_index,858 zcu.navSrcLoc(nav_index),
922 sym.getAddress(.{}, macho_file),859 nav_init,
923 sym.getAtom(macho_file).?.size,860 &code_buffer,
924 ns,861 if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
862 .{ .parent_atom_index = sym_index },
925 );863 );
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
928 // Exports will be updated by `Zcu.processExports` after the update.893 // Exports will be updated by `Zcu.processExports` after the update.
929}894}
...@@ -1435,8 +1400,8 @@ pub fn updateNavLineNumber(...@@ -1435,8 +1400,8 @@ pub fn updateNavLineNumber(
1435 pt: Zcu.PerThread,1400 pt: Zcu.PerThread,
1436 nav_index: InternPool.Nav.Index,1401 nav_index: InternPool.Nav.Index,
1437) !void {1402) !void {
1438 if (self.dwarf) |*dw| {1403 if (self.dwarf) |*dwarf| {
1439 try dw.updateNavLineNumber(pt.zcu, nav_index);1404 try dwarf.updateNavLineNumber(pt.zcu, nav_index);
1440 }1405 }
1441}1406}
14421407
src/link/MachO/relocatable.zig+1-1
...@@ -465,7 +465,7 @@ fn allocateSections(macho_file: *MachO) !void {...@@ -465,7 +465,7 @@ fn allocateSections(macho_file: *MachO) !void {
465 const alignment = try math.powi(u32, 2, header.@"align");465 const alignment = try math.powi(u32, 2, header.@"align");
466 if (!header.isZerofill()) {466 if (!header.isZerofill()) {
467 if (needed_size > macho_file.allocatedSize(header.offset)) {467 if (needed_size > macho_file.allocatedSize(header.offset)) {
468 header.offset = math.cast(u32, macho_file.findFreeSpace(needed_size, alignment)) orelse468 header.offset = math.cast(u32, try macho_file.findFreeSpace(needed_size, alignment)) orelse
469 return error.Overflow;469 return error.Overflow;
470 }470 }
471 }471 }
src/link/Plan9.zig+23-20
...@@ -454,28 +454,31 @@ pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -454,28 +454,31 @@ pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
454 },454 },
455 else => nav_val,455 else => nav_val,
456 };456 };
457 const atom_idx = try self.seeNav(pt, nav_index);
458457
459 var code_buffer = std.ArrayList(u8).init(gpa);458 if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
460 defer code_buffer.deinit();459 const atom_idx = try self.seeNav(pt, nav_index);
461 // TODO we need the symbol index for symbol in the table of locals for the containing atom460
462 const res = try codegen.generateSymbol(&self.base, pt, zcu.navSrcLoc(nav_index), nav_init, &code_buffer, .none, .{461 var code_buffer = std.ArrayList(u8).init(gpa);
463 .parent_atom_index = @intCast(atom_idx),462 defer code_buffer.deinit();
464 });463 // TODO we need the symbol index for symbol in the table of locals for the containing atom
465 const code = switch (res) {464 const res = try codegen.generateSymbol(&self.base, pt, zcu.navSrcLoc(nav_index), nav_init, &code_buffer, .none, .{
466 .ok => code_buffer.items,465 .parent_atom_index = @intCast(atom_idx),
467 .fail => |em| {466 });
468 try zcu.failed_codegen.put(gpa, nav_index, em);467 const code = switch (res) {
469 return;468 .ok => code_buffer.items,
470 },469 .fail => |em| {
471 };470 try zcu.failed_codegen.put(gpa, nav_index, em);
472 try self.data_nav_table.ensureUnusedCapacity(gpa, 1);471 return;
473 const duped_code = try gpa.dupe(u8, code);472 },
474 self.getAtomPtr(self.navs.get(nav_index).?.index).code = .{ .code_ptr = null, .other = .{ .nav_index = nav_index } };473 };
475 if (self.data_nav_table.fetchPutAssumeCapacity(nav_index, duped_code)) |old_entry| {474 try self.data_nav_table.ensureUnusedCapacity(gpa, 1);
476 gpa.free(old_entry.value);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);
477 }481 }
478 return self.updateFinish(pt, nav_index);
479}482}
480483
481/// called at the end of update{Decl,Func}484/// called at the end of update{Decl,Func}
src/link/Wasm/ZigObject.zig+32-29
...@@ -248,46 +248,49 @@ pub fn updateNav(...@@ -248,46 +248,49 @@ pub fn updateNav(
248 const ip = &zcu.intern_pool;248 const ip = &zcu.intern_pool;
249 const nav = ip.getNav(nav_index);249 const nav = ip.getNav(nav_index);
250250
251 const is_extern, const lib_name, const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {251 const nav_val = zcu.navValue(nav_index);
252 .variable => |variable| .{ false, variable.lib_name, variable.init },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) },
253 .func => return,254 .func => return,
254 .@"extern" => |@"extern"| if (ip.isFunctionType(nav.typeOf(ip)))255 .@"extern" => |@"extern"| if (ip.isFunctionType(nav.typeOf(ip)))
255 return256 return
256 else257 else
257 .{ true, @"extern".lib_name, nav.status.resolved.val },258 .{ true, @"extern".lib_name, nav_val },
258 else => .{ false, .none, nav.status.resolved.val },259 else => .{ false, .none, nav_val },
259 };260 };
260261
261 const gpa = wasm_file.base.comp.gpa;262 if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
262 const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index);263 const gpa = wasm_file.base.comp.gpa;
263 const atom = wasm_file.getAtomPtr(atom_index);264 const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index);
264 atom.clear();265 const atom = wasm_file.getAtomPtr(atom_index);
266 atom.clear();
265267
266 if (is_extern)268 if (is_extern)
267 return zig_object.addOrUpdateImport(wasm_file, nav.name.toSlice(ip), atom.sym_index, lib_name.toSlice(ip), null);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);271 var code_writer = std.ArrayList(u8).init(gpa);
270 defer code_writer.deinit();272 defer code_writer.deinit();
271273
272 const res = try codegen.generateSymbol(274 const res = try codegen.generateSymbol(
273 &wasm_file.base,275 &wasm_file.base,
274 pt,276 pt,
275 zcu.navSrcLoc(nav_index),277 zcu.navSrcLoc(nav_index),
276 Value.fromInterned(nav_init),278 nav_init,
277 &code_writer,279 &code_writer,
278 .none,280 .none,
279 .{ .parent_atom_index = @intFromEnum(atom.sym_index) },281 .{ .parent_atom_index = @intFromEnum(atom.sym_index) },
280 );282 );
281283
282 const code = switch (res) {284 const code = switch (res) {
283 .ok => code_writer.items,285 .ok => code_writer.items,
284 .fail => |em| {286 .fail => |em| {
285 try zcu.failed_codegen.put(zcu.gpa, nav_index, em);287 try zcu.failed_codegen.put(zcu.gpa, nav_index, em);
286 return;288 return;
287 },289 },
288 };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 }
291}294}
292295
293pub fn updateFunc(296pub fn updateFunc(
src/print_zir.zig+1-1
...@@ -746,7 +746,7 @@ const Writer = struct {...@@ -746,7 +746,7 @@ const Writer = struct {
746 fn writeIntBig(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {746 fn writeIntBig(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
747 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str;747 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str;
748 const byte_count = inst_data.len * @sizeOf(std.math.big.Limb);748 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];
750 // limb_bytes is not aligned properly; we must allocate and copy the bytes750 // limb_bytes is not aligned properly; we must allocate and copy the bytes
751 // in order to accomplish this.751 // in order to accomplish this.
752 const limbs = try self.gpa.alloc(std.math.big.Limb, inst_data.len);752 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");...@@ -10,6 +10,7 @@ const Zcu = @import("Zcu.zig");
10const expect = std.testing.expect;10const expect = std.testing.expect;
11const expectEqual = std.testing.expectEqual;11const expectEqual = std.testing.expectEqual;
12const expectEqualSlices = std.testing.expectEqualSlices;12const expectEqualSlices = std.testing.expectEqualSlices;
13const link = @import("link.zig");
1314
14const log = std.log.scoped(.register_manager);15const log = std.log.scoped(.register_manager);
1516
...@@ -25,7 +26,7 @@ pub const AllocateRegistersError = error{...@@ -25,7 +26,7 @@ pub const AllocateRegistersError = error{
25 /// Can happen when spilling an instruction triggers a codegen26 /// Can happen when spilling an instruction triggers a codegen
26 /// error, so we propagate that error27 /// error, so we propagate that error
27 CodegenFail,28 CodegenFail,
28};29} || link.File.UpdateDebugInfoError;
2930
30pub fn RegisterManager(31pub fn RegisterManager(
31 comptime Function: type,32 comptime Function: type,
test/src/Debugger.zig created+500
...@@ -0,0 +1,500 @@
1b: *std.Build,
2options: Options,
3root_step: *std.Build.Step,
4
5pub const Options = struct {
6 test_filters: []const []const u8,
7 gdb: ?[]const u8,
8 lldb: ?[]const u8,
9 optimize_modes: []const std.builtin.OptimizeMode,
10 skip_single_threaded: bool,
11 skip_non_native: bool,
12 skip_libc: bool,
13};
14
15pub const Target = struct {
16 resolved: std.Build.ResolvedTarget,
17 optimize_mode: std.builtin.OptimizeMode = .Debug,
18 link_libc: ?bool = null,
19 single_threaded: ?bool = null,
20 pic: ?bool = null,
21 test_name_suffix: []const u8,
22};
23
24pub fn addTestsForTarget(db: *Debugger, target: Target) void {
25 db.addLldbTest(
26 "basic",
27 target,
28 &.{
29 .{
30 .path = "basic.zig",
31 .source =
32 \\const Basic = struct {
33 \\ void: void = {},
34 \\ bool_false: bool = false,
35 \\ bool_true: bool = true,
36 \\ u0_0: u0 = 0,
37 \\ u1_0: u1 = 0,
38 \\ u1_1: u1 = 1,
39 \\ u2_0: u2 = 0,
40 \\ u2_3: u2 = 3,
41 \\ u3_0: u3 = 0,
42 \\ u3_7: u3 = 7,
43 \\ u4_0: u4 = 0,
44 \\ u4_15: u4 = 15,
45 \\ u5_0: u5 = 0,
46 \\ u5_31: u5 = 31,
47 \\ u6_0: u6 = 0,
48 \\ u6_63: u6 = 63,
49 \\ u7_0: u7 = 0,
50 \\ u7_127: u7 = 127,
51 \\ u8_0: u8 = 0,
52 \\ u8_255: u8 = 255,
53 \\ u16_0: u16 = 0,
54 \\ u16_65535: u16 = 65535,
55 \\ u24_0: u24 = 0,
56 \\ u24_16777215: u24 = 16777215,
57 \\ u32_0: u32 = 0,
58 \\ u32_4294967295: u32 = 4294967295,
59 \\ i0_0: i0 = 0,
60 \\ @"i1_-1": i1 = -1,
61 \\ i1_0: i1 = 0,
62 \\ @"i2_-2": i2 = -2,
63 \\ i2_0: i2 = 0,
64 \\ i2_1: i2 = 1,
65 \\ @"i3_-4": i3 = -4,
66 \\ i3_0: i3 = 0,
67 \\ i3_3: i3 = 3,
68 \\ @"i4_-8": i4 = -8,
69 \\ i4_0: i4 = 0,
70 \\ i4_7: i4 = 7,
71 \\ @"i5_-16": i5 = -16,
72 \\ i5_0: i5 = 0,
73 \\ i5_15: i5 = 15,
74 \\ @"i6_-32": i6 = -32,
75 \\ i6_0: i6 = 0,
76 \\ i6_31: i6 = 31,
77 \\ @"i7_-64": i7 = -64,
78 \\ i7_0: i7 = 0,
79 \\ i7_63: i7 = 63,
80 \\ @"i8_-128": i8 = -128,
81 \\ i8_0: i8 = 0,
82 \\ i8_127: i8 = 127,
83 \\ @"i16_-32768": i16 = -32768,
84 \\ i16_0: i16 = 0,
85 \\ i16_32767: i16 = 32767,
86 \\ @"i24_-8388608": i24 = -8388608,
87 \\ i24_0: i24 = 0,
88 \\ i24_8388607: i24 = 8388607,
89 \\ @"i32_-2147483648": i32 = -2147483648,
90 \\ i32_0: i32 = 0,
91 \\ i32_2147483647: i32 = 2147483647,
92 \\ @"f16_42.625": f16 = 42.625,
93 \\ @"f32_-2730.65625": f32 = -2730.65625,
94 \\ @"f64_357913941.33203125": f64 = 357913941.33203125,
95 \\ @"f80_-91625968981.3330078125": f80 = -91625968981.3330078125,
96 \\ @"f128_384307168202282325.333332061767578125": f128 = 384307168202282325.333332061767578125,
97 \\};
98 \\fn testBasic(basic: Basic) void {
99 \\ _ = basic;
100 \\}
101 \\pub fn main() void {
102 \\ testBasic(.{});
103 \\}
104 \\
105 ,
106 },
107 },
108 \\breakpoint set --file basic.zig --source-pattern-regexp '_ = basic;'
109 \\process launch
110 \\frame variable --show-types basic
111 \\breakpoint delete --force 1
112 ,
113 &.{
114 \\(lldb) frame variable --show-types basic
115 \\(root.basic.Basic) basic = {
116 \\ (void) void = {}
117 \\ (bool) bool_false = false
118 \\ (bool) bool_true = true
119 \\ (u0) u0_0 = 0
120 \\ (u1) u1_0 = 0
121 \\ (u1) u1_1 = 1
122 \\ (u2) u2_0 = 0
123 \\ (u2) u2_3 = 3
124 \\ (u3) u3_0 = 0
125 \\ (u3) u3_7 = 7
126 \\ (u4) u4_0 = 0
127 \\ (u4) u4_15 = 15
128 \\ (u5) u5_0 = 0
129 \\ (u5) u5_31 = 31
130 \\ (u6) u6_0 = 0
131 \\ (u6) u6_63 = 63
132 \\ (u7) u7_0 = 0
133 \\ (u7) u7_127 = 127
134 \\ (u8) u8_0 = 0
135 \\ (u8) u8_255 = 255
136 \\ (u16) u16_0 = 0
137 \\ (u16) u16_65535 = 65535
138 \\ (u24) u24_0 = 0
139 \\ (u24) u24_16777215 = 16777215
140 \\ (u32) u32_0 = 0
141 \\ (u32) u32_4294967295 = 4294967295
142 \\ (i0) i0_0 = 0
143 \\ (i1) i1_-1 = -1
144 \\ (i1) i1_0 = 0
145 \\ (i2) i2_-2 = -2
146 \\ (i2) i2_0 = 0
147 \\ (i2) i2_1 = 1
148 \\ (i3) i3_-4 = -4
149 \\ (i3) i3_0 = 0
150 \\ (i3) i3_3 = 3
151 \\ (i4) i4_-8 = -8
152 \\ (i4) i4_0 = 0
153 \\ (i4) i4_7 = 7
154 \\ (i5) i5_-16 = -16
155 \\ (i5) i5_0 = 0
156 \\ (i5) i5_15 = 15
157 \\ (i6) i6_-32 = -32
158 \\ (i6) i6_0 = 0
159 \\ (i6) i6_31 = 31
160 \\ (i7) i7_-64 = -64
161 \\ (i7) i7_0 = 0
162 \\ (i7) i7_63 = 63
163 \\ (i8) i8_-128 = -128
164 \\ (i8) i8_0 = 0
165 \\ (i8) i8_127 = 127
166 \\ (i16) i16_-32768 = -32768
167 \\ (i16) i16_0 = 0
168 \\ (i16) i16_32767 = 32767
169 \\ (i24) i24_-8388608 = -8388608
170 \\ (i24) i24_0 = 0
171 \\ (i24) i24_8388607 = 8388607
172 \\ (i32) i32_-2147483648 = -2147483648
173 \\ (i32) i32_0 = 0
174 \\ (i32) i32_2147483647 = 2147483647
175 \\ (f16) f16_42.625 = 42.625
176 \\ (f32) f32_-2730.65625 = -2730.65625
177 \\ (f64) f64_357913941.33203125 = 357913941.33203125
178 \\ (f80) f80_-91625968981.3330078125 = -91625968981.3330078125
179 \\ (f128) f128_384307168202282325.333332061767578125 = 384307168202282325.333332061767578125
180 \\}
181 \\(lldb) breakpoint delete --force 1
182 \\1 breakpoints deleted; 0 breakpoint locations disabled.
183 },
184 );
185 db.addLldbTest(
186 "storage",
187 target,
188 &.{
189 .{
190 .path = "storage.zig",
191 .source =
192 \\const global_const: u64 = 0x19e50dc8d6002077;
193 \\var global_var: u64 = 0xcc423cec08622e32;
194 \\threadlocal var global_threadlocal1: u64 = 0xb4d643528c042121;
195 \\threadlocal var global_threadlocal2: u64 = 0x43faea1cf5ad7a22;
196 \\fn testStorage(
197 \\ param1: u64,
198 \\ param2: u64,
199 \\ param3: u64,
200 \\ param4: u64,
201 \\ param5: u64,
202 \\ param6: u64,
203 \\ param7: u64,
204 \\ param8: u64,
205 \\) callconv(.C) void {
206 \\ const local_comptime_val: u64 = global_const *% global_const;
207 \\ const local_comptime_ptr: struct { u64 } = .{ local_comptime_val *% local_comptime_val };
208 \\ const local_const: u64 = global_var ^ global_threadlocal1 ^ global_threadlocal2 ^
209 \\ param1 ^ param2 ^ param3 ^ param4 ^ param5 ^ param6 ^ param7 ^ param8;
210 \\ var local_var: u64 = local_comptime_ptr[0] ^ local_const;
211 \\ local_var = local_var;
212 \\}
213 \\pub fn main() void {
214 \\ testStorage(
215 \\ 0x6a607e08125c7e00,
216 \\ 0x98944cb2a45a8b51,
217 \\ 0xa320cf10601ee6fb,
218 \\ 0x691ed3535bad3274,
219 \\ 0x63690e6867a5799f,
220 \\ 0x8e163f0ec76067f2,
221 \\ 0xf9a252c455fb4c06,
222 \\ 0xc88533722601e481,
223 \\ );
224 \\}
225 \\
226 ,
227 },
228 },
229 \\breakpoint set --file storage.zig --source-pattern-regexp 'local_var = local_var;'
230 \\process launch
231 \\target variable --show-types --format hex global_const global_var global_threadlocal1 global_threadlocal2
232 \\frame variable --show-types --format hex param1 param2 param3 param4 param5 param6 param7 param8 local_comptime_val local_comptime_ptr.0 local_const local_var
233 \\breakpoint delete --force 1
234 ,
235 &.{
236 \\(lldb) target variable --show-types --format hex global_const global_var global_threadlocal1 global_threadlocal2
237 \\(u64) global_const = 0x19e50dc8d6002077
238 \\(u64) global_var = 0xcc423cec08622e32
239 \\(u64) global_threadlocal1 = 0xb4d643528c042121
240 \\(u64) global_threadlocal2 = 0x43faea1cf5ad7a22
241 \\(lldb) frame variable --show-types --format hex param1 param2 param3 param4 param5 param6 param7 param8 local_comptime_val local_comptime_ptr.0 local_const local_var
242 \\(u64) param1 = 0x6a607e08125c7e00
243 \\(u64) param2 = 0x98944cb2a45a8b51
244 \\(u64) param3 = 0xa320cf10601ee6fb
245 \\(u64) param4 = 0x691ed3535bad3274
246 \\(u64) param5 = 0x63690e6867a5799f
247 \\(u64) param6 = 0x8e163f0ec76067f2
248 \\(u64) param7 = 0xf9a252c455fb4c06
249 \\(u64) param8 = 0xc88533722601e481
250 \\(u64) local_comptime_val = 0x69490636f81df751
251 \\(u64) local_comptime_ptr.0 = 0x82e834dae74767a1
252 \\(u64) local_const = 0xdffceb8b2f41e205
253 \\(u64) local_var = 0x5d14df51c80685a4
254 \\(lldb) breakpoint delete --force 1
255 \\1 breakpoints deleted; 0 breakpoint locations disabled.
256 },
257 );
258 db.addLldbTest(
259 "slices",
260 target,
261 &.{
262 .{
263 .path = "slices.zig",
264 .source =
265 \\pub fn main() void {
266 \\ {
267 \\ var array: [4]u32 = .{ 1, 2, 4, 8 };
268 \\ const slice: []u32 = &array;
269 \\ _ = slice;
270 \\ }
271 \\}
272 \\
273 ,
274 },
275 },
276 \\breakpoint set --file slices.zig --source-pattern-regexp '_ = slice;'
277 \\process launch
278 \\frame variable --show-types array slice
279 \\breakpoint delete --force 1
280 ,
281 &.{
282 \\(lldb) frame variable --show-types array slice
283 \\([4]u32) array = {
284 \\ (u32) [0] = 1
285 \\ (u32) [1] = 2
286 \\ (u32) [2] = 4
287 \\ (u32) [3] = 8
288 \\}
289 \\([]u32) slice = {
290 \\ (u32) [0] = 1
291 \\ (u32) [1] = 2
292 \\ (u32) [2] = 4
293 \\ (u32) [3] = 8
294 \\}
295 \\(lldb) breakpoint delete --force 1
296 \\1 breakpoints deleted; 0 breakpoint locations disabled.
297 },
298 );
299 db.addLldbTest(
300 "optionals",
301 target,
302 &.{
303 .{
304 .path = "optionals.zig",
305 .source =
306 \\pub fn main() void {
307 \\ {
308 \\ var null_u32: ?u32 = null;
309 \\ var maybe_u32: ?u32 = null;
310 \\ var nonnull_u32: ?u32 = 456;
311 \\ maybe_u32 = 123;
312 \\ _ = .{ &null_u32, &nonnull_u32 };
313 \\ }
314 \\}
315 \\
316 ,
317 },
318 },
319 \\breakpoint set --file optionals.zig --source-pattern-regexp 'maybe_u32 = 123;'
320 \\process launch
321 \\frame variable null_u32 maybe_u32 nonnull_u32
322 \\breakpoint delete --force 1
323 \\
324 \\breakpoint set --file optionals.zig --source-pattern-regexp '_ = .{ &null_u32, &nonnull_u32 };'
325 \\process continue
326 \\frame variable --show-types null_u32 maybe_u32 nonnull_u32
327 \\breakpoint delete --force 2
328 ,
329 &.{
330 \\(lldb) frame variable null_u32 maybe_u32 nonnull_u32
331 \\(?u32) null_u32 = null
332 \\(?u32) maybe_u32 = null
333 \\(?u32) nonnull_u32 = (nonnull_u32.? = 456)
334 \\(lldb) breakpoint delete --force 1
335 \\1 breakpoints deleted; 0 breakpoint locations disabled.
336 ,
337 \\(lldb) frame variable --show-types null_u32 maybe_u32 nonnull_u32
338 \\(?u32) null_u32 = null
339 \\(?u32) maybe_u32 = {
340 \\ (u32) maybe_u32.? = 123
341 \\}
342 \\(?u32) nonnull_u32 = {
343 \\ (u32) nonnull_u32.? = 456
344 \\}
345 \\(lldb) breakpoint delete --force 2
346 \\1 breakpoints deleted; 0 breakpoint locations disabled.
347 },
348 );
349 db.addLldbTest(
350 "cross_module_call",
351 target,
352 &.{
353 .{
354 .path = "main.zig",
355 .source =
356 \\const module = @import("module");
357 \\pub fn main() void {
358 \\ module.foo(123);
359 \\ module.bar(456);
360 \\}
361 ,
362 },
363 .{
364 .import = "module",
365 .path = "module.zig",
366 .source =
367 \\pub fn foo(x: u32) void {
368 \\ _ = x;
369 \\}
370 \\pub inline fn bar(y: u32) void {
371 \\ _ = y;
372 \\}
373 ,
374 },
375 },
376 \\breakpoint set --file module.zig --source-pattern-regexp '_ = x;'
377 \\process launch
378 \\source info
379 \\breakpoint delete --force 1
380 \\
381 \\breakpoint set --file module.zig --line 5
382 \\process continue
383 \\source info
384 \\breakpoint delete --force 2
385 ,
386 &.{
387 \\/module.zig:2:5
388 \\(lldb) breakpoint delete --force 1
389 \\1 breakpoints deleted; 0 breakpoint locations disabled.
390 ,
391 \\/module.zig:5:5
392 \\(lldb) breakpoint delete --force 2
393 \\1 breakpoints deleted; 0 breakpoint locations disabled.
394 },
395 );
396}
397
398const File = struct { import: ?[]const u8 = null, path: []const u8, source: []const u8 };
399
400fn addGdbTest(
401 db: *Debugger,
402 name: []const u8,
403 target: Target,
404 files: []const File,
405 commands: []const u8,
406 expected_output: []const []const u8,
407) void {
408 db.addTest(
409 name,
410 target,
411 files,
412 &.{
413 db.options.gdb orelse return,
414 "--batch",
415 "--command",
416 },
417 commands,
418 &.{
419 "--args",
420 },
421 expected_output,
422 );
423}
424
425fn addLldbTest(
426 db: *Debugger,
427 name: []const u8,
428 target: Target,
429 files: []const File,
430 commands: []const u8,
431 expected_output: []const []const u8,
432) void {
433 db.addTest(
434 name,
435 target,
436 files,
437 &.{
438 db.options.lldb orelse return,
439 "--batch",
440 "--source",
441 },
442 commands,
443 &.{
444 "--",
445 },
446 expected_output,
447 );
448}
449
450/// After a failure while running a script, the debugger starts accepting commands from stdin, and
451/// because it is empty, the debugger exits normally with status 0. Choose a non-zero status to
452/// return from the debugger script instead to detect it running to completion and indicate success.
453const success = 99;
454
455fn addTest(
456 db: *Debugger,
457 name: []const u8,
458 target: Target,
459 files: []const File,
460 db_argv1: []const []const u8,
461 commands: []const u8,
462 db_argv2: []const []const u8,
463 expected_output: []const []const u8,
464) void {
465 for (db.options.test_filters) |test_filter| {
466 if (std.mem.indexOf(u8, name, test_filter)) |_| return;
467 }
468 const files_wf = db.b.addWriteFiles();
469 const exe = db.b.addExecutable(.{
470 .name = name,
471 .target = target.resolved,
472 .root_source_file = files_wf.add(files[0].path, files[0].source),
473 .optimize = target.optimize_mode,
474 .link_libc = target.link_libc,
475 .single_threaded = target.single_threaded,
476 .pic = target.pic,
477 .strip = false,
478 .use_llvm = false,
479 .use_lld = false,
480 });
481 for (files[1..]) |file| {
482 const path = files_wf.add(file.path, file.source);
483 if (file.import) |import| exe.root_module.addImport(import, db.b.createModule(.{
484 .root_source_file = path,
485 }));
486 }
487 const commands_wf = db.b.addWriteFiles();
488 const run = std.Build.Step.Run.create(db.b, db.b.fmt("run {s} {s}", .{ name, target.test_name_suffix }));
489 run.addArgs(db_argv1);
490 run.addFileArg(commands_wf.add(db.b.fmt("{s}.cmd", .{name}), db.b.fmt("{s}\n\nquit {d}\n", .{ commands, success })));
491 run.addArgs(db_argv2);
492 run.addArtifactArg(exe);
493 for (expected_output) |expected| run.addCheck(.{ .expect_stdout_match = db.b.fmt("{s}\n", .{expected}) });
494 run.addCheck(.{ .expect_term = .{ .Exited = success } });
495 run.setStdIn(.{ .bytes = "" });
496 db.root_step.dependOn(&run.step);
497}
498
499const Debugger = @This();
500const std = @import("std");
test/tests.zig+34
...@@ -17,6 +17,7 @@ pub const TranslateCContext = @import("src/TranslateC.zig");...@@ -17,6 +17,7 @@ pub const TranslateCContext = @import("src/TranslateC.zig");
17pub const RunTranslatedCContext = @import("src/RunTranslatedC.zig");17pub const RunTranslatedCContext = @import("src/RunTranslatedC.zig");
18pub const CompareOutputContext = @import("src/CompareOutput.zig");18pub const CompareOutputContext = @import("src/CompareOutput.zig");
19pub const StackTracesContext = @import("src/StackTrace.zig");19pub const StackTracesContext = @import("src/StackTrace.zig");
20pub const DebuggerContext = @import("src/Debugger.zig");
2021
21const TestTarget = struct {22const TestTarget = struct {
22 target: std.Target.Query = .{},23 target: std.Target.Query = .{},
...@@ -1283,3 +1284,36 @@ pub fn addCases(...@@ -1283,3 +1284,36 @@ pub fn addCases(
1283 test_filters,1284 test_filters,
1284 );1285 );
1285}1286}
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}