1const Dwarf = @This();
2
3const std = @import("std");
4const Io = std.Io;
5const Allocator = std.mem.Allocator;
6const DW = std.dwarf;
7const Zir = std.zig.Zir;
8const assert = std.debug.assert;
9const log = std.log.scoped(.dwarf);
10const Writer = std.Io.Writer;
11
12const InternPool = @import("../InternPool.zig");
13const Module = @import("../Module.zig");
14const Type = @import("../Type.zig");
15const Value = @import("../Value.zig");
16const Zcu = @import("../Zcu.zig");
17const codegen = @import("../codegen.zig");
18const dev = @import("../dev.zig");
19const link = @import("../link.zig");
20const target_info = @import("../target.zig");
21
22gpa: Allocator,
23bin_file: *link.File,
24format: DW.Format,
25endian: std.lang.Endian,
26address_size: AddressSize,
27
28const_pool: link.ConstPool,
29
30mods: std.array_hash_map.Auto(*Module, ModInfo),
31/// Indices are `link.ConstPool.Index`.
32values: std.ArrayList(struct { Unit.Index, Entry.Index }),
33navs: std.array_hash_map.Auto(InternPool.Nav.Index, Entry.Index),
34decls: std.array_hash_map.Auto(InternPool.TrackedInst.Index, Entry.Index),
35
36debug_abbrev: DebugAbbrev,
37debug_aranges: DebugAranges,
38debug_frame: DebugFrame,
39debug_info: DebugInfo,
40debug_line: DebugLine,
41debug_line_str: StringSection,
42debug_loclists: DebugLocLists,
43debug_rnglists: DebugRngLists,
44debug_str: StringSection,
45
46pub const UpdateError = error{
47 WriteFailed,
48 ReinterpretDeclRef,
49 Unimplemented,
50 EndOfStream,
51 Underflow,
52 UnexpectedEndOfFile,
53 NonResizable,
54 Overflow,
55} ||
56 link.Error ||
57 Io.File.OpenError ||
58 Io.File.LengthError ||
59 Io.File.ReadPositionalError ||
60 Io.File.WritePositionalError;
61
62pub const RelocError = Io.File.PWriteError;
63
64pub const AddressSize = enum(u8) {
65 @"32" = 4,
66 @"64" = 8,
67 _,
68};
69
70const ModInfo = struct {
71 root_dir_path: Entry.Index,
72 dirs: std.array_hash_map.Auto(Unit.Index, void),
73 files: std.array_hash_map.Auto(Zcu.File.Index, void),
74
75 fn deinit(mod_info: *ModInfo, gpa: Allocator) void {
76 mod_info.dirs.deinit(gpa);
77 mod_info.files.deinit(gpa);
78 mod_info.* = undefined;
79 }
80};
81
82const DebugAbbrev = struct {
83 section: Section,
84 const unit: Unit.Index = @fromBackingInt(@intCast(0));
85
86 const header_bytes = 0;
87
88 const trailer_bytes = uleb128Bytes(@backingInt(AbbrevCode.null));
89};
90
91const DebugAranges = struct {
92 section: Section,
93
94 fn headerBytes(dwarf: *Dwarf) u32 {
95 return dwarf.unitLengthBytes() + 2 + dwarf.sectionOffsetBytes() + 1 + 1;
96 }
97
98 fn trailerBytes(dwarf: *Dwarf) u32 {
99 return @backingInt(dwarf.address_size) * 2;
100 }
101};
102
103const DebugFrame = struct {
104 header: Header,
105 section: Section,
106
107 const Format = enum { none, debug_frame, eh_frame };
108 const Header = struct {
109 format: Format,
110 code_alignment_factor: u32,
111 data_alignment_factor: i32,
112 return_address_register: u32,
113 initial_instructions: []const Cfa,
114 };
115
116 fn headerBytes(dwarf: *Dwarf) u32 {
117 const target = &dwarf.bin_file.comp.root_mod.resolved_target.result;
118 return @intCast(switch (dwarf.debug_frame.header.format) {
119 .none => return 0,
120 .debug_frame => dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() + 1 + "\x00".len + 1 + 1,
121 .eh_frame => dwarf.unitLengthBytes() + 4 + 1 + "zR\x00".len +
122 uleb128Bytes(1) + 1,
123 } + switch (target.cpu.arch) {
124 .x86_64 => len: {
125 dev.check(.x86_64_backend);
126 const Register = @import("../codegen/x86_64/bits.zig").Register;
127 break :len uleb128Bytes(1) + sleb128Bytes(-8) + uleb128Bytes(Register.rip.dwarfNum()) +
128 1 + uleb128Bytes(Register.rsp.dwarfNum()) + sleb128Bytes(-1) +
129 1 + uleb128Bytes(1);
130 },
131 else => unreachable,
132 });
133 }
134
135 fn trailerBytes(dwarf: *Dwarf) u32 {
136 return @intCast(switch (dwarf.debug_frame.header.format) {
137 .none => 0,
138 .debug_frame => dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() + 1 + "\x00".len + 1 + 1 + uleb128Bytes(1) + sleb128Bytes(1) + uleb128Bytes(0),
139 .eh_frame => dwarf.unitLengthBytes() + 4 + 1 + "\x00".len + uleb128Bytes(1) + sleb128Bytes(1) + uleb128Bytes(0),
140 });
141 }
142};
143
144const DebugInfo = struct {
145 section: Section,
146
147 fn headerBytes(dwarf: *Dwarf) u32 {
148 return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() +
149 uleb128Bytes(@backingInt(AbbrevCode.compile_unit)) + 1 + dwarf.sectionOffsetBytes() * 6 + uleb128Bytes(0) +
150 uleb128Bytes(@backingInt(AbbrevCode.module)) + dwarf.sectionOffsetBytes() + uleb128Bytes(0);
151 }
152
153 fn declEntryLineOff(dwarf: *Dwarf) u32 {
154 return AbbrevCode.decl_bytes + dwarf.sectionOffsetBytes();
155 }
156
157 fn declAbbrevCode(debug_info: *DebugInfo, unit: Unit.Index, entry: Entry.Index) !AbbrevCode {
158 const dwarf: *Dwarf = @fieldParentPtr("debug_info", debug_info);
159 const comp = dwarf.bin_file.comp;
160 const io = comp.io;
161 const unit_ptr = debug_info.section.getUnit(unit);
162 const entry_ptr = unit_ptr.getEntry(entry);
163 if (entry_ptr.len < AbbrevCode.decl_bytes) return .null;
164 var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined;
165 if (try dwarf.getFile().?.readPositionalAll(
166 io,
167 &abbrev_code_buf,
168 debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off,
169 ) != abbrev_code_buf.len) return error.InputOutput;
170 var abbrev_code_reader: std.Io.Reader = .fixed(&abbrev_code_buf);
171 return @fromBackingInt(@intCast(
172 abbrev_code_reader.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable,
173 ));
174 }
175
176 const trailer_bytes = 1 + 1;
177};
178
179const DebugLine = struct {
180 header: Header,
181 section: Section,
182
183 const Header = struct {
184 minimum_instruction_length: u8,
185 maximum_operations_per_instruction: u8,
186 default_is_stmt: bool,
187 line_base: i8,
188 line_range: u8,
189 opcode_base: u8,
190 };
191
192 fn dirIndexInfo(dir_count: u32) struct { bytes: u8, form: DeclValEnum(DW.FORM) } {
193 return if (dir_count <= 1 << 8)
194 .{ .bytes = 1, .form = .data1 }
195 else if (dir_count <= 1 << 16)
196 .{ .bytes = 2, .form = .data2 }
197 else
198 unreachable;
199 }
200
201 fn headerBytes(dwarf: *Dwarf, dir_count: u32, file_count: u32) u32 {
202 const dir_index_info = dirIndexInfo(dir_count);
203 return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() + 1 + 1 + 1 + 1 + 1 + 1 + 1 * (dwarf.debug_line.header.opcode_base - 1) +
204 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(dir_count) + (dwarf.sectionOffsetBytes()) * dir_count +
205 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(DW.LNCT.directory_index) + uleb128Bytes(@backingInt(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;
206 }
207
208 const trailer_bytes = 1 + uleb128Bytes(1) + 1;
209};
210
211const DebugLocLists = struct {
212 section: Section,
213
214 fn baseOffset(dwarf: *Dwarf) u32 {
215 return dwarf.unitLengthBytes() + 2 + 1 + 1 + 4;
216 }
217
218 fn headerBytes(dwarf: *Dwarf) u32 {
219 return baseOffset(dwarf);
220 }
221
222 const trailer_bytes = 0;
223};
224
225const DebugRngLists = struct {
226 section: Section,
227
228 const baseOffset = DebugLocLists.baseOffset;
229
230 fn headerBytes(dwarf: *Dwarf) u32 {
231 return baseOffset(dwarf) + dwarf.sectionOffsetBytes() * 1;
232 }
233
234 const trailer_bytes = 1;
235};
236
237const StringSection = struct {
238 contents: std.ArrayList(u8),
239 map: std.array_hash_map.Auto(void, void),
240 section: Section,
241
242 const unit: Unit.Index = @fromBackingInt(@intCast(0));
243
244 const init: StringSection = .{
245 .contents = .empty,
246 .map = .empty,
247 .section = Section.init,
248 };
249
250 fn deinit(str_sec: *StringSection, gpa: Allocator) void {
251 str_sec.contents.deinit(gpa);
252 str_sec.map.deinit(gpa);
253 str_sec.section.deinit(gpa);
254 }
255
256 fn addString(str_sec: *StringSection, dwarf: *Dwarf, str: []const u8) UpdateError!Entry.Index {
257 const gop = try str_sec.map.getOrPutAdapted(dwarf.gpa, str, Adapter{ .str_sec = str_sec });
258 const entry: Entry.Index = @fromBackingInt(@intCast(gop.index));
259 if (!gop.found_existing) {
260 errdefer _ = str_sec.map.pop();
261 const unit_ptr = str_sec.section.getUnit(unit);
262 assert(try str_sec.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
263 errdefer _ = unit_ptr.entries.pop();
264 const entry_ptr = unit_ptr.getEntry(entry);
265 if (unit_ptr.last.unwrap()) |last_entry|
266 unit_ptr.getEntry(last_entry).next = entry.toOptional();
267 entry_ptr.prev = unit_ptr.last;
268 unit_ptr.last = entry.toOptional();
269 entry_ptr.off = @intCast(str_sec.contents.items.len);
270 entry_ptr.len = @intCast(str.len + 1);
271 try str_sec.contents.ensureUnusedCapacity(dwarf.gpa, str.len + 1);
272 str_sec.contents.appendSliceAssumeCapacity(str);
273 str_sec.contents.appendAssumeCapacity(0);
274 str_sec.section.dirty = true;
275 }
276 return entry;
277 }
278
279 const Adapter = struct {
280 str_sec: *StringSection,
281
282 pub fn hash(_: Adapter, key: []const u8) u32 {
283 return @truncate(std.hash.Wyhash.hash(0, key));
284 }
285
286 pub fn eql(adapter: Adapter, key: []const u8, _: void, rhs_index: usize) bool {
287 const entry = adapter.str_sec.section.getUnit(unit).getEntry(@fromBackingInt(@intCast(rhs_index)));
288 return std.mem.eql(u8, key, adapter.str_sec.contents.items[entry.off..][0 .. entry.len - 1 :0]);
289 }
290 };
291};
292
293/// A linker section containing a sequence of `Unit`s.
294pub const Section = struct {
295 dirty: bool,
296 pad_entries_to_ideal: bool,
297 alignment: InternPool.Alignment,
298 index: u32,
299 first: Unit.Index.Optional,
300 last: Unit.Index.Optional,
301 len: u64,
302 units: std.ArrayList(Unit),
303
304 pub const Index = enum {
305 debug_abbrev,
306 debug_aranges,
307 debug_frame,
308 debug_info,
309 debug_line,
310 debug_line_str,
311 debug_loclists,
312 debug_rnglists,
313 debug_str,
314 };
315
316 const init: Section = .{
317 .dirty = true,
318 .pad_entries_to_ideal = true,
319 .alignment = .@"1",
320 .index = std.math.maxInt(u32),
321 .first = .none,
322 .last = .none,
323 .units = .empty,
324 .len = 0,
325 };
326
327 fn deinit(sec: *Section, gpa: Allocator) void {
328 for (sec.units.items) |*unit| unit.deinit(gpa);
329 sec.units.deinit(gpa);
330 sec.* = undefined;
331 }
332
333 fn off(sec: Section, dwarf: *Dwarf) u64 {
334 if (dwarf.bin_file.cast(.elf)) |elf_file| {
335 const zo = elf_file.zigObjectPtr().?;
336 const atom = zo.symbol(sec.index).atom(elf_file).?;
337 return atom.offset(elf_file);
338 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
339 const header = if (macho_file.d_sym) |d_sym|
340 d_sym.sections.items[sec.index]
341 else
342 macho_file.sections.items(.header)[sec.index];
343 return header.offset;
344 } else unreachable;
345 }
346
347 fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index {
348 const unit: Unit.Index = @fromBackingInt(@intCast(sec.units.items.len));
349 const unit_ptr = try sec.units.addOne(dwarf.gpa);
350 errdefer sec.popUnit(dwarf.gpa);
351 const aligned_header_len: u32 = @intCast(sec.alignment.forward(header_len));
352 const aligned_trailer_len: u32 = @intCast(sec.alignment.forward(trailer_len));
353 unit_ptr.* = .{
354 .prev = sec.last,
355 .next = .none,
356 .first = .none,
357 .last = .none,
358 .free = .none,
359 .header_len = aligned_header_len,
360 .trailer_len = aligned_trailer_len,
361 .off = 0,
362 .len = aligned_header_len + aligned_trailer_len,
363 .entries = .empty,
364 .cross_unit_relocs = .empty,
365 .cross_section_relocs = .empty,
366 };
367 if (sec.last.unwrap()) |last_unit| {
368 const last_unit_ptr = sec.getUnit(last_unit);
369 last_unit_ptr.next = unit.toOptional();
370 unit_ptr.off = last_unit_ptr.off + sec.padUnitToIdeal(last_unit_ptr.len);
371 }
372 if (sec.first == .none)
373 sec.first = unit.toOptional();
374 sec.last = unit.toOptional();
375 try sec.resize(dwarf, unit_ptr.off + sec.padUnitToIdeal(unit_ptr.len));
376 return unit;
377 }
378
379 fn unlinkUnit(sec: *Section, unit: Unit.Index) void {
380 const unit_ptr = sec.getUnit(unit);
381 if (unit_ptr.prev.unwrap()) |prev_unit| sec.getUnit(prev_unit).next = unit_ptr.next;
382 if (unit_ptr.next.unwrap()) |next_unit| sec.getUnit(next_unit).prev = unit_ptr.prev;
383 if (sec.first == unit.toOptional()) sec.first = unit_ptr.next;
384 if (sec.last == unit.toOptional()) sec.last = unit_ptr.prev;
385 }
386
387 fn popUnit(sec: *Section, gpa: Allocator) void {
388 const unit_index: Unit.Index = @fromBackingInt(@intCast(sec.units.items.len - 1));
389 sec.unlinkUnit(unit_index);
390 var unit = sec.units.pop().?;
391 unit.deinit(gpa);
392 }
393
394 pub fn getUnit(sec: *Section, unit: Unit.Index) *Unit {
395 return &sec.units.items[@backingInt(unit)];
396 }
397
398 fn resizeEntry(
399 sec: *Section,
400 unit: Unit.Index,
401 entry: Entry.Index,
402 dwarf: *Dwarf,
403 len: u32,
404 ) (UpdateError || Writer.Error)!void {
405 const unit_ptr = sec.getUnit(unit);
406 const entry_ptr = unit_ptr.getEntry(entry);
407 if (len > 0) {
408 if (entry_ptr.len == 0) {
409 assert(entry_ptr.prev == .none and entry_ptr.next == .none);
410 entry_ptr.off = if (unit_ptr.last.unwrap()) |last_entry| off: {
411 const last_entry_ptr = unit_ptr.getEntry(last_entry);
412 last_entry_ptr.next = entry.toOptional();
413 break :off last_entry_ptr.off + sec.padEntryToIdeal(last_entry_ptr.len);
414 } else 0;
415 entry_ptr.prev = unit_ptr.last;
416 unit_ptr.last = entry.toOptional();
417 if (unit_ptr.first == .none) unit_ptr.first = unit_ptr.last;
418 if (entry_ptr.prev.unwrap()) |prev_entry| try unit_ptr.getEntry(prev_entry).pad(unit_ptr, sec, dwarf);
419 }
420 try entry_ptr.resize(unit_ptr, sec, dwarf, len);
421 }
422 assert(entry_ptr.len == len);
423 }
424
425 fn replaceEntry(
426 sec: *Section,
427 unit: Unit.Index,
428 entry: Entry.Index,
429 dwarf: *Dwarf,
430 contents: []const u8,
431 ) (UpdateError || Writer.Error)!void {
432 try sec.resizeEntry(unit, entry, dwarf, @intCast(contents.len));
433 const unit_ptr = sec.getUnit(unit);
434 try unit_ptr.getEntry(entry).replace(unit_ptr, sec, dwarf, contents);
435 }
436
437 fn freeEntry(
438 sec: *Section,
439 unit: Unit.Index,
440 entry: Entry.Index,
441 dwarf: *Dwarf,
442 ) (UpdateError || Writer.Error)!void {
443 const unit_ptr = sec.getUnit(unit);
444 const entry_ptr = unit_ptr.getEntry(entry);
445 if (entry_ptr.len > 0) {
446 if (entry_ptr.next.unwrap()) |next_entry| unit_ptr.getEntry(next_entry).prev = entry_ptr.prev;
447 if (entry_ptr.prev.unwrap()) |prev_entry| {
448 const prev_entry_ptr = unit_ptr.getEntry(prev_entry);
449 prev_entry_ptr.next = entry_ptr.next;
450 try prev_entry_ptr.pad(unit_ptr, sec, dwarf);
451 } else {
452 unit_ptr.trim();
453 sec.trim(dwarf);
454 }
455 } else assert(entry_ptr.prev == .none and entry_ptr.next == .none);
456 entry_ptr.prev = .none;
457 entry_ptr.next = unit_ptr.free;
458 entry_ptr.off = 0;
459 entry_ptr.len = 0;
460 entry_ptr.clear();
461 unit_ptr.free = entry.toOptional();
462 }
463
464 fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {
465 if (len <= sec.len) return;
466 if (dwarf.bin_file.cast(.elf)) |elf_file| {
467 const zo = elf_file.zigObjectPtr().?;
468 const atom = zo.symbol(sec.index).atom(elf_file).?;
469 atom.size = len;
470 atom.alignment = sec.alignment;
471 sec.len = len;
472 try zo.allocateAtom(atom, false, elf_file);
473 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
474 const header = if (macho_file.d_sym) |*d_sym| header: {
475 try d_sym.growSection(@intCast(sec.index), len, true, macho_file);
476 break :header &d_sym.sections.items[sec.index];
477 } else header: {
478 try macho_file.growSection(@intCast(sec.index), len);
479 break :header &macho_file.sections.items(.header)[sec.index];
480 };
481 sec.len = header.size;
482 }
483 }
484
485 fn trim(sec: *Section, dwarf: *Dwarf) void {
486 const len = sec.getUnit(sec.first.unwrap() orelse return).off;
487 if (len == 0) return;
488 for (sec.units.items) |*unit| unit.off -= len;
489 sec.len -= len;
490 if (dwarf.bin_file.cast(.elf)) |elf_file| {
491 const zo = elf_file.zigObjectPtr().?;
492 const atom = zo.symbol(sec.index).atom(elf_file).?;
493 if (atom.prevAtom(elf_file)) |_| {
494 atom.value += len;
495 } else {
496 const shdr = &elf_file.sections.items(.shdr)[atom.output_section_index];
497 shdr.sh_offset += len;
498 shdr.sh_size -= len;
499 atom.value = 0;
500 }
501 atom.size -= len;
502 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
503 const header = if (macho_file.d_sym) |*d_sym|
504 &d_sym.sections.items[sec.index]
505 else
506 &macho_file.sections.items(.header)[sec.index];
507 header.offset += @intCast(len);
508 header.size -= len;
509 }
510 }
511
512 fn resolveRelocs(sec: *Section, dwarf: *Dwarf) RelocError!void {
513 for (sec.units.items) |*unit| try unit.resolveRelocs(sec, dwarf);
514 }
515
516 fn padUnitToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) {
517 return @intCast(sec.alignment.forward(Dwarf.padToIdeal(actual_size)));
518 }
519
520 fn padEntryToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) {
521 return @intCast(sec.alignment.forward(if (sec.pad_entries_to_ideal) Dwarf.padToIdeal(actual_size) else actual_size));
522 }
523};
524
525/// A unit within a `Section` containing a sequence of `Entry`s.
526const Unit = struct {
527 prev: Index.Optional,
528 next: Index.Optional,
529 first: Entry.Index.Optional,
530 last: Entry.Index.Optional,
531 free: Entry.Index.Optional,
532 /// offset within containing section
533 off: u32,
534 header_len: u32,
535 trailer_len: u32,
536 /// data length in bytes
537 len: u32,
538 entries: std.ArrayList(Entry),
539 cross_unit_relocs: std.ArrayList(CrossUnitReloc),
540 cross_section_relocs: std.ArrayList(CrossSectionReloc),
541
542 const Index = enum(u32) {
543 main,
544 _,
545
546 const Optional = enum(u32) {
547 none = std.math.maxInt(u32),
548 _,
549
550 pub fn unwrap(uio: Optional) ?Index {
551 return if (uio != .none) @fromBackingInt(@intCast(@backingInt(uio))) else null;
552 }
553 };
554
555 fn toOptional(ui: Index) Optional {
556 return @fromBackingInt(@intCast(@backingInt(ui)));
557 }
558 };
559
560 fn clear(unit: *Unit) void {
561 unit.cross_unit_relocs.clearRetainingCapacity();
562 unit.cross_section_relocs.clearRetainingCapacity();
563 }
564
565 fn deinit(unit: *Unit, gpa: Allocator) void {
566 for (unit.entries.items) |*entry| entry.deinit(gpa);
567 unit.entries.deinit(gpa);
568 unit.cross_unit_relocs.deinit(gpa);
569 unit.cross_section_relocs.deinit(gpa);
570 unit.* = undefined;
571 }
572
573 fn addEntry(unit: *Unit, gpa: Allocator) Allocator.Error!Entry.Index {
574 if (unit.free.unwrap()) |entry| {
575 const entry_ptr = unit.getEntry(entry);
576 unit.free = entry_ptr.next;
577 entry_ptr.next = .none;
578 return entry;
579 }
580 const entry: Entry.Index = @fromBackingInt(@intCast(unit.entries.items.len));
581 const entry_ptr = try unit.entries.addOne(gpa);
582 entry_ptr.* = .{
583 .prev = .none,
584 .next = .none,
585 .off = 0,
586 .len = 0,
587 .cross_entry_relocs = .empty,
588 .cross_unit_relocs = .empty,
589 .cross_section_relocs = .empty,
590 .external_relocs = .empty,
591 };
592 return entry;
593 }
594
595 pub fn getEntry(unit: *Unit, entry: Entry.Index) *Entry {
596 return &unit.entries.items[@backingInt(entry)];
597 }
598
599 fn resize(unit_ptr: *Unit, sec: *Section, dwarf: *Dwarf, extra_header_len: u32, len: u32) UpdateError!void {
600 const end = if (unit_ptr.next.unwrap()) |next_unit|
601 sec.getUnit(next_unit).off
602 else
603 sec.len;
604 if (extra_header_len > 0 or unit_ptr.off + len > end) {
605 unit_ptr.len = @min(unit_ptr.len, len);
606 var new_off = unit_ptr.off;
607 if (unit_ptr.next.unwrap()) |next_unit| {
608 const next_unit_ptr = sec.getUnit(next_unit);
609 if (unit_ptr.prev.unwrap()) |prev_unit|
610 sec.getUnit(prev_unit).next = unit_ptr.next
611 else
612 sec.first = unit_ptr.next;
613 const unit = next_unit_ptr.prev;
614 next_unit_ptr.prev = unit_ptr.prev;
615 const last_unit_ptr = sec.getUnit(sec.last.unwrap().?);
616 last_unit_ptr.next = unit;
617 unit_ptr.prev = sec.last;
618 unit_ptr.next = .none;
619 new_off = last_unit_ptr.off + sec.padUnitToIdeal(last_unit_ptr.len);
620 sec.last = unit;
621 sec.dirty = true;
622 } else if (extra_header_len > 0) {
623 // `copyRangeAll` in `move` does not support overlapping ranges
624 // so make sure new location is disjoint from current location.
625 new_off += unit_ptr.len -| extra_header_len;
626 }
627 try sec.resize(dwarf, new_off + len);
628 try unit_ptr.move(sec, dwarf, new_off + extra_header_len);
629 unit_ptr.off -= extra_header_len;
630 unit_ptr.header_len += extra_header_len;
631 sec.trim(dwarf);
632 }
633 unit_ptr.len = len;
634 }
635
636 fn trim(unit: *Unit) void {
637 const len = unit.getEntry(unit.first.unwrap() orelse return).off;
638 if (len == 0) return;
639 for (unit.entries.items) |*entry| entry.off -= len;
640 unit.off += len;
641 unit.len -= len;
642 }
643
644 fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {
645 if (unit.off == new_off) return;
646 const comp = dwarf.bin_file.comp;
647 const io = comp.io;
648 const file = dwarf.getFile().?;
649 try link.File.copyRangeAll2(io, file, file, sec.off(dwarf) + unit.off, sec.off(dwarf) + new_off, unit.len);
650 unit.off = new_off;
651 }
652
653 fn resizeHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void {
654 unit.trim();
655 if (unit.header_len == len) return;
656 const available_len = if (unit.prev.unwrap()) |prev_unit| prev_excess: {
657 const prev_unit_ptr = sec.getUnit(prev_unit);
658 break :prev_excess unit.off - prev_unit_ptr.off - prev_unit_ptr.len;
659 } else 0;
660 if (available_len + unit.header_len < len)
661 try unit.resize(sec, dwarf, len - unit.header_len, unit.len - unit.header_len + len);
662 if (unit.header_len > len) {
663 const excess_header_len = unit.header_len - len;
664 unit.off += excess_header_len;
665 unit.header_len -= excess_header_len;
666 unit.len -= excess_header_len;
667 } else if (unit.header_len < len) {
668 const needed_header_len = len - unit.header_len;
669 unit.off -= needed_header_len;
670 unit.header_len += needed_header_len;
671 unit.len += needed_header_len;
672 }
673 assert(unit.header_len == len);
674 sec.trim(dwarf);
675 }
676
677 fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
678 assert(contents.len == unit.header_len);
679 const comp = dwarf.bin_file.comp;
680 const io = comp.io;
681 try dwarf.getFile().?.writePositionalAll(io, contents, sec.off(dwarf) + unit.off);
682 }
683
684 fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
685 const comp = dwarf.bin_file.comp;
686 const io = comp.io;
687 const start = unit.off + unit.header_len + if (unit.last.unwrap()) |last_entry| end: {
688 const last_entry_ptr = unit.getEntry(last_entry);
689 break :end last_entry_ptr.off + last_entry_ptr.len;
690 } else 0;
691 const end = if (unit.next.unwrap()) |next_unit| sec.getUnit(next_unit).off else sec.len;
692 const len: usize = @intCast(end - start);
693 assert(len >= unit.trailer_len);
694 if (sec == &dwarf.debug_line.section) {
695 var buf: [1 + uleb128Bytes(std.math.maxInt(u32)) + 1]u8 = undefined;
696 var fw: Writer = .fixed(&buf);
697 fw.writeByte(DW.LNS.extended_op) catch unreachable;
698 const extended_op_bytes = fw.end;
699 var op_len_bytes: u5 = 1;
700 while (true) switch (std.math.order(len - extended_op_bytes - op_len_bytes, @as(u32, 1) << 7 * op_len_bytes)) {
701 .lt => break fw.writeUleb128(len - extended_op_bytes - op_len_bytes) catch unreachable,
702 .eq => {
703 // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
704 op_len_bytes += 1;
705 std.leb.writeUnsignedExtended(
706 fw.writableSlice(op_len_bytes) catch unreachable,
707 len - extended_op_bytes - op_len_bytes,
708 );
709 break;
710 },
711 .gt => op_len_bytes += 1,
712 };
713 assert(fw.end == extended_op_bytes + op_len_bytes);
714 fw.writeByte(DW.LNE.padding) catch unreachable;
715 assert(fw.end >= unit.trailer_len and fw.end <= len);
716 return dwarf.getFile().?.writePositionalAll(io, fw.buffered(), sec.off(dwarf) + start);
717 }
718 var trailer_aw: Writer.Allocating = try .initCapacity(dwarf.gpa, len);
719 defer trailer_aw.deinit();
720 const tw = &trailer_aw.writer;
721 const fill_byte: u8 = if (sec == &dwarf.debug_abbrev.section) fill: {
722 tw.writeUleb128(@backingInt(AbbrevCode.null)) catch unreachable;
723 assert(uleb128Bytes(@backingInt(AbbrevCode.null)) == 1);
724 break :fill @backingInt(AbbrevCode.null);
725 } else if (sec == &dwarf.debug_aranges.section) fill: {
726 tw.splatByteAll(0, @backingInt(dwarf.address_size) * 2) catch unreachable;
727 break :fill 0;
728 } else if (sec == &dwarf.debug_frame.section) fill: {
729 switch (dwarf.debug_frame.header.format) {
730 .none => {},
731 .debug_frame, .eh_frame => |format| {
732 const unit_len = len - dwarf.unitLengthBytes();
733 switch (dwarf.format) {
734 .@"32" => tw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
735 .@"64" => {
736 tw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
737 tw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
738 },
739 }
740 switch (format) {
741 .none => unreachable,
742 .debug_frame => {
743 switch (dwarf.format) {
744 .@"32" => tw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable,
745 .@"64" => tw.writeInt(u64, std.math.maxInt(u64), dwarf.endian) catch unreachable,
746 }
747 tw.writeByte(4) catch unreachable;
748 tw.writeAll("\x00") catch unreachable;
749 tw.writeByte(@backingInt(dwarf.address_size)) catch unreachable;
750 tw.writeByte(0) catch unreachable;
751 },
752 .eh_frame => {
753 tw.writeInt(u32, 0, dwarf.endian) catch unreachable;
754 tw.writeByte(1) catch unreachable;
755 tw.writeAll("\x00") catch unreachable;
756 },
757 }
758 tw.writeUleb128(1) catch unreachable;
759 tw.writeSleb128(1) catch unreachable;
760 tw.writeUleb128(0) catch unreachable;
761 },
762 }
763 tw.splatByteAll(DW.CFA.nop, unit.trailer_len - tw.end) catch unreachable;
764 break :fill DW.CFA.nop;
765 } else if (sec == &dwarf.debug_info.section) fill: {
766 for (0..2) |_| tw.writeUleb128(@backingInt(AbbrevCode.null)) catch unreachable;
767 assert(uleb128Bytes(@backingInt(AbbrevCode.null)) == 1);
768 break :fill @backingInt(AbbrevCode.null);
769 } else if (sec == &dwarf.debug_rnglists.section) fill: {
770 tw.writeByte(DW.RLE.end_of_list) catch unreachable;
771 break :fill DW.RLE.end_of_list;
772 } else unreachable;
773 assert(tw.end == unit.trailer_len);
774 tw.splatByteAll(fill_byte, len - unit.trailer_len) catch unreachable;
775 assert(tw.end == len);
776 try dwarf.getFile().?.writePositionalAll(io, trailer_aw.written(), sec.off(dwarf) + start);
777 }
778
779 fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {
780 const unit_off = sec.off(dwarf) + unit.off;
781 for (unit.cross_unit_relocs.items) |reloc| {
782 const target_unit = sec.getUnit(reloc.target_unit);
783 try dwarf.resolveReloc(
784 unit_off + reloc.source_off,
785 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
786 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(target_unit, sec, dwarf).off
787 else
788 0) + reloc.target_off,
789 dwarf.sectionOffsetBytes(),
790 );
791 }
792 for (unit.cross_section_relocs.items) |reloc| {
793 const target_sec = switch (reloc.target_sec) {
794 inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section,
795 };
796 const target_unit = target_sec.getUnit(reloc.target_unit);
797 try dwarf.resolveReloc(
798 unit_off + reloc.source_off,
799 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
800 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(target_unit, sec, dwarf).off
801 else
802 0) + reloc.target_off,
803 dwarf.sectionOffsetBytes(),
804 );
805 }
806 for (unit.entries.items) |*entry| try entry.resolveRelocs(unit, sec, dwarf);
807 }
808};
809
810/// An indivisible entry within a `Unit` containing section-specific data.
811const Entry = struct {
812 prev: Index.Optional,
813 next: Index.Optional,
814 /// offset from end of containing unit header
815 off: u32,
816 /// data length in bytes
817 len: u32,
818 cross_entry_relocs: std.ArrayList(CrossEntryReloc),
819 cross_unit_relocs: std.ArrayList(CrossUnitReloc),
820 cross_section_relocs: std.ArrayList(CrossSectionReloc),
821 external_relocs: std.ArrayList(ExternalReloc),
822
823 fn clear(entry: *Entry) void {
824 entry.cross_entry_relocs.clearRetainingCapacity();
825 entry.cross_unit_relocs.clearRetainingCapacity();
826 entry.cross_section_relocs.clearRetainingCapacity();
827 entry.external_relocs.clearRetainingCapacity();
828 }
829
830 fn deinit(entry: *Entry, gpa: Allocator) void {
831 entry.cross_entry_relocs.deinit(gpa);
832 entry.cross_unit_relocs.deinit(gpa);
833 entry.cross_section_relocs.deinit(gpa);
834 entry.external_relocs.deinit(gpa);
835 entry.* = undefined;
836 }
837
838 const Index = enum(u32) {
839 _,
840
841 const Optional = enum(u32) {
842 none = std.math.maxInt(u32),
843 _,
844
845 pub fn unwrap(eio: Optional) ?Index {
846 return if (eio != .none) @fromBackingInt(@intCast(@backingInt(eio))) else null;
847 }
848 };
849
850 fn toOptional(ei: Index) Optional {
851 return @fromBackingInt(@intCast(@backingInt(ei)));
852 }
853 };
854
855 fn pad(
856 entry: *Entry,
857 unit: *Unit,
858 sec: *Section,
859 dwarf: *Dwarf,
860 ) (UpdateError || Writer.Error)!void {
861 assert(entry.len > 0);
862 const comp = dwarf.bin_file.comp;
863 const io = comp.io;
864 const start = entry.off + entry.len;
865 if (sec == &dwarf.debug_frame.section) {
866 const len = if (entry.next.unwrap()) |next_entry|
867 unit.getEntry(next_entry).off - entry.off
868 else
869 entry.len;
870 var unit_len_buf: [8]u8 = undefined;
871 const unit_len_bytes = unit_len_buf[0..dwarf.sectionOffsetBytes()];
872 dwarf.writeInt(unit_len_bytes, len - dwarf.unitLengthBytes());
873 try dwarf.getFile().?.writePositionalAll(io, unit_len_bytes, sec.off(dwarf) + unit.off + unit.header_len + entry.off);
874 const buf = try dwarf.gpa.alloc(u8, len - entry.len);
875 defer dwarf.gpa.free(buf);
876 @memset(buf, DW.CFA.nop);
877 try dwarf.getFile().?.writePositionalAll(io, buf, sec.off(dwarf) + unit.off + unit.header_len + start);
878 return;
879 }
880 const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;
881 var buf: [
882 @max(
883 uleb128Bytes(@backingInt(AbbrevCode.pad_1)),
884 uleb128Bytes(@backingInt(AbbrevCode.pad_n)) + uleb128Bytes(std.math.maxInt(u32)),
885 1 + uleb128Bytes(std.math.maxInt(u32)) + 1,
886 )
887 ]u8 = undefined;
888 var fw: Writer = .fixed(&buf);
889 if (sec == &dwarf.debug_info.section) switch (len) {
890 0 => {},
891 1 => fw.writeUleb128(try dwarf.refAbbrevCode(.pad_1)) catch unreachable,
892 else => {
893 fw.writeUleb128(try dwarf.refAbbrevCode(.pad_n)) catch unreachable;
894 const abbrev_code_bytes = fw.end;
895 var block_len_bytes: u5 = 1;
896 while (true) switch (std.math.order(len - abbrev_code_bytes - block_len_bytes, @as(u32, 1) << 7 * block_len_bytes)) {
897 .lt => break fw.writeUleb128(len - abbrev_code_bytes - block_len_bytes) catch unreachable,
898 .eq => {
899 // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
900 block_len_bytes += 1;
901 std.leb.writeUnsignedExtended(
902 fw.writableSlice(block_len_bytes) catch unreachable,
903 len - abbrev_code_bytes - block_len_bytes,
904 );
905 break;
906 },
907 .gt => block_len_bytes += 1,
908 };
909 assert(fw.end == abbrev_code_bytes + block_len_bytes);
910 },
911 } else if (sec == &dwarf.debug_line.section) switch (len) {
912 0 => {},
913 1 => fw.writeByte(DW.LNS.const_add_pc) catch unreachable,
914 else => {
915 fw.writeByte(DW.LNS.extended_op) catch unreachable;
916 const extended_op_bytes = fw.end;
917 var op_len_bytes: u5 = 1;
918 while (true) switch (std.math.order(len - extended_op_bytes - op_len_bytes, @as(u32, 1) << 7 * op_len_bytes)) {
919 .lt => break fw.writeUleb128(len - extended_op_bytes - op_len_bytes) catch unreachable,
920 .eq => {
921 // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
922 op_len_bytes += 1;
923 std.leb.writeUnsignedExtended(
924 fw.writableSlice(op_len_bytes) catch unreachable,
925 len - extended_op_bytes - op_len_bytes,
926 );
927 break;
928 },
929 .gt => op_len_bytes += 1,
930 };
931 assert(fw.end == extended_op_bytes + op_len_bytes);
932 if (len > 2) fw.writeByte(DW.LNE.padding) catch unreachable;
933 },
934 } else assert(!sec.pad_entries_to_ideal and len == 0);
935 assert(fw.end <= len);
936 try dwarf.getFile().?.writePositionalAll(io, fw.buffered(), sec.off(dwarf) + unit.off + unit.header_len + start);
937 }
938
939 fn resize(
940 entry_ptr: *Entry,
941 unit: *Unit,
942 sec: *Section,
943 dwarf: *Dwarf,
944 len: u32,
945 ) (UpdateError || Writer.Error)!void {
946 assert(len > 0);
947 assert(sec.alignment.check(len));
948 if (entry_ptr.len == len) return;
949 const end = if (entry_ptr.next.unwrap()) |next_entry|
950 unit.getEntry(next_entry).off
951 else
952 unit.len -| (unit.header_len + unit.trailer_len);
953 if (entry_ptr.off + len > end) {
954 if (entry_ptr.next.unwrap()) |next_entry| {
955 if (entry_ptr.prev.unwrap()) |prev_entry| {
956 const prev_entry_ptr = unit.getEntry(prev_entry);
957 prev_entry_ptr.next = entry_ptr.next;
958 try prev_entry_ptr.pad(unit, sec, dwarf);
959 } else unit.first = entry_ptr.next;
960 const next_entry_ptr = unit.getEntry(next_entry);
961 const entry = next_entry_ptr.prev;
962 next_entry_ptr.prev = entry_ptr.prev;
963 const last_entry_ptr = unit.getEntry(unit.last.unwrap().?);
964 last_entry_ptr.next = entry;
965 entry_ptr.prev = unit.last;
966 entry_ptr.next = .none;
967 entry_ptr.off = last_entry_ptr.off + sec.padEntryToIdeal(last_entry_ptr.len);
968 unit.last = entry;
969 try last_entry_ptr.pad(unit, sec, dwarf);
970 }
971 try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padEntryToIdeal(len) + unit.trailer_len));
972 }
973 entry_ptr.len = len;
974 try entry_ptr.pad(unit, sec, dwarf);
975 }
976
977 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
978 assert(contents.len == entry_ptr.len);
979 const comp = dwarf.bin_file.comp;
980 const io = comp.io;
981 try dwarf.getFile().?.writePositionalAll(io, contents, sec.off(dwarf) + unit.off + unit.header_len + entry_ptr.off);
982 if (false) {
983 const buf = try dwarf.gpa.alloc(u8, sec.len);
984 defer dwarf.gpa.free(buf);
985 _ = try dwarf.getFile().?.readPositionalAll(io, buf, sec.off(dwarf));
986 log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{
987 @backingInt(sec.first),
988 @backingInt(sec.last),
989 sec.off(dwarf),
990 sec.len,
991 });
992 for (sec.units.items) |*unit_ptr| {
993 log.info(" Unit{{ .prev = {}, .next = {}, .first = {}, .last = {}, .off = 0x{x}, .header_len = 0x{x}, .trailer_len = 0x{x}, .len = 0x{x} }}", .{
994 @backingInt(unit_ptr.prev),
995 @backingInt(unit_ptr.next),
996 @backingInt(unit_ptr.first),
997 @backingInt(unit_ptr.last),
998 unit_ptr.off,
999 unit_ptr.header_len,
1000 unit_ptr.trailer_len,
1001 unit_ptr.len,
1002 });
1003 for (unit_ptr.entries.items) |*entry| {
1004 log.info(" Entry{{ .prev = {}, .next = {}, .off = 0x{x}, .len = 0x{x} }}", .{
1005 @backingInt(entry.prev),
1006 @backingInt(entry.next),
1007 entry.off,
1008 entry.len,
1009 });
1010 }
1011 }
1012 std.debug.dumpHex(buf);
1013 }
1014 }
1015
1016 pub fn assertNonEmpty(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) *Entry {
1017 if (entry.len > 0) return entry;
1018 if (std.debug.runtime_safety) {
1019 log.err("missing {} from {s}", .{
1020 @as(Entry.Index, @fromBackingInt(@intCast(entry - unit.entries.items.ptr))),
1021 std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file|
1022 elf_file.zigObjectPtr().?.symbol(sec.index).name(elf_file)
1023 else if (dwarf.bin_file.cast(.macho)) |macho_file|
1024 if (macho_file.d_sym) |*d_sym|
1025 &d_sym.sections.items[sec.index].segname
1026 else
1027 &macho_file.sections.items(.header)[sec.index].segname
1028 else
1029 "?", 0),
1030 });
1031 const zcu = dwarf.bin_file.comp.zcu.?;
1032 const ip = &zcu.intern_pool;
1033 for (0.., dwarf.values.items) |raw_index, unit_and_entry| {
1034 const index: link.ConstPool.Index = @fromBackingInt(@intCast(raw_index));
1035 const val = index.val(&dwarf.const_pool);
1036 const val_unit, const val_entry = unit_and_entry;
1037 if (sec.getUnit(val_unit) == unit and unit.getEntry(val_entry) == entry)
1038 log.err("missing Value({f}({d}))", .{
1039 Value.fromInterned(val).fmtValue(.{ .tid = .main, .zcu = zcu }),
1040 @backingInt(val),
1041 });
1042 }
1043 for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| {
1044 const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFile(ip)).mod.?) catch unreachable;
1045 if (sec.getUnit(nav_unit) == unit and unit.getEntry(other_entry) == entry)
1046 log.err("missing Nav({f}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @backingInt(nav) });
1047 }
1048 }
1049 @panic("missing dwarf relocation target");
1050 }
1051
1052 fn resolveRelocs(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {
1053 const entry_off = sec.off(dwarf) + unit.off + unit.header_len + entry.off;
1054 for (entry.cross_entry_relocs.items) |reloc| {
1055 try dwarf.resolveReloc(
1056 entry_off + reloc.source_off,
1057 unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off,
1058 dwarf.sectionOffsetBytes(),
1059 );
1060 }
1061 for (entry.cross_unit_relocs.items) |reloc| {
1062 const target_unit = sec.getUnit(reloc.target_unit);
1063 try dwarf.resolveReloc(
1064 entry_off + reloc.source_off,
1065 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
1066 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(target_unit, sec, dwarf).off
1067 else
1068 0) + reloc.target_off,
1069 dwarf.sectionOffsetBytes(),
1070 );
1071 }
1072 for (entry.cross_section_relocs.items) |reloc| {
1073 const target_sec = switch (reloc.target_sec) {
1074 inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section,
1075 };
1076 const target_unit = target_sec.getUnit(reloc.target_unit);
1077 try dwarf.resolveReloc(
1078 entry_off + reloc.source_off,
1079 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
1080 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(target_unit, sec, dwarf).off
1081 else
1082 0) + reloc.target_off,
1083 dwarf.sectionOffsetBytes(),
1084 );
1085 }
1086 if (sec == &dwarf.debug_frame.section) switch (DebugFrame.format(dwarf)) {
1087 .none, .debug_frame => {},
1088 .eh_frame => return if (dwarf.bin_file.cast(.elf)) |elf_file| {
1089 const zo = elf_file.zigObjectPtr().?;
1090 const shndx = zo.symbol(sec.index).atom(elf_file).?.output_section_index;
1091 const entry_addr: i64 = @intCast(entry_off - sec.off(dwarf) + elf_file.shdrs.items[shndx].sh_addr);
1092 for (entry.external_relocs.items) |reloc| {
1093 const symbol = zo.symbol(reloc.target_sym);
1094 try dwarf.resolveReloc(
1095 entry_off + reloc.source_off,
1096 @bitCast((symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off))) -
1097 (entry_addr + reloc.source_off + 4)),
1098 4,
1099 );
1100 }
1101 } else unreachable,
1102 };
1103 if (dwarf.bin_file.cast(.elf)) |elf_file| {
1104 const zo = elf_file.zigObjectPtr().?;
1105 for (entry.external_relocs.items) |reloc| {
1106 const symbol = zo.symbol(reloc.target_sym);
1107 try dwarf.resolveReloc(
1108 entry_off + reloc.source_off,
1109 @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) -
1110 if (symbol.flags.is_tls) elf_file.dtpAddress() else 0),
1111 @backingInt(dwarf.address_size),
1112 );
1113 }
1114 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
1115 const zo = macho_file.getZigObject().?;
1116 for (entry.external_relocs.items) |reloc| {
1117 const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
1118 try dwarf.resolveReloc(
1119 entry_off + reloc.source_off,
1120 ref.getSymbol(macho_file).?.getAddress(.{}, macho_file) + @as(i64, @intCast(reloc.target_off)),
1121 @backingInt(dwarf.address_size),
1122 );
1123 }
1124 }
1125 }
1126};
1127
1128const CrossEntryReloc = struct {
1129 source_off: u32 = 0,
1130 target_entry: Entry.Index.Optional = .none,
1131 target_off: u32 = 0,
1132};
1133const CrossUnitReloc = struct {
1134 source_off: u32 = 0,
1135 target_unit: Unit.Index,
1136 target_entry: Entry.Index.Optional = .none,
1137 target_off: u32 = 0,
1138};
1139const CrossSectionReloc = struct {
1140 source_off: u32 = 0,
1141 target_sec: Section.Index,
1142 target_unit: Unit.Index,
1143 target_entry: Entry.Index.Optional = .none,
1144 target_off: u32 = 0,
1145};
1146const ExternalReloc = struct {
1147 source_off: u32 = 0,
1148 target_sym: link.File.SymbolId,
1149 target_off: u64 = 0,
1150};
1151
1152pub const Loc = union(enum) {
1153 empty,
1154 addr_reloc: link.File.SymbolId,
1155 deref: *const Loc,
1156 constu: u64,
1157 consts: i64,
1158 plus: Bin,
1159 reg: u32,
1160 breg: u32,
1161 push_object_address,
1162 call: struct {
1163 args: []const Loc = &.{},
1164 unit: Unit.Index,
1165 entry: Entry.Index,
1166 },
1167 form_tls_address: *const Loc,
1168 implicit_value: []const u8,
1169 stack_value: *const Loc,
1170 implicit_pointer: struct {
1171 unit: Unit.Index,
1172 entry: Entry.Index,
1173 offset: i65,
1174 },
1175 wasm_ext: union(enum) {
1176 local: u32,
1177 global: u32,
1178 operand_stack: u32,
1179 },
1180
1181 pub const Bin = struct { *const Loc, *const Loc };
1182
1183 fn getConst(loc: Loc, comptime Int: type) ?Int {
1184 return switch (loc) {
1185 .constu => |constu| std.math.cast(Int, constu),
1186 .consts => |consts| std.math.cast(Int, consts),
1187 else => null,
1188 };
1189 }
1190
1191 fn getBaseReg(loc: Loc) ?u32 {
1192 return switch (loc) {
1193 .breg => |breg| breg,
1194 else => null,
1195 };
1196 }
1197
1198 fn writeReg(reg: u32, op0: u8, opx: u8, writer: *Writer) Writer.Error!void {
1199 if (std.math.cast(u5, reg)) |small_reg| {
1200 try writer.writeByte(op0 + small_reg);
1201 } else {
1202 try writer.writeByte(opx);
1203 try writer.writeUleb128(reg);
1204 }
1205 }
1206
1207 fn write(loc: Loc, adapter: anytype) (UpdateError || Writer.Error)!void {
1208 const writer = adapter.writer();
1209 switch (loc) {
1210 .empty => {},
1211 .addr_reloc => |sym_index| {
1212 try writer.writeByte(DW.OP.addr);
1213 try adapter.addrSym(sym_index);
1214 },
1215 .deref => |addr| {
1216 try addr.write(adapter);
1217 try writer.writeByte(DW.OP.deref);
1218 },
1219 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
1220 try writer.writeByte(@as(u8, DW.OP.lit0) + lit);
1221 } else if (std.math.cast(u8, constu)) |const1u| {
1222 try writer.writeAll(&.{ DW.OP.const1u, const1u });
1223 } else if (std.math.cast(u16, constu)) |const2u| {
1224 try writer.writeByte(DW.OP.const2u);
1225 try writer.writeInt(u16, const2u, adapter.endian());
1226 } else if (std.math.cast(u21, constu)) |const3u| {
1227 try writer.writeByte(DW.OP.constu);
1228 try writer.writeUleb128(const3u);
1229 } else if (std.math.cast(u32, constu)) |const4u| {
1230 try writer.writeByte(DW.OP.const4u);
1231 try writer.writeInt(u32, const4u, adapter.endian());
1232 } else if (std.math.cast(u49, constu)) |const7u| {
1233 try writer.writeByte(DW.OP.constu);
1234 try writer.writeUleb128(const7u);
1235 } else {
1236 try writer.writeByte(DW.OP.const8u);
1237 try writer.writeInt(u64, constu, adapter.endian());
1238 },
1239 .consts => |consts| if (std.math.cast(i8, consts)) |const1s| {
1240 try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) });
1241 } else if (std.math.cast(i16, consts)) |const2s| {
1242 try writer.writeByte(DW.OP.const2s);
1243 try writer.writeInt(i16, const2s, adapter.endian());
1244 } else if (std.math.cast(i21, consts)) |const3s| {
1245 try writer.writeByte(DW.OP.consts);
1246 try writer.writeSleb128(const3s);
1247 } else if (std.math.cast(i32, consts)) |const4s| {
1248 try writer.writeByte(DW.OP.const4s);
1249 try writer.writeInt(i32, const4s, adapter.endian());
1250 } else if (std.math.cast(i49, consts)) |const7s| {
1251 try writer.writeByte(DW.OP.consts);
1252 try writer.writeSleb128(const7s);
1253 } else {
1254 try writer.writeByte(DW.OP.const8s);
1255 try writer.writeInt(i64, consts, adapter.endian());
1256 },
1257 .plus => |plus| done: {
1258 if (plus[0].getConst(u0)) |_| {
1259 try plus[1].write(adapter);
1260 break :done;
1261 }
1262 if (plus[1].getConst(u0)) |_| {
1263 try plus[0].write(adapter);
1264 break :done;
1265 }
1266 if (plus[0].getBaseReg()) |breg| {
1267 if (plus[1].getConst(i65)) |offset| {
1268 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
1269 try writer.writeSleb128(offset);
1270 break :done;
1271 }
1272 }
1273 if (plus[1].getBaseReg()) |breg| {
1274 if (plus[0].getConst(i65)) |offset| {
1275 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
1276 try writer.writeSleb128(offset);
1277 break :done;
1278 }
1279 }
1280 if (plus[0].getConst(u64)) |uconst| {
1281 try plus[1].write(adapter);
1282 try writer.writeByte(DW.OP.plus_uconst);
1283 try writer.writeUleb128(uconst);
1284 break :done;
1285 }
1286 if (plus[1].getConst(u64)) |uconst| {
1287 try plus[0].write(adapter);
1288 try writer.writeByte(DW.OP.plus_uconst);
1289 try writer.writeUleb128(uconst);
1290 break :done;
1291 }
1292 try plus[0].write(adapter);
1293 try plus[1].write(adapter);
1294 try writer.writeByte(DW.OP.plus);
1295 },
1296 .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer),
1297 .breg => |breg| {
1298 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
1299 try writer.writeSleb128(0);
1300 },
1301 .push_object_address => try writer.writeByte(DW.OP.push_object_address),
1302 .call => |call| {
1303 for (call.args) |arg| try arg.write(adapter);
1304 try writer.writeByte(DW.OP.call_ref);
1305 try adapter.infoEntry(call.unit, call.entry);
1306 },
1307 .form_tls_address => |addr| {
1308 try addr.write(adapter);
1309 try writer.writeByte(DW.OP.form_tls_address);
1310 },
1311 .implicit_value => |value| {
1312 try writer.writeByte(DW.OP.implicit_value);
1313 try writer.writeUleb128(value.len);
1314 try writer.writeAll(value);
1315 },
1316 .stack_value => |value| {
1317 try value.write(adapter);
1318 try writer.writeByte(DW.OP.stack_value);
1319 },
1320 .implicit_pointer => |implicit_pointer| {
1321 try writer.writeByte(DW.OP.implicit_pointer);
1322 try adapter.infoEntry(implicit_pointer.unit, implicit_pointer.entry);
1323 try writer.writeSleb128(implicit_pointer.offset);
1324 },
1325 .wasm_ext => |wasm_ext| {
1326 try writer.writeByte(DW.OP.WASM_location);
1327 switch (wasm_ext) {
1328 .local => |local| {
1329 try writer.writeByte(DW.OP.WASM_local);
1330 try writer.writeUleb128(local);
1331 },
1332 .global => |global| if (std.math.cast(u21, global)) |global_u21| {
1333 try writer.writeByte(DW.OP.WASM_global);
1334 try writer.writeUleb128(global_u21);
1335 } else {
1336 try writer.writeByte(DW.OP.WASM_global_u32);
1337 try writer.writeInt(u32, global, adapter.endian());
1338 },
1339 .operand_stack => |operand_stack| {
1340 try writer.writeByte(DW.OP.WASM_operand_stack);
1341 try writer.writeUleb128(operand_stack);
1342 },
1343 }
1344 },
1345 }
1346 }
1347};
1348
1349pub const Cfa = union(enum) {
1350 nop,
1351 advance_loc: u32,
1352 offset: RegOff,
1353 rel_offset: RegOff,
1354 restore: u32,
1355 undefined: u32,
1356 same_value: u32,
1357 register: [2]u32,
1358 remember_state,
1359 restore_state,
1360 def_cfa: RegOff,
1361 def_cfa_register: u32,
1362 def_cfa_offset: i64,
1363 adjust_cfa_offset: i64,
1364 def_cfa_expression: Loc,
1365 expression: RegExpr,
1366 val_offset: RegOff,
1367 val_expression: RegExpr,
1368 escape: []const u8,
1369
1370 const RegOff = struct { reg: u32, off: i64 };
1371 const RegExpr = struct { reg: u32, expr: Loc };
1372
1373 fn write(cfa: Cfa, wip_nav: *WipNav) (UpdateError || Writer.Error)!void {
1374 const dfw = &wip_nav.debug_frame.writer;
1375 switch (cfa) {
1376 .nop => try dfw.writeByte(DW.CFA.nop),
1377 .advance_loc => |loc| {
1378 const delta = @divExact(loc - wip_nav.cfi.loc, wip_nav.dwarf.debug_frame.header.code_alignment_factor);
1379 if (delta == 0) {} else if (std.math.cast(u6, delta)) |small_delta|
1380 try dfw.writeByte(@as(u8, DW.CFA.advance_loc) + small_delta)
1381 else if (std.math.cast(u8, delta)) |ubyte_delta|
1382 try dfw.writeAll(&.{ DW.CFA.advance_loc1, ubyte_delta })
1383 else if (std.math.cast(u16, delta)) |uhalf_delta| {
1384 try dfw.writeByte(DW.CFA.advance_loc2);
1385 try dfw.writeInt(u16, uhalf_delta, wip_nav.dwarf.endian);
1386 } else if (std.math.cast(u32, delta)) |uword_delta| {
1387 try dfw.writeByte(DW.CFA.advance_loc4);
1388 try dfw.writeInt(u32, uword_delta, wip_nav.dwarf.endian);
1389 }
1390 wip_nav.cfi.loc = loc;
1391 },
1392 .offset, .rel_offset => |reg_off| {
1393 const factored_off = @divExact(reg_off.off - switch (cfa) {
1394 else => unreachable,
1395 .offset => 0,
1396 .rel_offset => wip_nav.cfi.cfa.off,
1397 }, wip_nav.dwarf.debug_frame.header.data_alignment_factor);
1398 if (std.math.cast(u63, factored_off)) |unsigned_off| {
1399 if (std.math.cast(u6, reg_off.reg)) |small_reg| {
1400 try dfw.writeByte(@as(u8, DW.CFA.offset) + small_reg);
1401 } else {
1402 try dfw.writeByte(DW.CFA.offset_extended);
1403 try dfw.writeUleb128(reg_off.reg);
1404 }
1405 try dfw.writeUleb128(unsigned_off);
1406 } else {
1407 try dfw.writeByte(DW.CFA.offset_extended_sf);
1408 try dfw.writeUleb128(reg_off.reg);
1409 try dfw.writeSleb128(factored_off);
1410 }
1411 },
1412 .restore => |reg| if (std.math.cast(u6, reg)) |small_reg|
1413 try dfw.writeByte(@as(u8, DW.CFA.restore) + small_reg)
1414 else {
1415 try dfw.writeByte(DW.CFA.restore_extended);
1416 try dfw.writeUleb128(reg);
1417 },
1418 .undefined => |reg| {
1419 try dfw.writeByte(DW.CFA.undefined);
1420 try dfw.writeUleb128(reg);
1421 },
1422 .same_value => |reg| {
1423 try dfw.writeByte(DW.CFA.same_value);
1424 try dfw.writeUleb128(reg);
1425 },
1426 .register => |regs| if (regs[0] != regs[1]) {
1427 try dfw.writeByte(DW.CFA.register);
1428 for (regs) |reg| try dfw.writeUleb128(reg);
1429 } else {
1430 try dfw.writeByte(DW.CFA.same_value);
1431 try dfw.writeUleb128(regs[0]);
1432 },
1433 .remember_state => try dfw.writeByte(DW.CFA.remember_state),
1434 .restore_state => try dfw.writeByte(DW.CFA.restore_state),
1435 .def_cfa, .def_cfa_register, .def_cfa_offset, .adjust_cfa_offset => {
1436 const reg_off: RegOff = switch (cfa) {
1437 else => unreachable,
1438 .def_cfa => |reg_off| reg_off,
1439 .def_cfa_register => |reg| .{ .reg = reg, .off = wip_nav.cfi.cfa.off },
1440 .def_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = off },
1441 .adjust_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = wip_nav.cfi.cfa.off + off },
1442 };
1443 const changed_reg = reg_off.reg != wip_nav.cfi.cfa.reg;
1444 const unsigned_off = std.math.cast(u63, reg_off.off);
1445 if (reg_off.off == wip_nav.cfi.cfa.off) {
1446 if (changed_reg) {
1447 try dfw.writeByte(DW.CFA.def_cfa_register);
1448 try dfw.writeUleb128(reg_off.reg);
1449 }
1450 } else if (switch (wip_nav.dwarf.debug_frame.header.data_alignment_factor) {
1451 0 => unreachable,
1452 1 => unsigned_off != null,
1453 else => |data_alignment_factor| @rem(reg_off.off, data_alignment_factor) != 0,
1454 }) {
1455 try dfw.writeByte(if (changed_reg) DW.CFA.def_cfa else DW.CFA.def_cfa_offset);
1456 if (changed_reg) try dfw.writeUleb128(reg_off.reg);
1457 try dfw.writeUleb128(unsigned_off.?);
1458 } else {
1459 try dfw.writeByte(if (changed_reg) DW.CFA.def_cfa_sf else DW.CFA.def_cfa_offset_sf);
1460 if (changed_reg) try dfw.writeUleb128(reg_off.reg);
1461 try dfw.writeSleb128(@divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor));
1462 }
1463 wip_nav.cfi.cfa = reg_off;
1464 },
1465 .def_cfa_expression => |expr| {
1466 try dfw.writeByte(DW.CFA.def_cfa_expression);
1467 try wip_nav.frameExprLoc(expr);
1468 },
1469 .expression => |reg_expr| {
1470 try dfw.writeByte(DW.CFA.expression);
1471 try dfw.writeUleb128(reg_expr.reg);
1472 try wip_nav.frameExprLoc(reg_expr.expr);
1473 },
1474 .val_offset => |reg_off| {
1475 const factored_off = @divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor);
1476 if (std.math.cast(u63, factored_off)) |unsigned_off| {
1477 try dfw.writeByte(DW.CFA.val_offset);
1478 try dfw.writeUleb128(reg_off.reg);
1479 try dfw.writeUleb128(unsigned_off);
1480 } else {
1481 try dfw.writeByte(DW.CFA.val_offset_sf);
1482 try dfw.writeUleb128(reg_off.reg);
1483 try dfw.writeSleb128(factored_off);
1484 }
1485 },
1486 .val_expression => |reg_expr| {
1487 try dfw.writeByte(DW.CFA.val_expression);
1488 try dfw.writeUleb128(reg_expr.reg);
1489 try wip_nav.frameExprLoc(reg_expr.expr);
1490 },
1491 .escape => |bytes| try dfw.writeAll(bytes),
1492 }
1493 }
1494};
1495
1496pub const WipNav = struct {
1497 dwarf: *Dwarf,
1498 pt: Zcu.PerThread,
1499 unit: Unit.Index,
1500 entry: Entry.Index,
1501 any_children: bool,
1502 func: InternPool.Index,
1503 func_sym_index: link.File.SymbolId,
1504 func_high_pc: u32,
1505 blocks: std.ArrayList(struct {
1506 abbrev_code: u32,
1507 low_pc_off: u64,
1508 high_pc: u32,
1509 }),
1510 cfi: struct {
1511 loc: u32,
1512 cfa: Cfa.RegOff,
1513 },
1514 debug_frame: Writer.Allocating,
1515 debug_info: Writer.Allocating,
1516 debug_line: Writer.Allocating,
1517 debug_loclists: Writer.Allocating,
1518
1519 pub fn deinit(wip_nav: *WipNav) void {
1520 const gpa = wip_nav.dwarf.gpa;
1521 if (wip_nav.func != .none) wip_nav.blocks.deinit(gpa);
1522 wip_nav.debug_frame.deinit();
1523 wip_nav.debug_info.deinit();
1524 wip_nav.debug_line.deinit();
1525 wip_nav.debug_loclists.deinit();
1526 }
1527
1528 pub fn genDebugFrame(wip_nav: *WipNav, loc: u32, cfa: Cfa) UpdateError!void {
1529 return wip_nav.genDebugFrameWriterError(loc, cfa) catch |err| switch (err) {
1530 error.WriteFailed => error.OutOfMemory,
1531 else => |e| e,
1532 };
1533 }
1534 fn genDebugFrameWriterError(wip_nav: *WipNav, loc: u32, cfa: Cfa) (UpdateError || Writer.Error)!void {
1535 assert(wip_nav.func != .none);
1536 if (wip_nav.dwarf.debug_frame.header.format == .none) return;
1537 const loc_cfa: Cfa = .{ .advance_loc = loc };
1538 try loc_cfa.write(wip_nav);
1539 try cfa.write(wip_nav);
1540 }
1541
1542 pub const LocalVarTag = enum { arg, local_var };
1543 pub fn genLocalVarDebugInfo(
1544 wip_nav: *WipNav,
1545 tag: LocalVarTag,
1546 opt_name: ?[]const u8,
1547 ty: Type,
1548 loc: Loc,
1549 ) UpdateError!void {
1550 return wip_nav.genLocalVarDebugInfoWriterError(tag, opt_name, ty, loc) catch |err| switch (err) {
1551 error.WriteFailed => error.OutOfMemory,
1552 else => |e| e,
1553 };
1554 }
1555 fn genLocalVarDebugInfoWriterError(
1556 wip_nav: *WipNav,
1557 tag: LocalVarTag,
1558 opt_name: ?[]const u8,
1559 ty: Type,
1560 loc: Loc,
1561 ) (UpdateError || Writer.Error)!void {
1562 assert(wip_nav.func != .none);
1563 try wip_nav.abbrevCode(switch (tag) {
1564 .arg => if (opt_name) |_| .arg else .unnamed_arg,
1565 .local_var => if (opt_name) |_| .local_var else unreachable,
1566 });
1567 if (opt_name) |name| try wip_nav.strp(name);
1568 try wip_nav.refType(ty);
1569 try wip_nav.infoExprLoc(loc);
1570 wip_nav.any_children = true;
1571 }
1572
1573 pub const LocalConstTag = enum { comptime_arg, local_const };
1574 pub fn genLocalConstDebugInfo(
1575 wip_nav: *WipNav,
1576 tag: LocalConstTag,
1577 opt_name: ?[]const u8,
1578 val: Value,
1579 ) UpdateError!void {
1580 return wip_nav.genLocalConstDebugInfoWriterError(tag, opt_name, val) catch |err| switch (err) {
1581 error.WriteFailed => error.OutOfMemory,
1582 else => |e| e,
1583 };
1584 }
1585 fn genLocalConstDebugInfoWriterError(
1586 wip_nav: *WipNav,
1587 tag: LocalConstTag,
1588 opt_name: ?[]const u8,
1589 val: Value,
1590 ) (UpdateError || Writer.Error)!void {
1591 assert(wip_nav.func != .none);
1592 const pt = wip_nav.pt;
1593 const zcu = pt.zcu;
1594 const ty = val.typeOf(zcu);
1595 const has_runtime_bits = ty.hasRuntimeBits(zcu);
1596 const has_comptime_state = ty.comptimeOnly(zcu);
1597 try wip_nav.abbrevCode(if (has_runtime_bits and has_comptime_state) switch (tag) {
1598 .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits_comptime_state else .unnamed_comptime_arg_runtime_bits_comptime_state,
1599 .local_const => if (opt_name) |_| .local_const_runtime_bits_comptime_state else unreachable,
1600 } else if (has_comptime_state) switch (tag) {
1601 .comptime_arg => if (opt_name) |_| .comptime_arg_comptime_state else .unnamed_comptime_arg_comptime_state,
1602 .local_const => if (opt_name) |_| .local_const_comptime_state else unreachable,
1603 } else if (has_runtime_bits) switch (tag) {
1604 .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits else .unnamed_comptime_arg_runtime_bits,
1605 .local_const => if (opt_name) |_| .local_const_runtime_bits else unreachable,
1606 } else switch (tag) {
1607 .comptime_arg => if (opt_name) |_| .comptime_arg else .unnamed_comptime_arg,
1608 .local_const => if (opt_name) |_| .local_const else unreachable,
1609 });
1610 if (opt_name) |name| try wip_nav.strp(name);
1611 try wip_nav.refType(ty);
1612 if (has_runtime_bits) try wip_nav.blockValue(val);
1613 if (has_comptime_state) try wip_nav.refValue(val);
1614 wip_nav.any_children = true;
1615 }
1616
1617 pub fn genVarArgsDebugInfo(wip_nav: *WipNav) UpdateError!void {
1618 return wip_nav.genVarArgsDebugInfoWriterError() catch |err| switch (err) {
1619 error.WriteFailed => error.OutOfMemory,
1620 else => |e| e,
1621 };
1622 }
1623 fn genVarArgsDebugInfoWriterError(wip_nav: *WipNav) (UpdateError || Writer.Error)!void {
1624 assert(wip_nav.func != .none);
1625 try wip_nav.abbrevCode(.is_var_args);
1626 wip_nav.any_children = true;
1627 }
1628
1629 pub fn advancePCAndLine(wip_nav: *WipNav, delta_line: i33, delta_pc: u64) Allocator.Error!void {
1630 return wip_nav.advancePCAndLineWriterError(delta_line, delta_pc) catch |err| switch (err) {
1631 error.WriteFailed => error.OutOfMemory,
1632 };
1633 }
1634 fn advancePCAndLineWriterError(
1635 wip_nav: *WipNav,
1636 delta_line: i33,
1637 delta_pc: u64,
1638 ) Writer.Error!void {
1639 const dlw = &wip_nav.debug_line.writer;
1640
1641 const header = wip_nav.dwarf.debug_line.header;
1642 assert(header.maximum_operations_per_instruction == 1);
1643 const delta_op: u64 = 0;
1644
1645 const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or
1646 delta_line - header.line_base >= header.line_range)
1647 remaining: {
1648 assert(delta_line != 0);
1649 try dlw.writeByte(DW.LNS.advance_line);
1650 try dlw.writeSleb128(delta_line);
1651 break :remaining 0;
1652 } else delta_line);
1653
1654 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
1655 header.maximum_operations_per_instruction + delta_op;
1656 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
1657 const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: {
1658 try dlw.writeByte(DW.LNS.advance_pc);
1659 try dlw.writeUleb128(op_advance);
1660 break :remaining 0;
1661 } else if (op_advance >= max_op_advance) remaining: {
1662 try dlw.writeByte(DW.LNS.const_add_pc);
1663 break :remaining op_advance - max_op_advance;
1664 } else op_advance);
1665
1666 if (remaining_delta_line == 0 and remaining_op_advance == 0)
1667 try dlw.writeByte(DW.LNS.copy)
1668 else
1669 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +
1670 (header.line_range * remaining_op_advance) + header.opcode_base));
1671 }
1672
1673 pub fn setColumn(wip_nav: *WipNav, column: u32) Allocator.Error!void {
1674 return wip_nav.setColumnWriterError(column) catch |err| switch (err) {
1675 error.WriteFailed => error.OutOfMemory,
1676 };
1677 }
1678 fn setColumnWriterError(wip_nav: *WipNav, column: u32) Writer.Error!void {
1679 const dlw = &wip_nav.debug_line.writer;
1680 try dlw.writeByte(DW.LNS.set_column);
1681 try dlw.writeUleb128(column + 1);
1682 }
1683
1684 pub fn negateStmt(wip_nav: *WipNav) Allocator.Error!void {
1685 return wip_nav.negateStmtWriterError() catch |err| switch (err) {
1686 error.WriteFailed => error.OutOfMemory,
1687 };
1688 }
1689 fn negateStmtWriterError(wip_nav: *WipNav) Writer.Error!void {
1690 try wip_nav.debug_line.writer.writeByte(DW.LNS.negate_stmt);
1691 }
1692
1693 pub fn setPrologueEnd(wip_nav: *WipNav) Allocator.Error!void {
1694 return wip_nav.setPrologueEndWriterError() catch |err| switch (err) {
1695 error.WriteFailed => error.OutOfMemory,
1696 };
1697 }
1698 fn setPrologueEndWriterError(wip_nav: *WipNav) Writer.Error!void {
1699 try wip_nav.debug_line.writer.writeByte(DW.LNS.set_prologue_end);
1700 }
1701
1702 pub fn setEpilogueBegin(wip_nav: *WipNav) Allocator.Error!void {
1703 return wip_nav.setEpilogueBeginWriterError() catch |err| switch (err) {
1704 error.WriteFailed => error.OutOfMemory,
1705 };
1706 }
1707 fn setEpilogueBeginWriterError(wip_nav: *WipNav) Writer.Error!void {
1708 try wip_nav.debug_line.writer.writeByte(DW.LNS.set_epilogue_begin);
1709 }
1710
1711 pub fn enterBlock(wip_nav: *WipNav, code_off: u64) UpdateError!void {
1712 return wip_nav.enterBlockWriterError(code_off) catch |err| switch (err) {
1713 error.WriteFailed => error.OutOfMemory,
1714 else => |e| e,
1715 };
1716 }
1717 fn enterBlockWriterError(wip_nav: *WipNav, code_off: u64) (UpdateError || Writer.Error)!void {
1718 const dwarf = wip_nav.dwarf;
1719 const diw = &wip_nav.debug_info.writer;
1720 const block = try wip_nav.blocks.addOne(dwarf.gpa);
1721
1722 block.abbrev_code = @intCast(diw.end);
1723 try wip_nav.abbrevCode(.block);
1724 block.low_pc_off = code_off;
1725 try wip_nav.infoAddrSym(wip_nav.func_sym_index, code_off);
1726 block.high_pc = @intCast(diw.end);
1727 try diw.writeInt(u32, 0, dwarf.endian);
1728 wip_nav.any_children = false;
1729 }
1730
1731 pub fn leaveBlock(wip_nav: *WipNav, code_off: u64) UpdateError!void {
1732 return wip_nav.leaveBlockWriterError(code_off) catch |err| switch (err) {
1733 error.WriteFailed => error.OutOfMemory,
1734 else => |e| e,
1735 };
1736 }
1737 fn leaveBlockWriterError(wip_nav: *WipNav, code_off: u64) (UpdateError || Writer.Error)!void {
1738 const block_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.block));
1739 const block = wip_nav.blocks.pop().?;
1740 if (wip_nav.any_children)
1741 try wip_nav.debug_info.writer.writeUleb128(@backingInt(AbbrevCode.null))
1742 else
1743 std.leb.writeUnsignedFixed(
1744 block_bytes,
1745 wip_nav.debug_info.written()[block.abbrev_code..][0..block_bytes],
1746 @intCast(try wip_nav.dwarf.refAbbrevCode(.empty_block)),
1747 );
1748 std.mem.writeInt(u32, wip_nav.debug_info.written()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian);
1749 wip_nav.any_children = true;
1750 }
1751
1752 pub fn enterInlineFunc(
1753 wip_nav: *WipNav,
1754 func: InternPool.Index,
1755 code_off: u64,
1756 line: u32,
1757 column: u32,
1758 ) UpdateError!void {
1759 return wip_nav.enterInlineFuncWriterError(func, code_off, line, column) catch |err| switch (err) {
1760 error.WriteFailed => error.OutOfMemory,
1761 else => |e| e,
1762 };
1763 }
1764 fn enterInlineFuncWriterError(
1765 wip_nav: *WipNav,
1766 func: InternPool.Index,
1767 code_off: u64,
1768 line: u32,
1769 column: u32,
1770 ) (UpdateError || Writer.Error)!void {
1771 const dwarf = wip_nav.dwarf;
1772 const zcu = wip_nav.pt.zcu;
1773 const diw = &wip_nav.debug_info.writer;
1774 const block = try wip_nav.blocks.addOne(dwarf.gpa);
1775
1776 block.abbrev_code = @intCast(diw.end);
1777 try wip_nav.abbrevCode(.inlined_func);
1778 try wip_nav.refNav(zcu.funcInfo(func).owner_nav);
1779 try diw.writeUleb128(zcu.navSrcLine(zcu.funcInfo(wip_nav.func).owner_nav) + line + 1);
1780 try diw.writeUleb128(column + 1);
1781 block.low_pc_off = code_off;
1782 try wip_nav.infoAddrSym(wip_nav.func_sym_index, code_off);
1783 block.high_pc = @intCast(diw.end);
1784 try diw.writeInt(u32, 0, dwarf.endian);
1785 try wip_nav.setInlineFunc(func);
1786 wip_nav.any_children = false;
1787 }
1788
1789 pub fn leaveInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64) UpdateError!void {
1790 return wip_nav.leaveInlineFuncWriterError(func, code_off) catch |err| switch (err) {
1791 error.WriteFailed => error.OutOfMemory,
1792 else => |e| e,
1793 };
1794 }
1795 fn leaveInlineFuncWriterError(
1796 wip_nav: *WipNav,
1797 func: InternPool.Index,
1798 code_off: u64,
1799 ) (UpdateError || Writer.Error)!void {
1800 const inlined_func_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.inlined_func));
1801 const block = wip_nav.blocks.pop().?;
1802 if (wip_nav.any_children)
1803 try wip_nav.debug_info.writer.writeUleb128(@backingInt(AbbrevCode.null))
1804 else
1805 std.leb.writeUnsignedFixed(
1806 inlined_func_bytes,
1807 wip_nav.debug_info.written()[block.abbrev_code..][0..inlined_func_bytes],
1808 @intCast(try wip_nav.dwarf.refAbbrevCode(.empty_inlined_func)),
1809 );
1810 std.mem.writeInt(u32, wip_nav.debug_info.written()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian);
1811 try wip_nav.setInlineFunc(func);
1812 wip_nav.any_children = true;
1813 }
1814
1815 pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void {
1816 return wip_nav.setInlineFuncWriterError(func) catch |err| switch (err) {
1817 error.WriteFailed => error.OutOfMemory,
1818 else => |e| e,
1819 };
1820 }
1821 fn setInlineFuncWriterError(wip_nav: *WipNav, func: InternPool.Index) (UpdateError || Writer.Error)!void {
1822 const zcu = wip_nav.pt.zcu;
1823 const dwarf = wip_nav.dwarf;
1824 if (wip_nav.func == func) return;
1825
1826 const new_func_info = zcu.funcInfo(func);
1827 const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav);
1828 const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod.?);
1829
1830 const dlw = &wip_nav.debug_line.writer;
1831 if (dwarf.incremental()) {
1832 const new_nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, new_func_info.owner_nav);
1833 errdefer _ = if (!new_nav_gop.found_existing) dwarf.navs.pop();
1834 if (!new_nav_gop.found_existing) new_nav_gop.value_ptr.* = try dwarf.addCommonEntry(new_unit);
1835
1836 try dlw.writeByte(DW.LNS.extended_op);
1837 try dlw.writeUleb128(1 + dwarf.sectionOffsetBytes());
1838 try dlw.writeByte(DW.LNE.ZIG_set_decl);
1839 try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{
1840 .source_off = @intCast(dlw.end),
1841 .target_sec = .debug_info,
1842 .target_unit = new_unit,
1843 .target_entry = new_nav_gop.value_ptr.toOptional(),
1844 });
1845 try dlw.splatByteAll(0, dwarf.sectionOffsetBytes());
1846 return;
1847 }
1848
1849 const old_func_info = zcu.funcInfo(wip_nav.func);
1850 const old_file = zcu.navFileScopeIndex(old_func_info.owner_nav);
1851 if (old_file != new_file) {
1852 const mod_info = dwarf.getModInfo(wip_nav.unit);
1853 try mod_info.dirs.put(dwarf.gpa, new_unit, {});
1854 const file_gop = try mod_info.files.getOrPut(dwarf.gpa, new_file);
1855
1856 try dlw.writeByte(DW.LNS.set_file);
1857 try dlw.writeUleb128(file_gop.index);
1858 }
1859
1860 const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav);
1861 const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav);
1862 if (new_src_line != old_src_line) {
1863 try dlw.writeByte(DW.LNS.advance_line);
1864 try dlw.writeSleb128(new_src_line - old_src_line);
1865 }
1866
1867 wip_nav.func = func;
1868 }
1869
1870 fn externalReloc(wip_nav: *WipNav, sec: *Section, reloc: ExternalReloc) Allocator.Error!void {
1871 try sec.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(wip_nav.dwarf.gpa, reloc);
1872 }
1873
1874 pub fn infoExternalReloc(wip_nav: *WipNav, reloc: ExternalReloc) Allocator.Error!void {
1875 try wip_nav.externalReloc(&wip_nav.dwarf.debug_info.section, reloc);
1876 }
1877
1878 fn frameExternalReloc(wip_nav: *WipNav, reloc: ExternalReloc) Allocator.Error!void {
1879 try wip_nav.externalReloc(&wip_nav.dwarf.debug_frame.section, reloc);
1880 }
1881
1882 fn abbrevCode(wip_nav: *WipNav, abbrev_code: AbbrevCode) (UpdateError || Writer.Error)!void {
1883 try wip_nav.debug_info.writer.writeUleb128(try wip_nav.dwarf.refAbbrevCode(abbrev_code));
1884 }
1885
1886 fn sectionOffset(
1887 wip_nav: *WipNav,
1888 comptime sec: Section.Index,
1889 target_sec: Section.Index,
1890 target_unit: Unit.Index,
1891 target_entry: Entry.Index,
1892 target_off: u32,
1893 ) (UpdateError || Writer.Error)!void {
1894 const dwarf = wip_nav.dwarf;
1895 const gpa = dwarf.gpa;
1896 const entry_ptr = @field(dwarf, @tagName(sec)).section.getUnit(wip_nav.unit).getEntry(wip_nav.entry);
1897 const sw = &@field(wip_nav, @tagName(sec)).writer;
1898 const source_off: u32 = @intCast(sw.end);
1899 if (target_sec != sec) {
1900 try entry_ptr.cross_section_relocs.append(gpa, .{
1901 .source_off = source_off,
1902 .target_sec = target_sec,
1903 .target_unit = target_unit,
1904 .target_entry = target_entry.toOptional(),
1905 .target_off = target_off,
1906 });
1907 } else if (target_unit != wip_nav.unit) {
1908 try entry_ptr.cross_unit_relocs.append(gpa, .{
1909 .source_off = source_off,
1910 .target_unit = target_unit,
1911 .target_entry = target_entry.toOptional(),
1912 .target_off = target_off,
1913 });
1914 } else {
1915 try entry_ptr.cross_entry_relocs.append(gpa, .{
1916 .source_off = source_off,
1917 .target_entry = target_entry.toOptional(),
1918 .target_off = target_off,
1919 });
1920 }
1921 try sw.splatByteAll(0, dwarf.sectionOffsetBytes());
1922 }
1923
1924 fn infoSectionOffset(
1925 wip_nav: *WipNav,
1926 target_sec: Section.Index,
1927 target_unit: Unit.Index,
1928 target_entry: Entry.Index,
1929 target_off: u32,
1930 ) (UpdateError || Writer.Error)!void {
1931 try wip_nav.sectionOffset(.debug_info, target_sec, target_unit, target_entry, target_off);
1932 }
1933
1934 fn strp(wip_nav: *WipNav, str: []const u8) (UpdateError || Writer.Error)!void {
1935 try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0);
1936 }
1937
1938 fn strpFmt(wip_nav: *WipNav, comptime fmt: []const u8, args: anytype) (UpdateError || Writer.Error)!void {
1939 const str = try std.fmt.allocPrint(wip_nav.dwarf.gpa, fmt, args);
1940 defer wip_nav.dwarf.gpa.free(str);
1941 return wip_nav.strp(str);
1942 }
1943
1944 const ExprLocCounter = struct {
1945 dw: Writer.Discarding,
1946 section_offset_bytes: u32,
1947 address_size: AddressSize,
1948 fn init(dwarf: *Dwarf, buf: []u8) ExprLocCounter {
1949 return .{
1950 .dw = .init(buf),
1951 .section_offset_bytes = dwarf.sectionOffsetBytes(),
1952 .address_size = dwarf.address_size,
1953 };
1954 }
1955 fn writer(counter: *ExprLocCounter) *Writer {
1956 return &counter.dw.writer;
1957 }
1958 fn endian(_: ExprLocCounter) std.lang.Endian {
1959 return @import("builtin").cpu.arch.endian();
1960 }
1961 fn addrSym(counter: *ExprLocCounter, _: link.File.SymbolId) Writer.Error!void {
1962 try counter.dw.writer.splatByteAll(undefined, @backingInt(counter.address_size));
1963 }
1964 fn infoEntry(counter: *ExprLocCounter, _: Unit.Index, _: Entry.Index) Writer.Error!void {
1965 try counter.dw.writer.splatByteAll(undefined, counter.section_offset_bytes);
1966 }
1967 };
1968
1969 fn infoExprLoc(wip_nav: *WipNav, loc: Loc) (UpdateError || Writer.Error)!void {
1970 var buf: [64]u8 = undefined;
1971 var counter: ExprLocCounter = .init(wip_nav.dwarf, &buf);
1972 try loc.write(&counter);
1973
1974 const adapter: struct {
1975 wip_nav: *WipNav,
1976 fn writer(ctx: @This()) *Writer {
1977 return &ctx.wip_nav.debug_info.writer;
1978 }
1979 fn endian(ctx: @This()) std.lang.Endian {
1980 return ctx.wip_nav.dwarf.endian;
1981 }
1982 fn addrSym(ctx: @This(), sym_index: link.File.SymbolId) (UpdateError || Writer.Error)!void {
1983 try ctx.wip_nav.infoAddrSym(sym_index, 0);
1984 }
1985 fn infoEntry(
1986 ctx: @This(),
1987 unit: Unit.Index,
1988 entry: Entry.Index,
1989 ) (UpdateError || Writer.Error)!void {
1990 try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
1991 }
1992 } = .{ .wip_nav = wip_nav };
1993 try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end);
1994 try loc.write(adapter);
1995 }
1996
1997 fn infoAddrSym(
1998 wip_nav: *WipNav,
1999 sym_index: link.File.SymbolId,
2000 sym_off: u64,
2001 ) (UpdateError || Writer.Error)!void {
2002 const diw = &wip_nav.debug_info.writer;
2003 try wip_nav.infoExternalReloc(.{
2004 .source_off = @intCast(diw.end),
2005 .target_sym = sym_index,
2006 .target_off = sym_off,
2007 });
2008 try diw.splatByteAll(0, @backingInt(wip_nav.dwarf.address_size));
2009 }
2010
2011 fn frameExprLoc(wip_nav: *WipNav, loc: Loc) (UpdateError || Writer.Error)!void {
2012 var buf: [64]u8 = undefined;
2013 var counter: ExprLocCounter = .init(wip_nav.dwarf, &buf);
2014 try loc.write(&counter);
2015
2016 const adapter: struct {
2017 wip_nav: *WipNav,
2018 fn writer(ctx: @This()) *Writer {
2019 return &ctx.wip_nav.debug_frame.writer;
2020 }
2021 fn endian(ctx: @This()) std.lang.Endian {
2022 return ctx.wip_nav.dwarf.endian;
2023 }
2024 fn addrSym(ctx: @This(), sym_index: link.File.SymbolId) (UpdateError || Writer.Error)!void {
2025 try ctx.wip_nav.frameAddrSym(sym_index, 0);
2026 }
2027 fn infoEntry(
2028 ctx: @This(),
2029 unit: Unit.Index,
2030 entry: Entry.Index,
2031 ) (UpdateError || Writer.Error)!void {
2032 try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0);
2033 }
2034 } = .{ .wip_nav = wip_nav };
2035 try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end);
2036 try loc.write(adapter);
2037 }
2038
2039 fn frameAddrSym(
2040 wip_nav: *WipNav,
2041 sym_index: link.File.SymbolId,
2042 sym_off: u64,
2043 ) (UpdateError || Writer.Error)!void {
2044 const dfw = &wip_nav.debug_frame.writer;
2045 try wip_nav.frameExternalReloc(.{
2046 .source_off = @intCast(dfw.end),
2047 .target_sym = sym_index,
2048 .target_off = sym_off,
2049 });
2050 try dfw.splatByteAll(0, @backingInt(wip_nav.dwarf.address_size));
2051 }
2052
2053 fn refNav(
2054 wip_nav: *WipNav,
2055 nav_index: InternPool.Nav.Index,
2056 ) (UpdateError || Writer.Error)!void {
2057 const unit, const entry = try wip_nav.dwarf.getNavEntry(nav_index);
2058 try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
2059 }
2060
2061 fn refType(wip_nav: *WipNav, ty: Type) (UpdateError || Writer.Error)!void {
2062 return wip_nav.refValue(ty.toValue());
2063 }
2064
2065 fn refValue(wip_nav: *WipNav, value: Value) (UpdateError || Writer.Error)!void {
2066 const unit, const entry = try wip_nav.getValueEntry(value);
2067 try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
2068 }
2069
2070 fn getValueEntry(wip_nav: *WipNav, value: Value) UpdateError!struct { Unit.Index, Entry.Index } {
2071 if (value.typeOf(wip_nav.pt.zcu).toIntern() != .type_type) {
2072 assert(value.typeOf(wip_nav.pt.zcu).comptimeOnly(wip_nav.pt.zcu));
2073 }
2074 const dwarf = wip_nav.dwarf;
2075 const index = try dwarf.const_pool.get(wip_nav.pt, .{ .dwarf = dwarf }, value.toIntern());
2076 return dwarf.values.items[@backingInt(index)];
2077 }
2078
2079 fn refForward(wip_nav: *WipNav) (Allocator.Error || Writer.Error)!u32 {
2080 const dwarf = wip_nav.dwarf;
2081 const diw = &wip_nav.debug_info.writer;
2082 const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs;
2083 const reloc_index: u32 = @intCast(cross_entry_relocs.items.len);
2084 try cross_entry_relocs.append(dwarf.gpa, .{
2085 .source_off = @intCast(diw.end),
2086 .target_entry = undefined,
2087 .target_off = undefined,
2088 });
2089 try diw.splatByteAll(0, dwarf.sectionOffsetBytes());
2090 return reloc_index;
2091 }
2092
2093 fn finishForward(wip_nav: *WipNav, reloc_index: u32) void {
2094 const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs.items[reloc_index];
2095 reloc.target_entry = wip_nav.entry.toOptional();
2096 reloc.target_off = @intCast(wip_nav.debug_info.writer.end);
2097 }
2098
2099 fn blockValue(
2100 wip_nav: *WipNav,
2101 val: Value,
2102 ) (UpdateError || Writer.Error)!void {
2103 const ty = val.typeOf(wip_nav.pt.zcu);
2104 const diw = &wip_nav.debug_info.writer;
2105 const size = ty.abiSize(wip_nav.pt.zcu);
2106 try diw.writeUleb128(size);
2107 if (size == 0) return;
2108 const old_end = wip_nav.debug_info.writer.end;
2109 try codegen.generateSymbol(
2110 wip_nav.dwarf.bin_file,
2111 wip_nav.pt,
2112 val,
2113 &wip_nav.debug_info.writer,
2114 .{ .debug_output = .{ .dwarf = wip_nav } },
2115 );
2116 if (old_end + size != wip_nav.debug_info.writer.end) {
2117 std.debug.print("{f} [{}]: {} != {}\n", .{
2118 ty.fmt(wip_nav.pt),
2119 ty.toIntern(),
2120 size,
2121 wip_nav.debug_info.writer.end - old_end,
2122 });
2123 unreachable;
2124 }
2125 }
2126
2127 fn bigIntConstValue(wip_nav: *WipNav, ty: Type, big_int: std.math.big.int.Const) (UpdateError || Writer.Error)!void {
2128 const zcu = wip_nav.pt.zcu;
2129 const diw = &wip_nav.debug_info.writer;
2130 const signedness = switch (ty.toIntern()) {
2131 .comptime_int_type => .signed,
2132 else => ty.intInfo(zcu).signedness,
2133 };
2134 const bits = @max(1, big_int.bitCountTwosCompForSignedness(signedness));
2135 if (bits <= 64) {
2136 try diw.writeUleb128(@as(u13, switch (signedness) {
2137 .signed => DW.FORM.sdata,
2138 .unsigned => DW.FORM.udata,
2139 }));
2140 try wip_nav.debug_info.ensureUnusedCapacity(@divCeil(bits, 7));
2141 var bit: usize = 0;
2142 var carry: u1 = 1;
2143 while (bit < bits) {
2144 const limb_bits = @typeInfo(std.math.big.Limb).int.bits;
2145 const limb_index = bit / limb_bits;
2146 const limb_shift: std.math.Log2Int(std.math.big.Limb) = @intCast(bit % limb_bits);
2147 const low_abs_part: u7 = @truncate(big_int.limbs[limb_index] >> limb_shift);
2148 const abs_part = if (limb_shift > limb_bits - 7 and limb_index + 1 < big_int.limbs.len) abs_part: {
2149 const high_abs_part: u7 = @truncate(big_int.limbs[limb_index + 1] << -%limb_shift);
2150 break :abs_part high_abs_part | low_abs_part;
2151 } else low_abs_part;
2152 const twos_comp_part = if (big_int.positive) abs_part else twos_comp_part: {
2153 const twos_comp_part, carry = @addWithOverflow(~abs_part, carry);
2154 break :twos_comp_part twos_comp_part;
2155 };
2156 bit += 7;
2157 diw.writeByte(@as(u8, if (bit < bits) 0x80 else 0x00) | twos_comp_part) catch unreachable;
2158 }
2159 } else {
2160 try diw.writeUleb128(DW.FORM.block);
2161 const bytes = @max(ty.abiSize(zcu), @divCeil(bits, 8));
2162 try diw.writeUleb128(bytes);
2163 try wip_nav.debug_info.ensureUnusedCapacity(@intCast(bytes));
2164 big_int.writeTwosComplement(
2165 try diw.writableSlice(@intCast(bytes)),
2166 wip_nav.dwarf.endian,
2167 );
2168 }
2169 }
2170
2171 fn enumConstValue(wip_nav: *WipNav, loaded_enum: InternPool.LoadedEnumType, field_index: usize) (UpdateError || Writer.Error)!void {
2172 const zcu = wip_nav.pt.zcu;
2173 const ip = &zcu.intern_pool;
2174 var big_int_space: Value.BigIntSpace = undefined;
2175 try wip_nav.bigIntConstValue(.fromInterned(loaded_enum.int_tag_type), if (loaded_enum.field_values.len > 0)
2176 Value.fromInterned(loaded_enum.field_values.get(ip)[field_index]).toBigInt(&big_int_space, zcu)
2177 else
2178 std.math.big.int.Mutable.init(&big_int_space.limbs, field_index).toConst());
2179 }
2180
2181 fn declCommon(
2182 wip_nav: *WipNav,
2183 abbrev_code: struct {
2184 decl: AbbrevCode,
2185 generic_decl: AbbrevCode,
2186 decl_instance: AbbrevCode,
2187 },
2188 nav: *const InternPool.Nav,
2189 file: Zcu.File.Index,
2190 decl: *const std.zig.Zir.Inst.Declaration.Unwrapped,
2191 ) (UpdateError || Writer.Error)!void {
2192 const zcu = wip_nav.pt.zcu;
2193 const ip = &zcu.intern_pool;
2194 const dwarf = wip_nav.dwarf;
2195 const diw = &wip_nav.debug_info.writer;
2196
2197 const orig_entry = wip_nav.entry;
2198 defer wip_nav.entry = orig_entry;
2199 const parent_type, const is_generic_decl = if (nav.analysis) |analysis| parent_info: {
2200 const parent_type: Type = .fromInterned(zcu.namespacePtr(analysis.namespace).owner_type);
2201 const decl_gop = try dwarf.decls.getOrPut(dwarf.gpa, analysis.zir_index);
2202 errdefer _ = if (!decl_gop.found_existing) dwarf.decls.pop();
2203 const was_generic_decl = decl_gop.found_existing and
2204 switch (try dwarf.debug_info.declAbbrevCode(wip_nav.unit, decl_gop.value_ptr.*)) {
2205 .null,
2206 .decl_alias,
2207 .decl_empty_enum,
2208 .decl_enum,
2209 .decl_namespace_struct,
2210 .decl_struct,
2211 .decl_packed_struct,
2212 .decl_union,
2213 .decl_var,
2214 .decl_const,
2215 .decl_const_runtime_bits,
2216 .decl_const_comptime_state,
2217 .decl_const_runtime_bits_comptime_state,
2218 .decl_nullary_func,
2219 .decl_func,
2220 .decl_nullary_func_generic,
2221 .decl_func_generic,
2222 .decl_extern_nullary_func,
2223 .decl_extern_func,
2224 => false,
2225 .generic_decl_var,
2226 .generic_decl_const,
2227 .generic_decl_func,
2228 => true,
2229
2230 // This comes from a decl which was previously generated as an incomplete value
2231 // (I think that must mean either a function or an extern which previously had
2232 // incomplete types).
2233 .undefined_comptime_value => false,
2234
2235 else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}),
2236 };
2237 if (parent_type.getCaptures(zcu).len == 0) {
2238 if (was_generic_decl) try dwarf.freeCommonEntry(wip_nav.unit, decl_gop.value_ptr.*);
2239 decl_gop.value_ptr.* = orig_entry;
2240 break :parent_info .{ parent_type, false };
2241 } else {
2242 if (was_generic_decl)
2243 dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(decl_gop.value_ptr.*).clear()
2244 else
2245 decl_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
2246 wip_nav.entry = decl_gop.value_ptr.*;
2247 break :parent_info .{ parent_type, true };
2248 }
2249 } else .{ null, false };
2250
2251 try wip_nav.abbrevCode(if (is_generic_decl) abbrev_code.generic_decl else abbrev_code.decl);
2252 try wip_nav.refType((if (is_generic_decl) null else parent_type) orelse
2253 .fromInterned(zcu.fileRootType(file)));
2254 assert(diw.end == DebugInfo.declEntryLineOff(dwarf));
2255 try diw.writeInt(u32, decl.src_line + 1, dwarf.endian);
2256 try diw.writeUleb128(decl.src_column + 1);
2257 try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
2258 try wip_nav.strp(nav.name.toSlice(ip));
2259
2260 if (!is_generic_decl) return;
2261 const generic_decl_entry = wip_nav.entry;
2262 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, generic_decl_entry, dwarf, wip_nav.debug_info.written());
2263 wip_nav.debug_info.clearRetainingCapacity();
2264 wip_nav.entry = orig_entry;
2265 try wip_nav.abbrevCode(abbrev_code.decl_instance);
2266 try wip_nav.refType(parent_type.?);
2267 try wip_nav.infoSectionOffset(.debug_info, wip_nav.unit, generic_decl_entry, 0);
2268 }
2269};
2270
2271/// When allocating, the ideal_capacity is calculated by
2272/// actual_capacity + (actual_capacity / ideal_factor)
2273const ideal_factor = 3;
2274
2275fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
2276 return actual_size +| (actual_size / ideal_factor);
2277}
2278
2279pub fn init(lf: *link.File, format: DW.Format) Dwarf {
2280 const comp = lf.comp;
2281 const gpa = comp.gpa;
2282 const target = &comp.root_mod.resolved_target.result;
2283 return .{
2284 .gpa = gpa,
2285 .bin_file = lf,
2286 .format = format,
2287 .address_size = switch (target.ptrBitWidth()) {
2288 0...32 => .@"32",
2289 33...64 => .@"64",
2290 else => unreachable,
2291 },
2292 .endian = target.cpu.arch.endian(),
2293
2294 .const_pool = .empty,
2295
2296 .mods = .empty,
2297 .values = .empty,
2298 .navs = .empty,
2299 .decls = .empty,
2300
2301 .debug_abbrev = .{ .section = Section.init },
2302 .debug_aranges = .{ .section = Section.init },
2303 .debug_frame = .{
2304 .header = if (target.cpu.arch == .x86_64 and target.ofmt == .elf) header: {
2305 const Register = @import("../codegen/x86_64/bits.zig").Register;
2306 break :header comptime .{
2307 .format = .eh_frame,
2308 .code_alignment_factor = 1,
2309 .data_alignment_factor = -8,
2310 .return_address_register = Register.rip.dwarfNum(),
2311 .initial_instructions = &.{
2312 .{ .def_cfa = .{ .reg = Register.rsp.dwarfNum(), .off = 8 } },
2313 .{ .offset = .{ .reg = Register.rip.dwarfNum(), .off = -8 } },
2314 },
2315 };
2316 } else .{
2317 .format = .none,
2318 .code_alignment_factor = undefined,
2319 .data_alignment_factor = undefined,
2320 .return_address_register = undefined,
2321 .initial_instructions = &.{},
2322 },
2323 .section = Section.init,
2324 },
2325 .debug_info = .{ .section = Section.init },
2326 .debug_line = .{
2327 .header = switch (target.cpu.arch) {
2328 .x86_64, .aarch64 => .{
2329 .minimum_instruction_length = 1,
2330 .maximum_operations_per_instruction = 1,
2331 .default_is_stmt = true,
2332 .line_base = -5,
2333 .line_range = 14,
2334 .opcode_base = DW.LNS.set_isa + 1,
2335 },
2336 else => .{
2337 .minimum_instruction_length = 1,
2338 .maximum_operations_per_instruction = 1,
2339 .default_is_stmt = true,
2340 .line_base = 0,
2341 .line_range = 1,
2342 .opcode_base = DW.LNS.set_isa + 1,
2343 },
2344 },
2345 .section = Section.init,
2346 },
2347 .debug_line_str = StringSection.init,
2348 .debug_loclists = .{ .section = Section.init },
2349 .debug_rnglists = .{ .section = Section.init },
2350 .debug_str = StringSection.init,
2351 };
2352}
2353
2354pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
2355 if (dwarf.bin_file.cast(.macho)) |macho_file| {
2356 if (macho_file.d_sym) |*d_sym| {
2357 for ([_]*Section{
2358 &dwarf.debug_abbrev.section,
2359 &dwarf.debug_aranges.section,
2360 &dwarf.debug_info.section,
2361 &dwarf.debug_line.section,
2362 &dwarf.debug_line_str.section,
2363 &dwarf.debug_loclists.section,
2364 &dwarf.debug_rnglists.section,
2365 &dwarf.debug_str.section,
2366 }, [_]u8{
2367 d_sym.debug_abbrev_section_index.?,
2368 d_sym.debug_aranges_section_index.?,
2369 d_sym.debug_info_section_index.?,
2370 d_sym.debug_line_section_index.?,
2371 d_sym.debug_line_str_section_index.?,
2372 d_sym.debug_loclists_section_index.?,
2373 d_sym.debug_rnglists_section_index.?,
2374 d_sym.debug_str_section_index.?,
2375 }) |sec, sect_index| {
2376 const header = &d_sym.sections.items[sect_index];
2377 sec.index = sect_index;
2378 sec.len = header.size;
2379 }
2380 } else {
2381 for ([_]*Section{
2382 &dwarf.debug_abbrev.section,
2383 &dwarf.debug_aranges.section,
2384 &dwarf.debug_info.section,
2385 &dwarf.debug_line.section,
2386 &dwarf.debug_line_str.section,
2387 &dwarf.debug_loclists.section,
2388 &dwarf.debug_rnglists.section,
2389 &dwarf.debug_str.section,
2390 }, [_]u8{
2391 macho_file.debug_abbrev_sect_index.?,
2392 macho_file.debug_aranges_sect_index.?,
2393 macho_file.debug_info_sect_index.?,
2394 macho_file.debug_line_sect_index.?,
2395 macho_file.debug_line_str_sect_index.?,
2396 macho_file.debug_loclists_sect_index.?,
2397 macho_file.debug_rnglists_sect_index.?,
2398 macho_file.debug_str_sect_index.?,
2399 }) |sec, sect_index| {
2400 const header = &macho_file.sections.items(.header)[sect_index];
2401 sec.index = sect_index;
2402 sec.len = header.size;
2403 }
2404 }
2405 }
2406}
2407
2408pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
2409 if (dwarf.bin_file.cast(.elf)) |elf_file| {
2410 const zo = elf_file.zigObjectPtr().?;
2411 for ([_]*Section{
2412 &dwarf.debug_abbrev.section,
2413 &dwarf.debug_aranges.section,
2414 &dwarf.debug_frame.section,
2415 &dwarf.debug_info.section,
2416 &dwarf.debug_line.section,
2417 &dwarf.debug_line_str.section,
2418 &dwarf.debug_loclists.section,
2419 &dwarf.debug_rnglists.section,
2420 &dwarf.debug_str.section,
2421 }, [_]u32{
2422 zo.debug_abbrev_index.?,
2423 zo.debug_aranges_index.?,
2424 zo.eh_frame_index.?,
2425 zo.debug_info_index.?,
2426 zo.debug_line_index.?,
2427 zo.debug_line_str_index.?,
2428 zo.debug_loclists_index.?,
2429 zo.debug_rnglists_index.?,
2430 zo.debug_str_index.?,
2431 }) |sec, sym_index| {
2432 sec.index = sym_index;
2433 }
2434 }
2435 dwarf.reloadSectionMetadata();
2436
2437 dwarf.debug_abbrev.section.pad_entries_to_ideal = false;
2438 assert(try dwarf.debug_abbrev.section.addUnit(DebugAbbrev.header_bytes, DebugAbbrev.trailer_bytes, dwarf) == DebugAbbrev.unit);
2439 errdefer dwarf.debug_abbrev.section.popUnit(dwarf.gpa);
2440 for (std.enums.values(AbbrevCode)) |abbrev_code|
2441 assert(@backingInt(try dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).addEntry(dwarf.gpa)) == @backingInt(abbrev_code));
2442
2443 dwarf.debug_aranges.section.pad_entries_to_ideal = false;
2444 dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@backingInt(dwarf.address_size) * 2);
2445
2446 dwarf.debug_frame.section.alignment = switch (dwarf.debug_frame.header.format) {
2447 .none => .@"1",
2448 .debug_frame => InternPool.Alignment.fromNonzeroByteUnits(@backingInt(dwarf.address_size)),
2449 .eh_frame => .@"4",
2450 };
2451
2452 dwarf.debug_line_str.section.pad_entries_to_ideal = false;
2453 assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
2454 errdefer dwarf.debug_line_str.section.popUnit(dwarf.gpa);
2455
2456 dwarf.debug_str.section.pad_entries_to_ideal = false;
2457 assert(try dwarf.debug_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
2458 errdefer dwarf.debug_str.section.popUnit(dwarf.gpa);
2459
2460 dwarf.debug_loclists.section.pad_entries_to_ideal = false;
2461
2462 dwarf.debug_rnglists.section.pad_entries_to_ideal = false;
2463}
2464
2465pub fn deinit(dwarf: *Dwarf) void {
2466 const gpa = dwarf.gpa;
2467 dwarf.const_pool.deinit(gpa);
2468 for (dwarf.mods.values()) |*mod_info| mod_info.deinit(gpa);
2469 dwarf.mods.deinit(gpa);
2470 dwarf.values.deinit(gpa);
2471 dwarf.navs.deinit(gpa);
2472 dwarf.decls.deinit(gpa);
2473 dwarf.debug_abbrev.section.deinit(gpa);
2474 dwarf.debug_aranges.section.deinit(gpa);
2475 dwarf.debug_frame.section.deinit(gpa);
2476 dwarf.debug_info.section.deinit(gpa);
2477 dwarf.debug_line.section.deinit(gpa);
2478 dwarf.debug_line_str.deinit(gpa);
2479 dwarf.debug_loclists.section.deinit(gpa);
2480 dwarf.debug_rnglists.section.deinit(gpa);
2481 dwarf.debug_str.deinit(gpa);
2482 dwarf.* = undefined;
2483}
2484
2485fn getNavEntry(
2486 dwarf: *Dwarf,
2487 nav_index: InternPool.Nav.Index,
2488) UpdateError!struct { Unit.Index, Entry.Index } {
2489 const zcu = dwarf.bin_file.comp.zcu.?;
2490 const ip = &zcu.intern_pool;
2491 const nav = ip.getNav(nav_index);
2492 const unit = try dwarf.getUnit(zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?);
2493 const gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
2494 if (gop.found_existing) return .{ unit, gop.value_ptr.* };
2495 const entry = try dwarf.addCommonEntry(unit);
2496 gop.value_ptr.* = entry;
2497 return .{ unit, entry };
2498}
2499
2500fn getUnit(dwarf: *Dwarf, mod: *Module) !Unit.Index {
2501 const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod);
2502 const unit: Unit.Index = @fromBackingInt(@intCast(mod_gop.index));
2503 if (!mod_gop.found_existing) {
2504 errdefer _ = dwarf.mods.pop();
2505 mod_gop.value_ptr.* = .{
2506 .root_dir_path = undefined,
2507 .dirs = .empty,
2508 .files = .empty,
2509 };
2510 errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa);
2511 try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {});
2512 assert(try dwarf.debug_aranges.section.addUnit(
2513 DebugAranges.headerBytes(dwarf),
2514 DebugAranges.trailerBytes(dwarf),
2515 dwarf,
2516 ) == unit);
2517 errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa);
2518 assert(try dwarf.debug_frame.section.addUnit(
2519 DebugFrame.headerBytes(dwarf),
2520 DebugFrame.trailerBytes(dwarf),
2521 dwarf,
2522 ) == unit);
2523 errdefer dwarf.debug_frame.section.popUnit(dwarf.gpa);
2524 assert(try dwarf.debug_info.section.addUnit(
2525 DebugInfo.headerBytes(dwarf),
2526 DebugInfo.trailer_bytes,
2527 dwarf,
2528 ) == unit);
2529 errdefer dwarf.debug_info.section.popUnit(dwarf.gpa);
2530 assert(try dwarf.debug_line.section.addUnit(
2531 DebugLine.headerBytes(dwarf, 5, 25),
2532 DebugLine.trailer_bytes,
2533 dwarf,
2534 ) == unit);
2535 errdefer dwarf.debug_line.section.popUnit(dwarf.gpa);
2536 assert(try dwarf.debug_loclists.section.addUnit(
2537 DebugLocLists.headerBytes(dwarf),
2538 DebugLocLists.trailer_bytes,
2539 dwarf,
2540 ) == unit);
2541 errdefer dwarf.debug_loclists.section.popUnit(dwarf.gpa);
2542 assert(try dwarf.debug_rnglists.section.addUnit(
2543 DebugRngLists.headerBytes(dwarf),
2544 DebugRngLists.trailer_bytes,
2545 dwarf,
2546 ) == unit);
2547 errdefer dwarf.debug_rnglists.section.popUnit(dwarf.gpa);
2548 }
2549 return unit;
2550}
2551
2552fn getUnitIfExists(dwarf: *const Dwarf, mod: *Module) ?Unit.Index {
2553 return @fromBackingInt(@intCast(dwarf.mods.getIndex(mod) orelse return null));
2554}
2555
2556fn getModInfo(dwarf: *Dwarf, unit: Unit.Index) *ModInfo {
2557 return &dwarf.mods.values()[@backingInt(unit)];
2558}
2559
2560fn getUnitModule(dwarf: *Dwarf, unit: Unit.Index) *Module {
2561 return dwarf.mods.keys()[@backingInt(unit)];
2562}
2563
2564pub fn initWipNav(
2565 dwarf: *Dwarf,
2566 pt: Zcu.PerThread,
2567 nav_index: InternPool.Nav.Index,
2568 sym_index: link.File.SymbolId,
2569) error{ OutOfMemory, AlreadyReported }!WipNav {
2570 return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) {
2571 error.OutOfMemory => error.OutOfMemory,
2572 else => |e| pt.zcu.codegenFail(nav_index, "failed to init dwarf: {s}", .{@errorName(e)}),
2573 };
2574}
2575
2576fn initWipNavInner(
2577 dwarf: *Dwarf,
2578 pt: Zcu.PerThread,
2579 nav_index: InternPool.Nav.Index,
2580 sym_index: link.File.SymbolId,
2581) !WipNav {
2582 const zcu = pt.zcu;
2583 const ip = &zcu.intern_pool;
2584
2585 const nav = ip.getNav(nav_index);
2586 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
2587 const file = zcu.fileByIndex(inst_info.file);
2588 const decl = file.zir.?.getDeclaration(inst_info.inst);
2589 log.debug("initWipNav({s}:{d}:{d} %{d} = {f})", .{
2590 file.sub_file_path,
2591 decl.src_line + 1,
2592 decl.src_column + 1,
2593 @backingInt(inst_info.inst),
2594 nav.fqn.fmt(ip),
2595 });
2596
2597 const mod = file.mod.?;
2598 const unit = try dwarf.getUnit(mod);
2599 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
2600 errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
2601 if (nav_gop.found_existing) {
2602 for ([_]*Section{
2603 &dwarf.debug_aranges.section,
2604 &dwarf.debug_info.section,
2605 &dwarf.debug_line.section,
2606 &dwarf.debug_loclists.section,
2607 &dwarf.debug_rnglists.section,
2608 }) |sec| sec.getUnit(unit).getEntry(nav_gop.value_ptr.*).clear();
2609 } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2610 var wip_nav: WipNav = .{
2611 .dwarf = dwarf,
2612 .pt = pt,
2613 .unit = unit,
2614 .entry = nav_gop.value_ptr.*,
2615 .any_children = false,
2616 .func = .none,
2617 .func_sym_index = undefined,
2618 .func_high_pc = undefined,
2619 .blocks = undefined,
2620 .cfi = undefined,
2621 .debug_frame = .init(dwarf.gpa),
2622 .debug_info = .init(dwarf.gpa),
2623 .debug_line = .init(dwarf.gpa),
2624 .debug_loclists = .init(dwarf.gpa),
2625 };
2626 errdefer wip_nav.deinit();
2627
2628 const nav_val = zcu.navValue(nav_index);
2629 nav_val: switch (ip.indexToKey(nav_val.toIntern())) {
2630 .@"extern" => |@"extern"| switch (@"extern".source) {
2631 .builtin => {
2632 const maybe_func_type = switch (ip.indexToKey(@"extern".ty)) {
2633 .func_type => |func_type| func_type,
2634 else => null,
2635 };
2636 const diw = &wip_nav.debug_info.writer;
2637 try wip_nav.abbrevCode(if (maybe_func_type) |func_type|
2638 if (func_type.param_types.len > 0 or func_type.is_var_args) .builtin_extern_func else .builtin_extern_nullary_func
2639 else
2640 .builtin_extern_var);
2641 try wip_nav.refType(.fromInterned(zcu.fileRootType(inst_info.file)));
2642 try wip_nav.strp(@"extern".name.toSlice(ip));
2643 try wip_nav.refType(.fromInterned(if (maybe_func_type) |func_type| func_type.return_type else @"extern".ty));
2644 if (maybe_func_type) |func_type| {
2645 try wip_nav.infoAddrSym(sym_index, 0);
2646 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
2647 if (func_type.param_types.len > 0 or func_type.is_var_args) {
2648 for (func_type.param_types.get(ip)) |param_type| {
2649 try wip_nav.abbrevCode(.extern_param);
2650 try wip_nav.refType(.fromInterned(param_type));
2651 }
2652 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
2653 try diw.writeUleb128(@backingInt(AbbrevCode.null));
2654 }
2655 } else try wip_nav.infoExprLoc(.{ .addr_reloc = sym_index });
2656 },
2657 .syntax => switch (ip.isFunctionType(@"extern".ty)) {
2658 false => continue :nav_val .{ .undef = @"extern".ty },
2659 true => {
2660 const func_type = ip.indexToKey(@"extern".ty).func_type;
2661 const diw = &wip_nav.debug_info.writer;
2662 try wip_nav.declCommon(if (func_type.param_types.len > 0 or func_type.is_var_args) .{
2663 .decl = .decl_extern_func,
2664 .generic_decl = .generic_decl_func,
2665 .decl_instance = .decl_instance_extern_func,
2666 } else .{
2667 .decl = .decl_extern_nullary_func,
2668 .generic_decl = .generic_decl_func,
2669 .decl_instance = .decl_instance_extern_nullary_func,
2670 }, &nav, inst_info.file, &decl);
2671 try wip_nav.strp(@"extern".name.toSlice(ip));
2672 try wip_nav.refType(.fromInterned(func_type.return_type));
2673 try wip_nav.infoAddrSym(sym_index, 0);
2674 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
2675 if (func_type.param_types.len > 0 or func_type.is_var_args) {
2676 for (func_type.param_types.get(ip)) |param_type| {
2677 try wip_nav.abbrevCode(.extern_param);
2678 try wip_nav.refType(.fromInterned(param_type));
2679 }
2680 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
2681 try diw.writeUleb128(@backingInt(AbbrevCode.null));
2682 }
2683 },
2684 },
2685 },
2686 .func => |func| if (func.owner_nav != nav_index) {
2687 try wip_nav.declCommon(.{
2688 .decl = .decl_alias,
2689 .generic_decl = .generic_decl_const,
2690 .decl_instance = .decl_instance_alias,
2691 }, &nav, inst_info.file, &decl);
2692 try wip_nav.refNav(func.owner_nav);
2693 } else {
2694 const func_type = ip.indexToKey(func.ty).func_type;
2695 wip_nav.func = nav_val.toIntern();
2696 wip_nav.func_sym_index = sym_index;
2697 wip_nav.blocks = .empty;
2698 if (dwarf.debug_frame.header.format != .none) wip_nav.cfi = .{
2699 .loc = 0,
2700 .cfa = dwarf.debug_frame.header.initial_instructions[0].def_cfa,
2701 };
2702
2703 switch (dwarf.debug_frame.header.format) {
2704 .none => {},
2705 .debug_frame, .eh_frame => |format| {
2706 const entry = dwarf.debug_frame.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry);
2707 const dfw = &wip_nav.debug_frame.writer;
2708 switch (dwarf.format) {
2709 .@"32" => try dfw.writeInt(u32, undefined, dwarf.endian),
2710 .@"64" => {
2711 try dfw.writeInt(u32, std.math.maxInt(u32), dwarf.endian);
2712 try dfw.writeInt(u64, undefined, dwarf.endian);
2713 },
2714 }
2715 switch (format) {
2716 .none => unreachable,
2717 .debug_frame => {
2718 try entry.cross_entry_relocs.append(dwarf.gpa, .{
2719 .source_off = @intCast(dfw.end),
2720 });
2721 try dfw.splatByteAll(0, dwarf.sectionOffsetBytes());
2722 try wip_nav.frameAddrSym(sym_index, 0);
2723 try dfw.splatByteAll(undefined, @backingInt(dwarf.address_size));
2724 },
2725 .eh_frame => {
2726 try dfw.writeInt(u32, undefined, dwarf.endian);
2727 try wip_nav.frameExternalReloc(.{
2728 .source_off = @intCast(dfw.end),
2729 .target_sym = sym_index,
2730 });
2731 try dfw.writeInt(u32, 0, dwarf.endian);
2732 try dfw.writeInt(u32, undefined, dwarf.endian);
2733 try dfw.writeUleb128(0);
2734 },
2735 }
2736 },
2737 }
2738
2739 const diw = &wip_nav.debug_info.writer;
2740 try wip_nav.declCommon(.{
2741 .decl = .decl_func,
2742 .generic_decl = .generic_decl_func,
2743 .decl_instance = .decl_instance_func,
2744 }, &nav, inst_info.file, &decl);
2745 try wip_nav.strp(switch (decl.linkage) {
2746 .normal => nav.fqn,
2747 .@"extern", .@"export" => nav.name,
2748 }.toSlice(ip));
2749 try wip_nav.refType(.fromInterned(func_type.return_type));
2750 try wip_nav.infoAddrSym(sym_index, 0);
2751 wip_nav.func_high_pc = @intCast(diw.end);
2752 try diw.writeInt(u32, 0, dwarf.endian);
2753 const target = &mod.resolved_target.result;
2754 try diw.writeUleb128(switch (nav.resolved.?.@"align") {
2755 .none => target_info.defaultFunctionAlignment(target),
2756 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
2757 }.toByteUnits().?);
2758 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2759 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
2760
2761 const dlw = &wip_nav.debug_line.writer;
2762 try dlw.writeByte(DW.LNS.extended_op);
2763 if (dwarf.incremental()) {
2764 try dlw.writeUleb128(1 + dwarf.sectionOffsetBytes());
2765 try dlw.writeByte(DW.LNE.ZIG_set_decl);
2766 try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{
2767 .source_off = @intCast(dlw.end),
2768 .target_sec = .debug_info,
2769 .target_unit = wip_nav.unit,
2770 .target_entry = wip_nav.entry.toOptional(),
2771 });
2772 try dlw.splatByteAll(0, dwarf.sectionOffsetBytes());
2773
2774 try dlw.writeByte(DW.LNS.set_column);
2775 try dlw.writeUleb128(func.lbrace_column + 1);
2776
2777 try wip_nav.advancePCAndLine(func.lbrace_line, 0);
2778 } else {
2779 try dlw.writeUleb128(1 + @backingInt(dwarf.address_size));
2780 try dlw.writeByte(DW.LNE.set_address);
2781 try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
2782 .source_off = @intCast(dlw.end),
2783 .target_sym = sym_index,
2784 });
2785 try dlw.splatByteAll(0, @backingInt(dwarf.address_size));
2786
2787 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
2788 try dlw.writeByte(DW.LNS.set_file);
2789 try dlw.writeUleb128(file_gop.index);
2790
2791 try dlw.writeByte(DW.LNS.set_column);
2792 try dlw.writeUleb128(func.lbrace_column + 1);
2793
2794 try wip_nav.advancePCAndLine(@intCast(decl.src_line + func.lbrace_line), 0);
2795 }
2796 },
2797 else => {
2798 const diw = &wip_nav.debug_info.writer;
2799 try wip_nav.declCommon(.{
2800 .decl = .decl_var,
2801 .generic_decl = switch (decl.kind) {
2802 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
2803 .@"const" => .generic_decl_const,
2804 .@"var" => .generic_decl_var,
2805 },
2806 .decl_instance = .decl_instance_var,
2807 }, &nav, inst_info.file, &decl);
2808 try wip_nav.strp(switch (decl.linkage) {
2809 .normal => nav.fqn,
2810 .@"extern", .@"export" => nav.name,
2811 }.toSlice(ip));
2812 const ty: Type = nav_val.typeOf(zcu);
2813 const addr: Loc = .{ .addr_reloc = sym_index };
2814 const loc: Loc = if (decl.is_threadlocal) loc: {
2815 const target = zcu.comp.root_mod.resolved_target.result;
2816 break :loc switch (target.cpu.arch) {
2817 .x86_64 => .{ .form_tls_address = &addr },
2818 else => .empty,
2819 };
2820 } else addr;
2821 switch (decl.kind) {
2822 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
2823 .@"const" => {
2824 const const_ty_reloc_index = try wip_nav.refForward();
2825 try wip_nav.infoExprLoc(loc);
2826 try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse
2827 ty.abiAlignment(zcu).toByteUnits().?);
2828 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2829 wip_nav.finishForward(const_ty_reloc_index);
2830 try wip_nav.abbrevCode(.is_const);
2831 try wip_nav.refType(ty);
2832 },
2833 .@"var" => {
2834 try wip_nav.refType(ty);
2835 try wip_nav.infoExprLoc(loc);
2836 try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse
2837 ty.abiAlignment(zcu).toByteUnits().?);
2838 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2839 },
2840 }
2841 },
2842 }
2843 return wip_nav;
2844}
2845
2846pub fn finishWipNavFunc(
2847 dwarf: *Dwarf,
2848 pt: Zcu.PerThread,
2849 nav_index: InternPool.Nav.Index,
2850 code_size: u64,
2851 wip_nav: *WipNav,
2852) UpdateError!void {
2853 return dwarf.finishWipNavFuncWriterError(pt, nav_index, code_size, wip_nav) catch |err| switch (err) {
2854 error.WriteFailed => error.OutOfMemory,
2855 else => |e| e,
2856 };
2857}
2858fn finishWipNavFuncWriterError(
2859 dwarf: *Dwarf,
2860 pt: Zcu.PerThread,
2861 nav_index: InternPool.Nav.Index,
2862 code_size: u64,
2863 wip_nav: *WipNav,
2864) (UpdateError || Writer.Error)!void {
2865 const zcu = pt.zcu;
2866 const ip = &zcu.intern_pool;
2867 const nav = ip.getNav(nav_index);
2868 assert(wip_nav.func != .none);
2869 log.debug("finishWipNavFunc({f})", .{nav.fqn.fmt(ip)});
2870
2871 {
2872 const external_relocs = &dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
2873 try external_relocs.append(dwarf.gpa, .{ .target_sym = wip_nav.func_sym_index });
2874 var entry: [8 + 8]u8 = undefined;
2875 @memset(entry[0..@backingInt(dwarf.address_size)], 0);
2876 dwarf.writeInt(entry[@backingInt(dwarf.address_size)..][0..@backingInt(dwarf.address_size)], code_size);
2877 try dwarf.debug_aranges.section.replaceEntry(
2878 wip_nav.unit,
2879 wip_nav.entry,
2880 dwarf,
2881 entry[0 .. @backingInt(dwarf.address_size) * 2],
2882 );
2883 }
2884 switch (dwarf.debug_frame.header.format) {
2885 .none => {},
2886 .debug_frame, .eh_frame => |format| {
2887 const dfw = &wip_nav.debug_frame.writer;
2888 try dfw.splatByteAll(
2889 DW.CFA.nop,
2890 @intCast(dwarf.debug_frame.section.alignment.forward(dfw.end) - dfw.end),
2891 );
2892 const contents = wip_nav.debug_frame.written();
2893 try dwarf.debug_frame.section.resizeEntry(wip_nav.unit, wip_nav.entry, dwarf, @intCast(contents.len));
2894 const unit = dwarf.debug_frame.section.getUnit(wip_nav.unit);
2895 const entry = unit.getEntry(wip_nav.entry);
2896 const unit_len = (if (entry.next.unwrap()) |next_entry|
2897 unit.getEntry(next_entry).off - entry.off
2898 else
2899 entry.len) - dwarf.unitLengthBytes();
2900 dwarf.writeInt(contents[dwarf.unitLengthBytes() - dwarf.sectionOffsetBytes() ..][0..dwarf.sectionOffsetBytes()], unit_len);
2901 switch (format) {
2902 .none => unreachable,
2903 .debug_frame => dwarf.writeInt(contents[dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() +
2904 @backingInt(dwarf.address_size) ..][0..@backingInt(dwarf.address_size)], code_size),
2905 .eh_frame => {
2906 std.mem.writeInt(
2907 u32,
2908 contents[dwarf.unitLengthBytes()..][0..4],
2909 unit.header_len + entry.off + dwarf.unitLengthBytes(),
2910 dwarf.endian,
2911 );
2912 std.mem.writeInt(u32, contents[dwarf.unitLengthBytes() + 4 + 4 ..][0..4], @intCast(code_size), dwarf.endian);
2913 },
2914 }
2915 try entry.replace(unit, &dwarf.debug_frame.section, dwarf, contents);
2916 },
2917 }
2918 {
2919 std.mem.writeInt(u32, wip_nav.debug_info.written()[wip_nav.func_high_pc..][0..4], @intCast(code_size), dwarf.endian);
2920 if (wip_nav.any_children) {
2921 const diw = &wip_nav.debug_info.writer;
2922 try diw.writeUleb128(@backingInt(AbbrevCode.null));
2923 } else {
2924 const abbrev_code_buf = wip_nav.debug_info.written()[0..AbbrevCode.decl_bytes];
2925 var abbrev_code_fr: std.Io.Reader = .fixed(abbrev_code_buf);
2926 const abbrev_code: AbbrevCode = @fromBackingInt(@intCast(
2927 abbrev_code_fr.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable,
2928 ));
2929 std.leb.writeUnsignedFixed(
2930 AbbrevCode.decl_bytes,
2931 abbrev_code_buf,
2932 @intCast(try dwarf.refAbbrevCode(switch (abbrev_code) {
2933 else => unreachable,
2934 .decl_func => .decl_nullary_func,
2935 .decl_instance_func => .decl_instance_nullary_func,
2936 })),
2937 );
2938 }
2939 }
2940 {
2941 try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.appendSlice(dwarf.gpa, &.{
2942 .{
2943 .source_off = 1,
2944 .target_sym = wip_nav.func_sym_index,
2945 },
2946 .{
2947 .source_off = 1 + @backingInt(dwarf.address_size),
2948 .target_sym = wip_nav.func_sym_index,
2949 .target_off = code_size,
2950 },
2951 });
2952 try dwarf.debug_rnglists.section.replaceEntry(
2953 wip_nav.unit,
2954 wip_nav.entry,
2955 dwarf,
2956 ([1]u8{DW.RLE.start_end} ++ @as([8 + 8]u8, @splat(0)))[0 .. 1 + @backingInt(dwarf.address_size) + @backingInt(dwarf.address_size)],
2957 );
2958 }
2959
2960 try dwarf.finishWipNav(pt, nav_index, wip_nav);
2961}
2962
2963pub fn finishWipNav(
2964 dwarf: *Dwarf,
2965 pt: Zcu.PerThread,
2966 nav_index: InternPool.Nav.Index,
2967 wip_nav: *WipNav,
2968) UpdateError!void {
2969 return dwarf.finishWipNavWriterError(pt, nav_index, wip_nav) catch |err| switch (err) {
2970 error.WriteFailed => error.OutOfMemory,
2971 else => |e| e,
2972 };
2973}
2974fn finishWipNavWriterError(
2975 dwarf: *Dwarf,
2976 pt: Zcu.PerThread,
2977 nav_index: InternPool.Nav.Index,
2978 wip_nav: *WipNav,
2979) (UpdateError || Writer.Error)!void {
2980 const zcu = pt.zcu;
2981 const ip = &zcu.intern_pool;
2982 const nav = ip.getNav(nav_index);
2983 log.debug("finishWipNav({f})", .{nav.fqn.fmt(ip)});
2984
2985 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
2986 const dlw = &wip_nav.debug_line.writer;
2987 if (dlw.end > 0) {
2988 try dlw.writeByte(DW.LNS.extended_op);
2989 try dlw.writeUleb128(1);
2990 try dlw.writeByte(DW.LNE.end_sequence);
2991 try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.written());
2992 }
2993 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written());
2994
2995 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
2996}
2997
2998pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error{ OutOfMemory, AlreadyReported }!void {
2999 return updateComptimeNavInner(dwarf, pt, nav_index) catch |err| switch (err) {
3000 error.OutOfMemory => error.OutOfMemory,
3001 else => |e| pt.zcu.codegenFail(nav_index, "failed to update dwarf: {s}", .{@errorName(e)}),
3002 };
3003}
3004
3005fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
3006 const zcu = pt.zcu;
3007 const ip = &zcu.intern_pool;
3008
3009 const nav = ip.getNav(nav_index);
3010 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
3011 const nav_val: Value = .fromInterned(nav.resolved.?.value);
3012 const file = zcu.fileByIndex(inst_info.file);
3013 const decl = file.zir.?.getDeclaration(inst_info.inst);
3014 log.debug("updateComptimeNav({s}:{d}:{d} %{d} = {f})", .{
3015 file.sub_file_path,
3016 decl.src_line + 1,
3017 decl.src_column + 1,
3018 @backingInt(inst_info.inst),
3019 nav.fqn.fmt(ip),
3020 });
3021
3022 const is_test = switch (decl.kind) {
3023 .unnamed_test, .@"test", .decltest => true,
3024 .@"comptime", .@"const", .@"var" => false,
3025 };
3026 if (is_test) {
3027 // This isn't actually a comptime Nav! It's a test, so it'll definitely never be referenced at comptime.
3028 return;
3029 }
3030
3031 const tag: union(enum) {
3032 alias,
3033 @"var",
3034 @"const",
3035 func: Type,
3036 func_alias: InternPool.Nav.Index,
3037 } = switch (ip.indexToKey(nav_val.toIntern())) {
3038 .int_type,
3039 .ptr_type,
3040 .array_type,
3041 .vector_type,
3042 .opt_type,
3043 .error_union_type,
3044 .anyframe_type,
3045 .simple_type,
3046 .tuple_type,
3047 .func_type,
3048 .error_set_type,
3049 .inferred_error_set_type,
3050 .spirv_type,
3051 => .alias,
3052
3053 .struct_type => tag: {
3054 const loaded_struct = ip.loadStructType(nav_val.toIntern());
3055 if (nav_index.toOptional() == loaded_struct.name_nav) {
3056 // This Nav's entry is populated by the type, not the actual Nav.
3057 _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());
3058 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
3059 return;
3060 }
3061 break :tag .alias;
3062 },
3063 .enum_type => tag: {
3064 const loaded_enum = ip.loadEnumType(nav_val.toIntern());
3065 if (nav_index.toOptional() == loaded_enum.name_nav) {
3066 // This Nav's entry is populated by the type, not the actual Nav.
3067 _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());
3068 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
3069 return;
3070 }
3071 break :tag .alias;
3072 },
3073 .union_type => tag: {
3074 const loaded_union = ip.loadUnionType(nav_val.toIntern());
3075 if (nav_index.toOptional() == loaded_union.name_nav) {
3076 // This Nav's entry is populated by the type, not the actual Nav.
3077 _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());
3078 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
3079 return;
3080 }
3081 break :tag .alias;
3082 },
3083 .opaque_type => tag: {
3084 const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
3085 if (nav_index.toOptional() == loaded_opaque.name_nav) {
3086 // This Nav's entry is populated by the type, not the actual Nav.
3087 _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());
3088 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
3089 return;
3090 }
3091 break :tag .alias;
3092 },
3093
3094 .undef,
3095 .simple_value,
3096 .int,
3097 .err,
3098 .error_union,
3099 .enum_literal,
3100 .enum_tag,
3101 .float,
3102 .ptr,
3103 .slice,
3104 .opt,
3105 .aggregate,
3106 .un,
3107 .bitpack,
3108 => if (nav.resolved.?.@"const") .@"const" else .@"var",
3109
3110 .@"extern" => unreachable,
3111
3112 .func => |func| tag: {
3113 if (func.owner_nav != nav_index) break :tag .{ .func_alias = func.owner_nav };
3114 break :tag .{ .func = .fromInterned(func.ty) };
3115 },
3116
3117 // memoization, not types
3118 .memoized_call => unreachable,
3119 };
3120
3121 const unit = try dwarf.getUnit(file.mod.?);
3122
3123 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
3124 errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
3125
3126 if (nav_gop.found_existing) {
3127 if (tag == .func) switch (try dwarf.debug_info.declAbbrevCode(unit, nav_gop.value_ptr.*)) {
3128 else => unreachable,
3129
3130 .decl_nullary_func,
3131 .decl_func,
3132 .decl_instance_nullary_func,
3133 .decl_instance_func,
3134 => return,
3135
3136 .null,
3137 .decl_nullary_func_generic,
3138 .decl_func_generic,
3139 .decl_instance_nullary_func_generic,
3140 .decl_instance_func_generic,
3141 => {},
3142 };
3143 dwarf.debug_info.section.getUnit(unit).getEntry(nav_gop.value_ptr.*).clear();
3144 } else {
3145 nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
3146 }
3147
3148 var wip_nav: WipNav = .{
3149 .dwarf = dwarf,
3150 .pt = pt,
3151 .unit = unit,
3152 .entry = nav_gop.value_ptr.*,
3153 .any_children = false,
3154 .func = .none,
3155 .func_sym_index = undefined,
3156 .func_high_pc = undefined,
3157 .blocks = undefined,
3158 .cfi = undefined,
3159 .debug_frame = .init(dwarf.gpa),
3160 .debug_info = .init(dwarf.gpa),
3161 .debug_line = .init(dwarf.gpa),
3162 .debug_loclists = .init(dwarf.gpa),
3163 };
3164 defer wip_nav.deinit();
3165 const diw = &wip_nav.debug_info.writer;
3166
3167 switch (tag) {
3168 .alias => {
3169 try wip_nav.declCommon(.{
3170 .decl = .decl_alias,
3171 .generic_decl = .generic_decl_const,
3172 .decl_instance = .decl_instance_alias,
3173 }, &nav, inst_info.file, &decl);
3174 try wip_nav.refType(nav_val.toType());
3175 },
3176 .@"var" => {
3177 try wip_nav.declCommon(.{
3178 .decl = .decl_var,
3179 .generic_decl = .generic_decl_var,
3180 .decl_instance = .decl_instance_var,
3181 }, &nav, inst_info.file, &decl);
3182 try wip_nav.strp(switch (decl.linkage) {
3183 .normal => nav.fqn,
3184 .@"extern", .@"export" => nav.name,
3185 }.toSlice(ip));
3186 const nav_ty = nav_val.typeOf(zcu);
3187 try wip_nav.refType(nav_ty);
3188 try wip_nav.blockValue(nav_val);
3189 try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse
3190 nav_ty.abiAlignment(zcu).toByteUnits().?);
3191 try diw.writeByte(@intFromBool(decl.linkage != .normal));
3192 },
3193 .@"const" => {
3194 const nav_ty = nav_val.typeOf(zcu);
3195 const has_runtime_bits = nav_ty.hasRuntimeBits(zcu);
3196 const has_comptime_state = nav_ty.comptimeOnly(zcu);
3197 try wip_nav.declCommon(if (has_runtime_bits and has_comptime_state) .{
3198 .decl = .decl_const_runtime_bits_comptime_state,
3199 .generic_decl = .generic_decl_const,
3200 .decl_instance = .decl_instance_const_runtime_bits_comptime_state,
3201 } else if (has_comptime_state) .{
3202 .decl = .decl_const_comptime_state,
3203 .generic_decl = .generic_decl_const,
3204 .decl_instance = .decl_instance_const_comptime_state,
3205 } else if (has_runtime_bits) .{
3206 .decl = .decl_const_runtime_bits,
3207 .generic_decl = .generic_decl_const,
3208 .decl_instance = .decl_instance_const_runtime_bits,
3209 } else .{
3210 .decl = .decl_const,
3211 .generic_decl = .generic_decl_const,
3212 .decl_instance = .decl_instance_const,
3213 }, &nav, inst_info.file, &decl);
3214 try wip_nav.strp(switch (decl.linkage) {
3215 .normal => nav.fqn,
3216 .@"extern", .@"export" => nav.name,
3217 }.toSlice(ip));
3218 const nav_ty_reloc_index = try wip_nav.refForward();
3219 try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse
3220 nav_ty.abiAlignment(zcu).toByteUnits().?);
3221 try diw.writeByte(@intFromBool(decl.linkage != .normal));
3222 if (has_runtime_bits) try wip_nav.blockValue(nav_val);
3223 if (has_comptime_state) try wip_nav.refValue(nav_val);
3224 wip_nav.finishForward(nav_ty_reloc_index);
3225 try wip_nav.abbrevCode(.is_const);
3226 try wip_nav.refType(nav_ty);
3227 },
3228 .func => |func_ty| {
3229 const func_type = ip.indexToKey(func_ty.toIntern()).func_type;
3230 const is_nullary = !func_type.is_var_args and for (0..func_type.param_types.len) |param_index| {
3231 if (!func_type.paramIsComptime(std.math.cast(u5, param_index) orelse break false)) break false;
3232 } else true;
3233 try wip_nav.declCommon(if (is_nullary) .{
3234 .decl = .decl_nullary_func_generic,
3235 .generic_decl = .generic_decl_func,
3236 .decl_instance = .decl_instance_nullary_func_generic,
3237 } else .{
3238 .decl = .decl_func_generic,
3239 .generic_decl = .generic_decl_func,
3240 .decl_instance = .decl_instance_func_generic,
3241 }, &nav, inst_info.file, &decl);
3242 try wip_nav.refType(.fromInterned(func_type.return_type));
3243 if (!is_nullary) {
3244 for (0..func_type.param_types.len) |param_index| {
3245 if (std.math.cast(u5, param_index)) |small_param_index|
3246 if (func_type.paramIsComptime(small_param_index)) continue;
3247 try wip_nav.abbrevCode(.func_type_param);
3248 try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
3249 }
3250 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
3251 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3252 }
3253 },
3254 .func_alias => |owner_nav| {
3255 try wip_nav.declCommon(.{
3256 .decl = .decl_alias,
3257 .generic_decl = .generic_decl_const,
3258 .decl_instance = .decl_instance_alias,
3259 }, &nav, inst_info.file, &decl);
3260 try wip_nav.refNav(owner_nav);
3261 },
3262 }
3263 try dwarf.debug_info.section.replaceEntry(unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
3264 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
3265}
3266
3267pub fn updateContainerType(
3268 dwarf: *Dwarf,
3269 pt: Zcu.PerThread,
3270 ty: InternPool.Index,
3271 success: bool,
3272) !void {
3273 try dwarf.const_pool.updateContainerType(pt, .{ .dwarf = dwarf }, ty, success);
3274}
3275/// Should only be called by the `link.ConstPool` implementation.
3276pub fn addConst(dwarf: *Dwarf, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
3277 addConstInner(dwarf, pt, index, val) catch |err| switch (err) {
3278 error.OutOfMemory => |e| return e,
3279 else => |e| std.debug.panic("DWARF TODO: '{t}' while registering constant\n", .{e}),
3280 };
3281}
3282fn addConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) !void {
3283 const zcu = pt.zcu;
3284 const ip = &zcu.intern_pool;
3285
3286 const unit: Unit.Index, const entry: Entry.Index = switch (ip.indexToKey(val)) {
3287 else => .{ .main, try dwarf.addCommonEntry(.main) },
3288 .func => |func| try dwarf.getNavEntry(func.owner_nav),
3289 .@"extern" => |@"extern"| try dwarf.getNavEntry(@"extern".owner_nav),
3290 .struct_type, .union_type, .enum_type, .opaque_type => |_, tag| entry: {
3291 const name_nav = switch (tag) {
3292 .struct_type => ip.loadStructType(val).name_nav,
3293 .union_type => ip.loadUnionType(val).name_nav,
3294 .enum_type => ip.loadEnumType(val).name_nav,
3295 .opaque_type => ip.loadOpaqueType(val).name_nav,
3296 else => unreachable,
3297 };
3298 if (name_nav.unwrap()) |nav| {
3299 break :entry try dwarf.getNavEntry(nav);
3300 } else {
3301 const zir_index = Type.fromInterned(val).typeDeclInstAllowGeneratedTag(zcu).?;
3302 const unit = try dwarf.getUnit(zcu.fileByIndex(zir_index.resolveFile(ip)).mod.?);
3303 break :entry .{ unit, try dwarf.addCommonEntry(unit) };
3304 }
3305 },
3306 };
3307
3308 assert(@backingInt(index) == dwarf.values.items.len);
3309 try dwarf.values.append(dwarf.gpa, .{ unit, entry });
3310}
3311/// Should only be called by the `link.ConstPool` implementation.
3312///
3313/// Emits a "dummy" DIE for the given comptime-only value (which may be a type). For types, this is
3314/// an opaque type. Otherwise, it is an undefined value of the value's type.
3315pub fn updateConstIncomplete(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) Allocator.Error!void {
3316 updateConstIncompleteInner(dwarf, pt, debug_const_index, value_index) catch |err| switch (err) {
3317 error.OutOfMemory => |e| return e,
3318 else => |e| std.debug.panic("DWARF TODO: '{t}' while updating incomplete constant\n", .{e}),
3319 };
3320}
3321fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) !void {
3322 const zcu = pt.zcu;
3323 const ip = &zcu.intern_pool;
3324
3325 const val: Value = .fromInterned(value_index);
3326
3327 switch (value_index) {
3328 .generic_poison_type => log.debug("updateValueIncomplete(anytype)", .{}),
3329 else => log.debug("updateValueIncomplete(@as({f}, {f}))", .{
3330 val.typeOf(zcu).fmt(pt),
3331 val.fmtValue(pt),
3332 }),
3333 }
3334
3335 const unit, const entry = dwarf.values.items[@backingInt(debug_const_index)];
3336
3337 for ([_]*Section{
3338 &dwarf.debug_aranges.section,
3339 &dwarf.debug_aranges.section,
3340 &dwarf.debug_info.section,
3341 &dwarf.debug_line.section,
3342 &dwarf.debug_loclists.section,
3343 &dwarf.debug_rnglists.section,
3344 }) |sec| sec.getUnit(unit).getEntry(entry).clear();
3345
3346 var wip_nav: WipNav = .{
3347 .dwarf = dwarf,
3348 .pt = pt,
3349 .unit = unit,
3350 .entry = entry,
3351 .any_children = false,
3352 .func = .none,
3353 .func_sym_index = undefined,
3354 .func_high_pc = undefined,
3355 .blocks = undefined,
3356 .cfi = undefined,
3357 .debug_frame = .init(dwarf.gpa),
3358 .debug_info = .init(dwarf.gpa),
3359 .debug_line = .init(dwarf.gpa),
3360 .debug_loclists = .init(dwarf.gpa),
3361 };
3362 defer wip_nav.deinit();
3363
3364 switch (ip.indexToKey(value_index)) {
3365 // Container types still need to be valid namespaces.
3366 .struct_type => {
3367 const loaded_struct = ip.loadStructType(value_index);
3368 const root_of_file: ?Zcu.File.Index = if (loaded_struct.zir_index.resolveFull(ip)) |r| f: {
3369 if (r.inst != .main_struct_inst) break :f null;
3370 break :f r.file;
3371 } else null;
3372 if (root_of_file) |file_index| {
3373 assert(loaded_struct.name_nav == .none);
3374 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file_index);
3375 try wip_nav.abbrevCode(.empty_file);
3376 try wip_nav.debug_info.writer.writeUleb128(file_gop.index);
3377 try wip_nav.strp(loaded_struct.name.toSlice(ip));
3378 } else {
3379 try dwarf.emitIncompleteContainerType(
3380 &wip_nav,
3381 loaded_struct.zir_index,
3382 loaded_struct.name,
3383 loaded_struct.name_nav,
3384 );
3385 }
3386 },
3387 .union_type => {
3388 const loaded_union = ip.loadUnionType(value_index);
3389 try dwarf.emitIncompleteContainerType(
3390 &wip_nav,
3391 loaded_union.zir_index,
3392 loaded_union.name,
3393 loaded_union.name_nav,
3394 );
3395 },
3396 .enum_type => {
3397 const loaded_enum = ip.loadEnumType(value_index);
3398 if (loaded_enum.zir_index.unwrap()) |zir_index| {
3399 try dwarf.emitIncompleteContainerType(
3400 &wip_nav,
3401 zir_index,
3402 loaded_enum.name,
3403 loaded_enum.name_nav,
3404 );
3405 } else {
3406 try wip_nav.abbrevCode(.generated_empty_struct_type);
3407 try wip_nav.strp(loaded_enum.name.toSlice(ip));
3408 try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
3409 }
3410 },
3411 .opaque_type => {
3412 const loaded_opaque = ip.loadOpaqueType(value_index);
3413 try dwarf.emitIncompleteContainerType(
3414 &wip_nav,
3415 loaded_opaque.zir_index,
3416 loaded_opaque.name,
3417 loaded_opaque.name_nav,
3418 );
3419 },
3420 // Not a container type, so just emit a dummy entry. If `val` happens to be a type, we'll
3421 // emit it as if it were an opaque type so that we can name it.
3422 else => |val_key| switch (val_key.typeOf()) {
3423 .type_type => {
3424 try wip_nav.abbrevCode(.generated_empty_struct_type);
3425 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3426 try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
3427 },
3428 else => |ty| {
3429 try wip_nav.abbrevCode(.undefined_comptime_value);
3430 try wip_nav.refType(.fromInterned(ty));
3431 },
3432 },
3433 }
3434 try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written());
3435 try dwarf.debug_loclists.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_loclists.written());
3436}
3437fn emitIncompleteContainerType(
3438 dwarf: *Dwarf,
3439 wip_nav: *WipNav,
3440 zir_index: InternPool.TrackedInst.Index,
3441 name: InternPool.NullTerminatedString,
3442 name_nav: InternPool.Nav.Index.Optional,
3443) !void {
3444 const zcu = wip_nav.pt.zcu;
3445 const ip = &zcu.intern_pool;
3446 const file = zir_index.resolveFile(ip);
3447 if (name_nav.unwrap()) |nav_index| {
3448 const nav = ip.getNav(nav_index);
3449 const decl_inst = nav.srcInst(ip).resolve(ip).?;
3450 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
3451 try wip_nav.declCommon(.{
3452 .decl = .decl_namespace_struct,
3453 .generic_decl = .generic_decl_const,
3454 .decl_instance = .decl_instance_namespace_struct,
3455 }, &nav, file, &decl);
3456 try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
3457 } else {
3458 const diw = &wip_nav.debug_info.writer;
3459 const file_gop = try dwarf.getModInfo(wip_nav.unit).files.getOrPut(dwarf.gpa, file);
3460 try wip_nav.abbrevCode(.empty_struct_type);
3461 try diw.writeUleb128(file_gop.index);
3462 try wip_nav.strp(name.toSlice(ip));
3463 try diw.writeByte(@intFromBool(true));
3464 }
3465}
3466/// Should only be called by the `link.ConstPool` implementation.
3467///
3468/// Emits a DIE for the given comptime-only value (which may be a type).
3469pub fn updateConst(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) Allocator.Error!void {
3470 updateConstInner(dwarf, pt, debug_const_index, value_index) catch |err| switch (err) {
3471 error.OutOfMemory => |e| return e,
3472 else => |e| std.debug.panic("DWARF TODO: '{t}' while updating constant\n", .{e}),
3473 };
3474}
3475fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) !void {
3476 const zcu = pt.zcu;
3477 const ip = &zcu.intern_pool;
3478
3479 const val: Value = .fromInterned(value_index);
3480
3481 if (val.typeOf(zcu).toIntern() == .type_type and !val.isUndef(zcu)) {
3482 val.toType().assertHasLayout(zcu);
3483 } else {
3484 val.typeOf(zcu).assertHasLayout(zcu);
3485 }
3486
3487 if (value_index == .anyerror_type) return; // handled in `flush` instead
3488
3489 const value_ip_key = ip.indexToKey(value_index);
3490 switch (value_ip_key) {
3491 .func => return, // populated by the Nav instead (`updateComptimeNav` or `initWipNav`)
3492 .@"extern" => return, // populated by the Nav instead (`initWipNav`)
3493 else => {},
3494 }
3495
3496 switch (value_index) {
3497 .generic_poison_type => log.debug("updateValue(anytype)", .{}),
3498 else => log.debug("updateValue(@as({f}, {f}))", .{
3499 val.typeOf(zcu).fmt(pt),
3500 val.fmtValue(pt),
3501 }),
3502 }
3503
3504 const unit, const entry = dwarf.values.items[@backingInt(debug_const_index)];
3505
3506 for ([_]*Section{
3507 &dwarf.debug_aranges.section,
3508 &dwarf.debug_info.section,
3509 &dwarf.debug_line.section,
3510 &dwarf.debug_loclists.section,
3511 &dwarf.debug_rnglists.section,
3512 }) |sec| sec.getUnit(unit).getEntry(entry).clear();
3513
3514 var wip_nav: WipNav = .{
3515 .dwarf = dwarf,
3516 .pt = pt,
3517 .unit = unit,
3518 .entry = entry,
3519 .any_children = false,
3520 .func = .none,
3521 .func_sym_index = undefined,
3522 .func_high_pc = undefined,
3523 .blocks = undefined,
3524 .cfi = undefined,
3525 .debug_frame = .init(dwarf.gpa),
3526 .debug_info = .init(dwarf.gpa),
3527 .debug_line = .init(dwarf.gpa),
3528 .debug_loclists = .init(dwarf.gpa),
3529 };
3530 defer wip_nav.deinit();
3531
3532 const diw = &wip_nav.debug_info.writer;
3533 var big_int_space: Value.BigIntSpace = undefined;
3534 switch (value_ip_key) {
3535 .func => unreachable, // handled above
3536 .@"extern" => unreachable, // handled above
3537 .spirv_type => unreachable,
3538
3539 .int_type => |int_type| {
3540 try wip_nav.abbrevCode(.numeric_type);
3541 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3542 try diw.writeByte(switch (int_type.signedness) {
3543 inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)),
3544 });
3545 try diw.writeUleb128(int_type.bits);
3546 try diw.writeUleb128(val.toType().abiSize(zcu));
3547 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
3548 },
3549 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
3550 .one, .many, .c => {
3551 const ptr_child_type: Type = .fromInterned(ptr_type.child);
3552 try wip_nav.abbrevCode(switch (ptr_type.flags.alignment) {
3553 .none => if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type,
3554 else => if (ptr_type.sentinel == .none) .ptr_aligned_type else .ptr_aligned_sentinel_type,
3555 });
3556 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3557 if (ptr_type.sentinel != .none) try wip_nav.blockValue(.fromInterned(ptr_type.sentinel));
3558 if (ptr_type.flags.alignment.toByteUnits()) |a| try diw.writeUleb128(a);
3559 try diw.writeByte(@backingInt(ptr_type.flags.address_space));
3560 if (ptr_type.flags.is_const or ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
3561 .debug_info,
3562 wip_nav.unit,
3563 wip_nav.entry,
3564 @intCast(diw.end + dwarf.sectionOffsetBytes()),
3565 ) else try wip_nav.refType(ptr_child_type);
3566 if (ptr_type.flags.is_const) {
3567 try wip_nav.abbrevCode(.is_const);
3568 if (ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
3569 .debug_info,
3570 wip_nav.unit,
3571 wip_nav.entry,
3572 @intCast(diw.end + dwarf.sectionOffsetBytes()),
3573 ) else try wip_nav.refType(ptr_child_type);
3574 }
3575 if (ptr_type.flags.is_volatile) {
3576 try wip_nav.abbrevCode(.is_volatile);
3577 try wip_nav.refType(ptr_child_type);
3578 }
3579 },
3580 .slice => {
3581 try wip_nav.abbrevCode(.generated_struct_type);
3582 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3583 try diw.writeUleb128(val.toType().abiSize(zcu));
3584 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
3585 try wip_nav.abbrevCode(.generated_field);
3586 try wip_nav.strp("ptr");
3587 const ptr_field_type = val.toType().slicePtrFieldType(zcu);
3588 try wip_nav.refType(ptr_field_type);
3589 try diw.writeUleb128(0);
3590 try wip_nav.abbrevCode(.generated_field);
3591 try wip_nav.strp("len");
3592 const len_field_type: Type = .usize;
3593 try wip_nav.refType(len_field_type);
3594 try diw.writeUleb128(len_field_type.abiAlignment(zcu).forward(ptr_field_type.abiSize(zcu)));
3595 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3596 },
3597 },
3598 .array_type => |array_type| {
3599 const array_child_type: Type = .fromInterned(array_type.child);
3600 try wip_nav.abbrevCode(if (array_type.sentinel == .none) .array_type else .array_sentinel_type);
3601 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3602 if (array_type.sentinel != .none) try wip_nav.blockValue(.fromInterned(array_type.sentinel));
3603 try wip_nav.refType(array_child_type);
3604 try wip_nav.abbrevCode(.array_len);
3605 try wip_nav.refType(.usize);
3606 try diw.writeUleb128(array_type.len);
3607 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3608 },
3609 .vector_type => |vector_type| {
3610 try wip_nav.abbrevCode(.vector_type);
3611 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3612 try wip_nav.refType(.fromInterned(vector_type.child));
3613 try wip_nav.abbrevCode(.array_len);
3614 try wip_nav.refType(.usize);
3615 try diw.writeUleb128(vector_type.len);
3616 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3617 },
3618 .opt_type => |opt_child_type_index| {
3619 const opt_child_type: Type = .fromInterned(opt_child_type_index);
3620 const opt_repr = optRepr(opt_child_type, zcu);
3621 try wip_nav.abbrevCode(.generated_union_type);
3622 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3623 try diw.writeUleb128(val.toType().abiSize(zcu));
3624 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
3625 switch (opt_repr) {
3626 .opv_null => {
3627 try wip_nav.abbrevCode(.generated_field);
3628 try wip_nav.strp("null");
3629 try wip_nav.refType(.null);
3630 try diw.writeUleb128(0);
3631 },
3632 .unpacked, .error_set, .pointer => {
3633 try wip_nav.abbrevCode(.tagged_union);
3634 try wip_nav.infoSectionOffset(
3635 .debug_info,
3636 wip_nav.unit,
3637 wip_nav.entry,
3638 @intCast(diw.end + dwarf.sectionOffsetBytes()),
3639 );
3640 {
3641 try wip_nav.abbrevCode(.generated_field);
3642 try wip_nav.strp("has_value");
3643 switch (opt_repr) {
3644 .opv_null => unreachable,
3645 .unpacked => {
3646 try wip_nav.refType(.bool);
3647 try diw.writeUleb128(if (opt_child_type.hasRuntimeBits(zcu))
3648 opt_child_type.abiSize(zcu)
3649 else
3650 0);
3651 },
3652 .error_set => {
3653 try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
3654 .signedness = .unsigned,
3655 .bits = zcu.errorSetBits(),
3656 } })));
3657 try diw.writeUleb128(0);
3658 },
3659 .pointer => {
3660 try wip_nav.refType(.usize);
3661 try diw.writeUleb128(0);
3662 },
3663 }
3664
3665 try wip_nav.abbrevCode(.tagged_union_field);
3666 try diw.writeUleb128(DW.FORM.udata);
3667 try diw.writeUleb128(0);
3668 {
3669 try wip_nav.abbrevCode(.generated_field);
3670 try wip_nav.strp("null");
3671 try wip_nav.refType(.null);
3672 try diw.writeUleb128(0);
3673 }
3674 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3675
3676 try wip_nav.abbrevCode(.tagged_union_default_field);
3677 {
3678 try wip_nav.abbrevCode(.generated_field);
3679 try wip_nav.strp("?");
3680 try wip_nav.refType(opt_child_type);
3681 try diw.writeUleb128(0);
3682 }
3683 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3684 }
3685 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3686 },
3687 }
3688 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3689 },
3690 .anyframe_type => unreachable,
3691 .error_union_type => |error_union_type| {
3692 const error_union_error_set_type: Type = .fromInterned(error_union_type.error_set_type);
3693 const error_union_payload_type: Type = .fromInterned(error_union_type.payload_type);
3694 const error_union_error_set_offset, const error_union_payload_offset = switch (error_union_type.payload_type) {
3695 .generic_poison_type => .{ 0, 0 },
3696 else => .{
3697 codegen.errUnionErrorOffset(error_union_payload_type, zcu),
3698 codegen.errUnionPayloadOffset(error_union_payload_type, zcu),
3699 },
3700 };
3701
3702 try wip_nav.abbrevCode(.generated_union_type);
3703 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3704 if (error_union_type.error_set_type != .generic_poison_type and
3705 error_union_type.payload_type != .generic_poison_type)
3706 {
3707 try diw.writeUleb128(val.toType().abiSize(zcu));
3708 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
3709 } else {
3710 try diw.writeUleb128(0);
3711 try diw.writeUleb128(1);
3712 }
3713 {
3714 try wip_nav.abbrevCode(.tagged_union);
3715 try wip_nav.infoSectionOffset(
3716 .debug_info,
3717 wip_nav.unit,
3718 wip_nav.entry,
3719 @intCast(diw.end + dwarf.sectionOffsetBytes()),
3720 );
3721 {
3722 try wip_nav.abbrevCode(.generated_field);
3723 try wip_nav.strp("is_error");
3724 try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
3725 .signedness = .unsigned,
3726 .bits = zcu.errorSetBits(),
3727 } })));
3728 try diw.writeUleb128(error_union_error_set_offset);
3729
3730 try wip_nav.abbrevCode(.tagged_union_field);
3731 try diw.writeUleb128(DW.FORM.udata);
3732 try diw.writeUleb128(0);
3733 {
3734 try wip_nav.abbrevCode(.generated_field);
3735 try wip_nav.strp("value");
3736 try wip_nav.refType(error_union_payload_type);
3737 try diw.writeUleb128(error_union_payload_offset);
3738 }
3739 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3740
3741 try wip_nav.abbrevCode(.tagged_union_default_field);
3742 {
3743 try wip_nav.abbrevCode(.generated_field);
3744 try wip_nav.strp("error");
3745 try wip_nav.refType(error_union_error_set_type);
3746 try diw.writeUleb128(error_union_error_set_offset);
3747 }
3748 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3749 }
3750 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3751 }
3752 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3753 },
3754 .simple_type => |simple_type| switch (simple_type) {
3755 .f16,
3756 .f32,
3757 .f64,
3758 .f80,
3759 .f128,
3760 .usize,
3761 .isize,
3762 .c_char,
3763 .c_short,
3764 .c_ushort,
3765 .c_int,
3766 .c_uint,
3767 .c_long,
3768 .c_ulong,
3769 .c_longlong,
3770 .c_ulonglong,
3771 .c_longdouble,
3772 .bool,
3773 => {
3774 try wip_nav.abbrevCode(.numeric_type);
3775 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3776 try diw.writeByte(if (value_index == .bool_type)
3777 DW.ATE.boolean
3778 else if (val.toType().isRuntimeFloat())
3779 DW.ATE.float
3780 else if (val.toType().isSignedInt(zcu))
3781 DW.ATE.signed
3782 else if (val.toType().isUnsignedInt(zcu))
3783 DW.ATE.unsigned
3784 else
3785 unreachable);
3786 try diw.writeUleb128(val.toType().bitSize(zcu));
3787 try diw.writeUleb128(val.toType().abiSize(zcu));
3788 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
3789 },
3790 .generic_poison => {
3791 try wip_nav.abbrevCode(.void_type);
3792 try wip_nav.strp("anytype");
3793 },
3794 .anyopaque,
3795 .void,
3796 .type,
3797 .comptime_int,
3798 .comptime_float,
3799 .noreturn,
3800 .null,
3801 .undefined,
3802 .enum_literal,
3803 => {
3804 try wip_nav.abbrevCode(.void_type);
3805 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3806 },
3807 .anyerror => unreachable, // already did early return above
3808 .adhoc_inferred_error_set => unreachable,
3809 },
3810 .tuple_type => |tuple_type| if (tuple_type.types.len == 0) {
3811 try wip_nav.abbrevCode(.generated_empty_struct_type);
3812 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3813 try diw.writeByte(@intFromBool(false));
3814 } else {
3815 try wip_nav.abbrevCode(.generated_struct_type);
3816 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3817 try diw.writeUleb128(val.toType().abiSize(zcu));
3818 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
3819 var field_byte_offset: u64 = 0;
3820 for (0..tuple_type.types.len) |field_index| {
3821 const comptime_value = tuple_type.values.get(ip)[field_index];
3822 const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);
3823 const has_runtime_bits, const has_comptime_state = switch (comptime_value) {
3824 .none => .{ false, false },
3825 else => .{ field_type.hasRuntimeBits(zcu), field_type.comptimeOnly(zcu) },
3826 };
3827 try wip_nav.abbrevCode(if (has_comptime_state)
3828 .field_comptime_comptime_state
3829 else if (has_runtime_bits)
3830 .field_comptime_runtime_bits
3831 else if (comptime_value != .none)
3832 .field_comptime
3833 else
3834 .field);
3835 {
3836 var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined;
3837 const field_name = std.mem.print(&field_name_buf, "{d}", .{field_index}) catch unreachable;
3838 try wip_nav.strp(field_name);
3839 }
3840 try wip_nav.refType(field_type);
3841 if (comptime_value == .none) {
3842 const field_align = field_type.abiAlignment(zcu);
3843 field_byte_offset = field_align.forward(field_byte_offset);
3844 try diw.writeUleb128(field_byte_offset);
3845 try diw.writeUleb128(field_type.abiAlignment(zcu).toByteUnits().?);
3846 field_byte_offset += field_type.abiSize(zcu);
3847 }
3848 if (has_comptime_state)
3849 try wip_nav.refValue(.fromInterned(comptime_value))
3850 else if (has_runtime_bits)
3851 try wip_nav.blockValue(.fromInterned(comptime_value));
3852 }
3853 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3854 },
3855 .struct_type => {
3856 const loaded_struct = ip.loadStructType(value_index);
3857 const ty = val.toType();
3858 const file = loaded_struct.zir_index.resolveFile(ip);
3859 switch (loaded_struct.layout) {
3860 .auto, .@"extern" => {
3861 const struct_is_file: bool = if (loaded_struct.zir_index.resolve(ip)) |inst| f: {
3862 break :f inst == .main_struct_inst;
3863 } else false;
3864 if (loaded_struct.name_nav.unwrap()) |nav_index| {
3865 assert(!struct_is_file);
3866 const nav = ip.getNav(nav_index);
3867 const decl_inst = nav.srcInst(ip).resolve(ip).?;
3868 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
3869 try wip_nav.declCommon(if (loaded_struct.field_types.len == 0) .{
3870 .decl = .decl_namespace_struct,
3871 .generic_decl = .generic_decl_const,
3872 .decl_instance = .decl_instance_namespace_struct,
3873 } else .{
3874 .decl = .decl_struct,
3875 .generic_decl = .generic_decl_const,
3876 .decl_instance = .decl_instance_struct,
3877 }, &nav, file, &decl);
3878 } else {
3879 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
3880 try wip_nav.abbrevCode(switch (loaded_struct.field_types.len) {
3881 0 => if (struct_is_file) .empty_file else .empty_struct_type,
3882 else => if (struct_is_file) .file else .struct_type,
3883 });
3884 try diw.writeUleb128(file_gop.index);
3885 try wip_nav.strp(loaded_struct.name.toSlice(ip));
3886 }
3887 if (loaded_struct.field_types.len == 0) {
3888 if (!struct_is_file) try diw.writeByte(@intFromBool(false));
3889 } else {
3890 try diw.writeUleb128(ty.abiSize(zcu));
3891 try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
3892 for (0..loaded_struct.field_types.len) |field_index| {
3893 const is_comptime = loaded_struct.field_is_comptime_bits.get(ip, field_index);
3894 // TODO: we currently don't emit information about default values for
3895 // non-`comptime` fields, because these default values are resolved at a
3896 // separate time in the compiler frontend. To emit this information, the
3897 // frontend needs to tell us when the default values are available: like
3898 // how `Zcu.PerThread.ensureTypeLayoutUpToDate` enqueues a link task to
3899 // indicate completion of the type's layout, a task should be enqueued
3900 // by `Zcu.PerThread.ensureStructDefaultsUpToDate`, and upon receiving
3901 // it we should patch the correct default field values in.
3902 const field_init: InternPool.Index = if (is_comptime) loaded_struct.field_defaults.getOrNone(ip, field_index) else .none;
3903 assert(!(is_comptime and field_init == .none));
3904 const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
3905 const has_runtime_bits, const has_comptime_state = switch (field_init) {
3906 .none => .{ false, false },
3907 else => .{
3908 field_type.hasRuntimeBits(zcu),
3909 field_type.comptimeOnly(zcu),
3910 },
3911 };
3912 try wip_nav.abbrevCode(if (is_comptime)
3913 if (has_comptime_state)
3914 .field_comptime_comptime_state
3915 else if (has_runtime_bits)
3916 .field_comptime_runtime_bits
3917 else
3918 .field_comptime
3919 else if (field_init != .none)
3920 if (has_comptime_state)
3921 .field_default_comptime_state
3922 else if (has_runtime_bits)
3923 .field_default_runtime_bits
3924 else
3925 .field
3926 else
3927 .field);
3928 try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
3929 try wip_nav.refType(field_type);
3930 if (!is_comptime) {
3931 try diw.writeUleb128(loaded_struct.field_offsets.get(ip)[field_index]);
3932 try diw.writeUleb128(loaded_struct.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
3933 field_type.abiAlignment(zcu).toByteUnits().?);
3934 }
3935 if (has_comptime_state)
3936 try wip_nav.refValue(.fromInterned(field_init))
3937 else if (has_runtime_bits)
3938 try wip_nav.blockValue(.fromInterned(field_init));
3939 }
3940 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3941 }
3942 },
3943 .@"packed" => {
3944 const need_terminator: bool = if (loaded_struct.name_nav.unwrap()) |nav_index| t: {
3945 const nav = ip.getNav(nav_index);
3946 const decl_inst = nav.srcInst(ip).resolve(ip).?;
3947 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
3948 try wip_nav.declCommon(.{
3949 .decl = .decl_packed_struct,
3950 .generic_decl = .generic_decl_const,
3951 .decl_instance = .decl_instance_packed_struct,
3952 }, &nav, file, &decl);
3953 break :t true;
3954 } else t: {
3955 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
3956 try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type);
3957 try diw.writeUleb128(file_gop.index);
3958 try wip_nav.strp(loaded_struct.name.toSlice(ip));
3959 break :t loaded_struct.field_types.len > 0;
3960 };
3961 try wip_nav.refType(.fromInterned(loaded_struct.packed_backing_int_type));
3962 var field_bit_offset: u16 = 0;
3963 for (0..loaded_struct.field_types.len) |field_index| {
3964 try wip_nav.abbrevCode(.packed_field);
3965 try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
3966 const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
3967 try wip_nav.refType(field_type);
3968 try diw.writeUleb128(field_bit_offset);
3969 field_bit_offset += @intCast(field_type.bitSize(zcu));
3970 }
3971 if (need_terminator) try diw.writeUleb128(@backingInt(AbbrevCode.null));
3972 },
3973 }
3974 },
3975 .union_type => {
3976 const loaded_union = ip.loadUnionType(value_index);
3977 const file = loaded_union.zir_index.resolveFile(ip);
3978 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
3979 switch (loaded_union.layout) {
3980 .auto, .@"extern" => {
3981 const need_terminator: bool = if (loaded_union.name_nav.unwrap()) |nav_index| t: {
3982 const nav = ip.getNav(nav_index);
3983 const decl_inst = nav.srcInst(ip).resolve(ip).?;
3984 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
3985 try wip_nav.declCommon(.{
3986 .decl = .decl_union,
3987 .generic_decl = .generic_decl_const,
3988 .decl_instance = .decl_instance_union,
3989 }, &nav, file, &decl);
3990 break :t true;
3991 } else t: {
3992 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
3993 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);
3994 try diw.writeUleb128(file_gop.index);
3995 try wip_nav.strp(loaded_union.name.toSlice(ip));
3996 break :t loaded_union.field_types.len > 0;
3997 };
3998 const union_layout = Type.getUnionLayout(loaded_union, zcu);
3999 try diw.writeUleb128(union_layout.abi_size);
4000 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
4001 if (loaded_union.has_runtime_tag) {
4002 try wip_nav.abbrevCode(.tagged_union);
4003 try wip_nav.infoSectionOffset(
4004 .debug_info,
4005 wip_nav.unit,
4006 wip_nav.entry,
4007 @intCast(diw.end + dwarf.sectionOffsetBytes()),
4008 );
4009 {
4010 try wip_nav.abbrevCode(.generated_field);
4011 try wip_nav.strp("tag");
4012 try wip_nav.refType(.fromInterned(loaded_union.enum_tag_type));
4013 try diw.writeUleb128(union_layout.tagOffset());
4014
4015 for (0..loaded_union.field_types.len) |field_index| {
4016 try wip_nav.abbrevCode(.tagged_union_field);
4017 try wip_nav.enumConstValue(loaded_tag, field_index);
4018 {
4019 try wip_nav.abbrevCode(.field);
4020 try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
4021 const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
4022 try wip_nav.refType(field_type);
4023 try diw.writeUleb128(union_layout.payloadOffset());
4024 try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
4025 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
4026 }
4027 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4028 }
4029 }
4030 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4031 } else for (0..loaded_union.field_types.len) |field_index| {
4032 try wip_nav.abbrevCode(.field);
4033 try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
4034 const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
4035 try wip_nav.refType(field_type);
4036 try diw.writeUleb128(0);
4037 try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
4038 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
4039 }
4040 if (need_terminator) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4041 },
4042 .@"packed" => {
4043 const need_terminator: bool = if (loaded_union.name_nav.unwrap()) |nav_index| t: {
4044 const nav = ip.getNav(nav_index);
4045 const decl_inst = nav.srcInst(ip).resolve(ip).?;
4046 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
4047 try wip_nav.declCommon(.{
4048 .decl = .decl_packed_union,
4049 .generic_decl = .generic_decl_const,
4050 .decl_instance = .decl_instance_packed_union,
4051 }, &nav, file, &decl);
4052 break :t true;
4053 } else t: {
4054 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
4055 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .packed_union_type else .empty_packed_union_type);
4056 try diw.writeUleb128(file_gop.index);
4057 try wip_nav.strp(loaded_union.name.toSlice(ip));
4058 break :t loaded_union.field_types.len > 0;
4059 };
4060 try wip_nav.refType(.fromInterned(loaded_union.packed_backing_int_type));
4061 for (0..loaded_union.field_types.len) |field_index| {
4062 try wip_nav.abbrevCode(.packed_field);
4063 try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
4064 try wip_nav.refType(.fromInterned(loaded_union.field_types.get(ip)[field_index]));
4065 try diw.writeUleb128(0);
4066 }
4067 if (need_terminator) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4068 },
4069 }
4070 },
4071 .enum_type => {
4072 const loaded_enum = ip.loadEnumType(value_index);
4073 if (loaded_enum.zir_index.unwrap()) |zir_index| {
4074 assert(loaded_enum.owner_union == .none);
4075 const file = zir_index.resolveFile(ip);
4076 if (loaded_enum.name_nav.unwrap()) |nav_index| {
4077 const nav = ip.getNav(nav_index);
4078 const decl_inst = nav.srcInst(ip).resolve(ip).?;
4079 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
4080 try wip_nav.declCommon(if (loaded_enum.field_names.len > 0) .{
4081 .decl = .decl_enum,
4082 .generic_decl = .generic_decl_const,
4083 .decl_instance = .decl_instance_enum,
4084 } else .{
4085 .decl = .decl_empty_enum,
4086 .generic_decl = .generic_decl_const,
4087 .decl_instance = .decl_instance_empty_enum,
4088 }, &nav, file, &decl);
4089 } else {
4090 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
4091 try wip_nav.abbrevCode(if (loaded_enum.field_names.len > 0) .enum_type else .empty_enum_type);
4092 try diw.writeUleb128(file_gop.index);
4093 try wip_nav.strp(loaded_enum.name.toSlice(ip));
4094 }
4095 try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
4096 for (0..loaded_enum.field_names.len) |field_index| {
4097 try wip_nav.abbrevCode(.enum_field);
4098 try wip_nav.enumConstValue(loaded_enum, field_index);
4099 try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
4100 }
4101 if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4102 } else {
4103 assert(loaded_enum.owner_union != .none);
4104 try wip_nav.abbrevCode(if (loaded_enum.field_names.len == 0) .generated_empty_enum_type else .generated_enum_type);
4105 try wip_nav.strp(loaded_enum.name.toSlice(ip));
4106 try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
4107 for (0..loaded_enum.field_names.len) |field_index| {
4108 try wip_nav.abbrevCode(.enum_field);
4109 try wip_nav.enumConstValue(loaded_enum, field_index);
4110 try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
4111 }
4112 if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4113 }
4114 },
4115 .opaque_type => {
4116 const loaded_opaque = ip.loadOpaqueType(value_index);
4117 const file = loaded_opaque.zir_index.resolveFile(ip);
4118 if (loaded_opaque.name_nav.unwrap()) |nav_index| {
4119 const nav = ip.getNav(nav_index);
4120 const decl_inst = nav.srcInst(ip).resolve(ip).?;
4121 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
4122 try wip_nav.declCommon(.{
4123 .decl = .decl_namespace_struct,
4124 .generic_decl = .generic_decl_const,
4125 .decl_instance = .decl_instance_namespace_struct,
4126 }, &nav, file, &decl);
4127 } else {
4128 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
4129 try wip_nav.abbrevCode(.empty_struct_type);
4130 try diw.writeUleb128(file_gop.index);
4131 try wip_nav.strp(loaded_opaque.name.toSlice(ip));
4132 }
4133 try diw.writeByte(@intFromBool(true));
4134 },
4135 .func_type => |func_type| {
4136 const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
4137 try wip_nav.abbrevCode(if (is_nullary) .nullary_func_type else .func_type);
4138 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
4139 const cc: DW.CC = cc: {
4140 if (zcu.getTarget().cCallingConvention()) |cc| {
4141 if (@as(std.lang.CallingConvention.Tag, cc) == func_type.cc) {
4142 break :cc .normal;
4143 }
4144 }
4145 // For better or worse, we try to match what Clang emits.
4146 break :cc switch (func_type.cc) {
4147 .@"inline" => .nocall,
4148 .async, .auto, .naked => .normal,
4149 .x86_64_sysv => .LLVM_X86_64SysV,
4150 .x86_64_win => .LLVM_Win64,
4151 .x86_64_regcall_v3_sysv => .LLVM_X86RegCall,
4152 .x86_64_regcall_v4_win => .LLVM_X86RegCall,
4153 .x86_64_vectorcall => .LLVM_vectorcall,
4154 .x86_sysv, .x86_win, .x86_mingw => .normal,
4155 .x86_64_preserve_none => .LLVM_PreserveNone,
4156 .x86_stdcall => .BORLAND_stdcall,
4157 .x86_fastcall => .BORLAND_msfastcall,
4158 .x86_thiscall => .BORLAND_thiscall,
4159 .x86_thiscall_mingw => .BORLAND_thiscall,
4160 .x86_regcall_v3 => .LLVM_X86RegCall,
4161 .x86_regcall_v4_win => .LLVM_X86RegCall,
4162 .x86_vectorcall => .LLVM_vectorcall,
4163
4164 .aarch64_aapcs => .normal,
4165 .aarch64_aapcs_darwin => .normal,
4166 .aarch64_aapcs_win => .normal,
4167 .aarch64_vfabi => .LLVM_AAPCS,
4168 .aarch64_vfabi_sve => .LLVM_AAPCS,
4169 .aarch64_preserve_none => .LLVM_PreserveNone,
4170
4171 .arm_aapcs => .LLVM_AAPCS,
4172 .arm_aapcs_vfp => .LLVM_AAPCS_VFP,
4173
4174 .riscv64_lp64_v,
4175 .riscv32_ilp32_v,
4176 => .LLVM_RISCVVectorCall,
4177
4178 .m68k_rtd => .LLVM_M68kRTD,
4179
4180 .sh_renesas => .GNU_renesas_sh,
4181
4182 .amdgcn_kernel => .LLVM_OpenCLKernel,
4183 .nvptx_kernel,
4184 .spirv_kernel,
4185 => .nocall,
4186
4187 .x86_64_interrupt,
4188 .x86_interrupt,
4189 .arm_interrupt,
4190 .mips64_interrupt,
4191 .mips_interrupt,
4192 .riscv64_interrupt,
4193 .riscv32_interrupt,
4194 .sh_interrupt,
4195 .arc_interrupt,
4196 .avr_builtin,
4197 .avr_signal,
4198 .avr_interrupt,
4199 .csky_interrupt,
4200 .m68k_interrupt,
4201 .microblaze_interrupt,
4202 .msp430_interrupt,
4203 => .normal,
4204
4205 else => .nocall,
4206 };
4207 };
4208 try diw.writeByte(@backingInt(cc));
4209 try wip_nav.refType(.fromInterned(func_type.return_type));
4210 if (!is_nullary) {
4211 for (0..func_type.param_types.len) |param_index| {
4212 try wip_nav.abbrevCode(.func_type_param);
4213 try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
4214 }
4215 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
4216 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4217 }
4218 },
4219 .error_set_type => |error_set_type| {
4220 try wip_nav.abbrevCode(if (error_set_type.names.len == 0) .generated_empty_enum_type else .generated_enum_type);
4221 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
4222 try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
4223 .signedness = .unsigned,
4224 .bits = zcu.errorSetBits(),
4225 } })));
4226 for (0..error_set_type.names.len) |field_index| {
4227 const field_name = error_set_type.names.get(ip)[field_index];
4228 try wip_nav.abbrevCode(.enum_field);
4229 try diw.writeUleb128(DW.FORM.udata);
4230 try diw.writeUleb128(ip.getErrorValueIfExists(field_name).?);
4231 try wip_nav.strp(field_name.toSlice(ip));
4232 }
4233 if (error_set_type.names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4234 },
4235 .inferred_error_set_type => |func| {
4236 try wip_nav.abbrevCode(.inferred_error_set_type);
4237 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
4238 try wip_nav.refType(.fromInterned(switch (ip.funcIesResolvedUnordered(func)) {
4239 .none => .anyerror_type,
4240 else => |ies| ies,
4241 }));
4242 },
4243
4244 .undef => |ty| {
4245 try wip_nav.abbrevCode(.undefined_comptime_value);
4246 try wip_nav.refType(.fromInterned(ty));
4247 },
4248 .simple_value => |simple_value| switch (simple_value) {
4249 .void => unreachable, // opv state
4250 .true, .false => unreachable, // runtime bits
4251 .@"unreachable" => unreachable, // not a value
4252 .null => {
4253 // TODO: proper representation for this
4254 try wip_nav.abbrevCode(.undefined_comptime_value);
4255 try wip_nav.refType(.null);
4256 },
4257 },
4258 .int => |int| {
4259 try wip_nav.abbrevCode(.comptime_value);
4260 try wip_nav.refType(.fromInterned(int.ty));
4261 try wip_nav.bigIntConstValue(.fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu));
4262 },
4263 .bitpack => |bitpack| {
4264 const backing_int_val: Value = .fromInterned(bitpack.backing_int_val);
4265 try wip_nav.abbrevCode(.comptime_value);
4266 try wip_nav.refType(.fromInterned(bitpack.ty));
4267 try wip_nav.bigIntConstValue(backing_int_val.typeOf(zcu), backing_int_val.toBigInt(&big_int_space, zcu));
4268 },
4269 .err => |err| {
4270 try wip_nav.abbrevCode(.comptime_value);
4271 try wip_nav.refType(.fromInterned(err.ty));
4272 try diw.writeUleb128(DW.FORM.udata);
4273 try diw.writeUleb128(try pt.getErrorValue(err.name));
4274 },
4275 .error_union => |error_union| {
4276 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value);
4277 try wip_nav.refType(.fromInterned(error_union.ty));
4278 var err_buf: [4]u8 = undefined;
4279 const err_bytes = err_buf[0..@divCeil(zcu.errorSetBits(), 8)];
4280 dwarf.writeInt(err_bytes, switch (error_union.val) {
4281 .err_name => |err_name| try pt.getErrorValue(err_name),
4282 .payload => 0,
4283 });
4284 {
4285 try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
4286 try wip_nav.strp("is_error");
4287 try diw.writeUleb128(err_bytes.len);
4288 try diw.writeAll(err_bytes);
4289 }
4290 payload_field: switch (error_union.val) {
4291 .err_name => {},
4292 .payload => |payload_val| {
4293 const payload_type: Type = .fromInterned(ip.typeOf(payload_val));
4294 const has_runtime_bits = payload_type.hasRuntimeBits(zcu);
4295 const has_comptime_state = payload_type.comptimeOnly(zcu);
4296 try wip_nav.abbrevCode(if (has_comptime_state)
4297 .comptime_value_field_comptime_state
4298 else if (has_runtime_bits)
4299 .comptime_value_field_runtime_bits
4300 else
4301 break :payload_field);
4302 try wip_nav.strp("value");
4303 if (has_comptime_state)
4304 try wip_nav.refValue(.fromInterned(payload_val))
4305 else
4306 try wip_nav.blockValue(.fromInterned(payload_val));
4307 },
4308 }
4309 {
4310 try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
4311 try wip_nav.strp("error");
4312 try diw.writeUleb128(err_bytes.len);
4313 try diw.writeAll(err_bytes);
4314 }
4315 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4316 },
4317 .enum_literal => |enum_literal| {
4318 try wip_nav.abbrevCode(.comptime_value);
4319 try wip_nav.refType(.enum_literal);
4320 try diw.writeUleb128(DW.FORM.strp);
4321 try wip_nav.strp(enum_literal.toSlice(ip));
4322 },
4323 .enum_tag => |enum_tag| {
4324 const int = ip.indexToKey(enum_tag.int).int;
4325 try wip_nav.abbrevCode(.comptime_value);
4326 try wip_nav.refType(.fromInterned(enum_tag.ty));
4327 try wip_nav.bigIntConstValue(.fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu));
4328 },
4329 .float => |float| {
4330 try wip_nav.abbrevCode(.comptime_value);
4331 try wip_nav.refType(.fromInterned(float.ty));
4332 switch (float.storage) {
4333 .f16 => |f16_val| {
4334 try diw.writeUleb128(DW.FORM.data2);
4335 try diw.writeInt(u16, @bitCast(f16_val), dwarf.endian);
4336 },
4337 .f32 => |f32_val| {
4338 try diw.writeUleb128(DW.FORM.data4);
4339 try diw.writeInt(u32, @bitCast(f32_val), dwarf.endian);
4340 },
4341 .f64 => |f64_val| {
4342 try diw.writeUleb128(DW.FORM.data8);
4343 try diw.writeInt(u64, @bitCast(f64_val), dwarf.endian);
4344 },
4345 .f80 => |f80_val| {
4346 try diw.writeUleb128(DW.FORM.block);
4347 try diw.writeUleb128(@divExact(80, 8));
4348 try diw.writeInt(u80, @bitCast(f80_val), dwarf.endian);
4349 },
4350 .f128 => |f128_val| {
4351 try diw.writeUleb128(DW.FORM.data16);
4352 try diw.writeInt(u128, @bitCast(f128_val), dwarf.endian);
4353 },
4354 }
4355 },
4356 .ptr => |ptr| {
4357 const Access = union(enum) {
4358 index: u64,
4359 field: InternPool.NullTerminatedString,
4360 synthetic_field: []const u8,
4361 tuple_index: u32,
4362 };
4363 var zero_bit_accesses: std.ArrayList(Access) = .empty;
4364 defer zero_bit_accesses.deinit(dwarf.gpa);
4365 location: {
4366 var base_addr = ptr.base_addr;
4367 var byte_offset = ptr.byte_offset;
4368 const base_unit, const base_entry = while (true) {
4369 const base_ptr, const access: Access = base_ptr_access: switch (base_addr) {
4370 .nav => |nav_index| break try dwarf.getNavEntry(nav_index),
4371 .comptime_alloc, .comptime_field => unreachable,
4372 .uav => |uav| {
4373 const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));
4374 if (uav_ty.classify(zcu) == .one_possible_value) {
4375 try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)
4376 .aggregate_comptime_value
4377 else
4378 .comptime_value);
4379 try wip_nav.refType(.fromInterned(ptr.ty));
4380 try diw.writeUleb128(DW.FORM.udata);
4381 try diw.writeUleb128(ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment.toByteUnits() orelse
4382 uav_ty.abiAlignment(zcu).toByteUnits().?);
4383 break :location;
4384 } else break try wip_nav.getValueEntry(.fromInterned(uav.val));
4385 },
4386 .int => {
4387 try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)
4388 .aggregate_comptime_value
4389 else
4390 .comptime_value);
4391 try wip_nav.refType(.fromInterned(ptr.ty));
4392 try diw.writeUleb128(DW.FORM.udata);
4393 try diw.writeUleb128(byte_offset);
4394 break :location;
4395 },
4396 .eu_payload => |eu_ptr| {
4397 const base_ptr = ip.indexToKey(eu_ptr).ptr;
4398 byte_offset += codegen.errUnionPayloadOffset(.fromInterned(ip.indexToKey(
4399 ip.indexToKey(base_ptr.ty).ptr_type.child,
4400 ).error_union_type.payload_type), zcu);
4401 break :base_ptr_access .{ base_ptr, .{ .synthetic_field = "value" } };
4402 },
4403 .opt_payload => |opt_ptr| .{ ip.indexToKey(opt_ptr).ptr, .{ .synthetic_field = "?" } },
4404 .field => |field| {
4405 const base_ptr = ip.indexToKey(field.base).ptr;
4406 const agg_ty: Type = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child);
4407 break :base_ptr_access .{
4408 base_ptr,
4409 if (agg_ty.isSlice(zcu)) .{ .synthetic_field = switch (field.index) {
4410 Value.slice_ptr_index => "ptr",
4411 Value.slice_len_index => "len",
4412 else => unreachable,
4413 } } else if (agg_ty.structFieldName(@intCast(field.index), zcu).unwrap()) |field_name|
4414 .{ .field = field_name }
4415 else
4416 .{ .tuple_index = @intCast(field.index) },
4417 };
4418 },
4419 .arr_elem => |arr_elem| .{
4420 ip.indexToKey(arr_elem.base).ptr,
4421 .{ .index = arr_elem.index },
4422 },
4423 };
4424 base_addr = base_ptr.base_addr;
4425 byte_offset += base_ptr.byte_offset;
4426 if (Type.fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child).hasRuntimeBits(zcu))
4427 assert(access != .index)
4428 else
4429 try zero_bit_accesses.append(dwarf.gpa, access);
4430 };
4431 try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)
4432 .aggregate_location_comptime_value
4433 else
4434 .location_comptime_value);
4435 try wip_nav.refType(.fromInterned(ptr.ty));
4436 try wip_nav.infoExprLoc(.{ .implicit_pointer = .{
4437 .unit = base_unit,
4438 .entry = base_entry,
4439 .offset = byte_offset,
4440 } });
4441 }
4442 if (zero_bit_accesses.items.len > 0) {
4443 for (zero_bit_accesses.items) |access| switch (access) {
4444 .index => |index| {
4445 try wip_nav.abbrevCode(.array_index);
4446 try diw.writeUleb128(index);
4447 },
4448 .field => |field| {
4449 try wip_nav.abbrevCode(.access);
4450 try wip_nav.strp(field.toSlice(ip));
4451 },
4452 .synthetic_field => |field| {
4453 try wip_nav.abbrevCode(.access);
4454 try wip_nav.strp(field);
4455 },
4456 .tuple_index => |index| {
4457 try wip_nav.abbrevCode(.access);
4458 var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined;
4459 const field_name = std.mem.print(&field_name_buf, "{d}", .{index}) catch unreachable;
4460 try wip_nav.strp(field_name);
4461 },
4462 };
4463 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4464 }
4465 },
4466 .slice => |slice| {
4467 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value);
4468 try wip_nav.refType(.fromInterned(slice.ty));
4469 {
4470 try wip_nav.abbrevCode(.comptime_value_field_comptime_state);
4471 try wip_nav.strp("ptr");
4472 try wip_nav.refValue(.fromInterned(slice.ptr));
4473 }
4474 {
4475 try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
4476 try wip_nav.strp("len");
4477 try wip_nav.blockValue(.fromInterned(slice.len));
4478 }
4479 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4480 },
4481 .opt => |opt| {
4482 const opt_child_type: Type = .fromInterned(ip.indexToKey(opt.ty).opt_type);
4483 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value);
4484 try wip_nav.refType(.fromInterned(opt.ty));
4485 {
4486 try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
4487 try wip_nav.strp("has_value");
4488 switch (optRepr(opt_child_type, zcu)) {
4489 .opv_null => try diw.writeUleb128(0),
4490 .unpacked => try wip_nav.blockValue(.makeBool(opt.val != .none)),
4491 .error_set, .pointer => try wip_nav.blockValue(.fromInterned(value_index)),
4492 }
4493 }
4494 if (opt.val != .none) child_field: {
4495 const has_runtime_bits = opt_child_type.hasRuntimeBits(zcu);
4496 const has_comptime_state = opt_child_type.comptimeOnly(zcu);
4497 try wip_nav.abbrevCode(if (has_comptime_state)
4498 .comptime_value_field_comptime_state
4499 else if (has_runtime_bits)
4500 .comptime_value_field_runtime_bits
4501 else
4502 break :child_field);
4503 try wip_nav.strp("?");
4504 if (has_comptime_state)
4505 try wip_nav.refValue(.fromInterned(opt.val))
4506 else
4507 try wip_nav.blockValue(.fromInterned(opt.val));
4508 }
4509 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4510 },
4511 .aggregate => |aggregate| {
4512 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value);
4513 try wip_nav.refType(.fromInterned(aggregate.ty));
4514 switch (ip.indexToKey(aggregate.ty)) {
4515 .struct_type => {
4516 const loaded_struct_type = ip.loadStructType(aggregate.ty);
4517 assert(loaded_struct_type.layout == .auto);
4518 for (0..loaded_struct_type.field_types.len) |field_index| {
4519 if (loaded_struct_type.field_is_comptime_bits.get(ip, field_index)) continue;
4520 const field_type: Type = .fromInterned(loaded_struct_type.field_types.get(ip)[field_index]);
4521 const has_runtime_bits = field_type.hasRuntimeBits(zcu);
4522 const has_comptime_state = field_type.comptimeOnly(zcu);
4523 try wip_nav.abbrevCode(if (has_comptime_state)
4524 .comptime_value_field_comptime_state
4525 else if (has_runtime_bits)
4526 .comptime_value_field_runtime_bits
4527 else
4528 continue);
4529 try wip_nav.strp(loaded_struct_type.field_names.get(ip)[field_index].toSlice(ip));
4530 const field_value: Value = .fromInterned(switch (aggregate.storage) {
4531 .bytes => unreachable,
4532 .elems => |elems| elems[field_index],
4533 .repeated_elem => |repeated_elem| repeated_elem,
4534 });
4535 if (has_comptime_state)
4536 try wip_nav.refValue(field_value)
4537 else
4538 try wip_nav.blockValue(field_value);
4539 }
4540 },
4541 .tuple_type => |tuple_type| for (0..tuple_type.types.len) |field_index| {
4542 if (tuple_type.values.get(ip)[field_index] != .none) continue;
4543 const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);
4544 const has_runtime_bits = field_type.hasRuntimeBits(zcu);
4545 const has_comptime_state = field_type.comptimeOnly(zcu);
4546 try wip_nav.abbrevCode(if (has_comptime_state)
4547 .comptime_value_field_comptime_state
4548 else if (has_runtime_bits)
4549 .comptime_value_field_runtime_bits
4550 else
4551 continue);
4552 {
4553 var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined;
4554 const field_name = std.mem.print(&field_name_buf, "{d}", .{field_index}) catch unreachable;
4555 try wip_nav.strp(field_name);
4556 }
4557 const field_value: Value = .fromInterned(switch (aggregate.storage) {
4558 .bytes => unreachable,
4559 .elems => |elems| elems[field_index],
4560 .repeated_elem => |repeated_elem| repeated_elem,
4561 });
4562 if (has_comptime_state)
4563 try wip_nav.refValue(field_value)
4564 else
4565 try wip_nav.blockValue(field_value);
4566 },
4567 inline .array_type, .vector_type => |sequence_type| {
4568 const child_type: Type = .fromInterned(sequence_type.child);
4569 const has_runtime_bits = child_type.hasRuntimeBits(zcu);
4570 const has_comptime_state = child_type.comptimeOnly(zcu);
4571 for (switch (aggregate.storage) {
4572 .bytes => unreachable,
4573 .elems => |elems| elems,
4574 .repeated_elem => |*repeated_elem| repeated_elem[0..1],
4575 }) |elem| {
4576 try wip_nav.abbrevCode(if (has_comptime_state)
4577 .comptime_value_elem_comptime_state
4578 else if (has_runtime_bits)
4579 .comptime_value_elem_runtime_bits
4580 else
4581 break);
4582 if (has_comptime_state)
4583 try wip_nav.refValue(.fromInterned(elem))
4584 else
4585 try wip_nav.blockValue(.fromInterned(elem));
4586 }
4587 },
4588 else => unreachable,
4589 }
4590 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4591 },
4592 .un => |un| {
4593 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value);
4594 try wip_nav.refType(.fromInterned(un.ty));
4595 {
4596 const loaded_union_type = ip.loadUnionType(un.ty);
4597 assert(loaded_union_type.layout == .auto);
4598 const field_index = zcu.unionTagFieldIndex(loaded_union_type, Value.fromInterned(un.tag)).?;
4599 const field_ty: Type = .fromInterned(loaded_union_type.field_types.get(ip)[field_index]);
4600 const field_name = ip.loadEnumType(loaded_union_type.enum_tag_type).field_names.get(ip)[field_index];
4601 const has_runtime_bits = field_ty.hasRuntimeBits(zcu);
4602 const has_comptime_state = field_ty.comptimeOnly(zcu);
4603 try wip_nav.abbrevCode(if (has_comptime_state)
4604 .comptime_value_field_comptime_state
4605 else if (has_runtime_bits)
4606 .comptime_value_field_runtime_bits
4607 else
4608 .access);
4609 try wip_nav.strp(field_name.toSlice(ip));
4610 if (has_comptime_state)
4611 try wip_nav.refValue(.fromInterned(un.val))
4612 else if (has_runtime_bits)
4613 try wip_nav.blockValue(.fromInterned(un.val));
4614 }
4615 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4616 },
4617 .memoized_call => unreachable, // not a value
4618 }
4619 try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written());
4620 try dwarf.debug_loclists.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_loclists.written());
4621}
4622
4623fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { unpacked, opv_null, error_set, pointer } {
4624 if (opt_child_type.isNoReturn(zcu)) return .opv_null;
4625 return switch (opt_child_type.toIntern()) {
4626 .anyerror_type => .error_set,
4627 else => switch (zcu.intern_pool.indexToKey(opt_child_type.toIntern())) {
4628 else => .unpacked,
4629 .error_set_type, .inferred_error_set_type => .error_set,
4630 .ptr_type => |ptr_type| if (ptr_type.flags.is_allowzero) .unpacked else .pointer,
4631 },
4632 };
4633}
4634
4635pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedInst.Index) UpdateError!void {
4636 const comp = dwarf.bin_file.comp;
4637 const io = comp.io;
4638 const ip = &zcu.intern_pool;
4639
4640 const inst_info = zir_index.resolveFull(ip).?;
4641 assert(inst_info.inst != .main_struct_inst);
4642 const file = zcu.fileByIndex(inst_info.file);
4643 const decl = file.zir.?.getDeclaration(inst_info.inst);
4644 log.debug("updateLineNumber({s}:{d}:{d} %{d} = {s})", .{
4645 file.sub_file_path,
4646 decl.src_line + 1,
4647 decl.src_column + 1,
4648 @backingInt(inst_info.inst),
4649 file.zir.?.nullTerminatedString(decl.name),
4650 });
4651
4652 var line_buf: [4]u8 = undefined;
4653 std.mem.writeInt(u32, &line_buf, decl.src_line + 1, dwarf.endian);
4654
4655 const unit = dwarf.debug_info.section.getUnit(dwarf.getUnitIfExists(file.mod.?) orelse return);
4656 const entry = unit.getEntry(dwarf.decls.get(zir_index) orelse return);
4657 try dwarf.getFile().?.writePositionalAll(io, &line_buf, dwarf.debug_info.section.off(dwarf) + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf));
4658}
4659
4660pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void {
4661 _ = dwarf;
4662 _ = nav_index;
4663}
4664
4665fn refAbbrevCode(
4666 dwarf: *Dwarf,
4667 abbrev_code: AbbrevCode,
4668) (UpdateError || Writer.Error)!@typeInfo(AbbrevCode).@"enum".tag_type {
4669 assert(abbrev_code != .null);
4670 const entry: Entry.Index = @fromBackingInt(@intCast(@backingInt(abbrev_code)));
4671 if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @backingInt(abbrev_code);
4672 var debug_abbrev_aw: Writer.Allocating = .init(dwarf.gpa);
4673 defer debug_abbrev_aw.deinit();
4674 const daw = &debug_abbrev_aw.writer;
4675 const abbrev = AbbrevCode.abbrevs.get(abbrev_code);
4676 try daw.writeUleb128(@backingInt(abbrev_code));
4677 try daw.writeUleb128(@backingInt(abbrev.tag));
4678 try daw.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no);
4679 for (abbrev.attrs) |*attr| inline for (attr) |info| try daw.writeUleb128(@backingInt(info));
4680 for (0..2) |_| try daw.writeUleb128(0);
4681 try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, entry, dwarf, debug_abbrev_aw.written());
4682 return @backingInt(abbrev_code);
4683}
4684
4685pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) UpdateError!void {
4686 return dwarf.flushWriterError(pt) catch |err| switch (err) {
4687 error.WriteFailed => error.OutOfMemory,
4688 else => |e| e,
4689 };
4690}
4691fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Error)!void {
4692 const zcu = pt.zcu;
4693 const ip = &zcu.intern_pool;
4694 const comp = dwarf.bin_file.comp;
4695 const io = comp.io;
4696
4697 // Update `anyerror` based on the finished global error set.
4698 {
4699 const index = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, .anyerror_type);
4700 const unit, const entry = dwarf.values.items[@backingInt(index)];
4701 var wip_nav: WipNav = .{
4702 .dwarf = dwarf,
4703 .pt = pt,
4704 .unit = unit,
4705 .entry = entry,
4706 .any_children = false,
4707 .func = .none,
4708 .func_sym_index = undefined,
4709 .func_high_pc = undefined,
4710 .blocks = undefined,
4711 .cfi = undefined,
4712 .debug_frame = .init(dwarf.gpa),
4713 .debug_info = .init(dwarf.gpa),
4714 .debug_line = .init(dwarf.gpa),
4715 .debug_loclists = .init(dwarf.gpa),
4716 };
4717 defer wip_nav.deinit();
4718 const diw = &wip_nav.debug_info.writer;
4719 const global_error_set_names = ip.global_error_set.getNamesFromMainThread();
4720 try wip_nav.abbrevCode(if (global_error_set_names.len == 0) .generated_empty_enum_type else .generated_enum_type);
4721 try wip_nav.strp("anyerror");
4722 try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
4723 .signedness = .unsigned,
4724 .bits = zcu.errorSetBits(),
4725 } })));
4726 for (global_error_set_names, 1..) |name, value| {
4727 try wip_nav.abbrevCode(.enum_field);
4728 try diw.writeUleb128(DW.FORM.udata);
4729 try diw.writeUleb128(value);
4730 try wip_nav.strp(name.toSlice(ip));
4731 }
4732 if (global_error_set_names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4733 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
4734 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
4735 }
4736
4737 for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {
4738 const root_dir_path = try mod.root.toAbsolute(&zcu.comp.dirs, dwarf.gpa);
4739 defer dwarf.gpa.free(root_dir_path);
4740 mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);
4741 }
4742
4743 var header_aw: Writer.Allocating = .init(dwarf.gpa);
4744 defer header_aw.deinit();
4745 const hw = &header_aw.writer;
4746 if (dwarf.debug_aranges.section.dirty) {
4747 for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| {
4748 const unit: Unit.Index = @fromBackingInt(@intCast(unit_index));
4749 unit_ptr.clear();
4750 try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 1);
4751 header_aw.clearRetainingCapacity();
4752 try header_aw.ensureTotalCapacity(unit_ptr.header_len);
4753 const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
4754 dwarf.debug_aranges.section.getUnit(next_unit).off
4755 else
4756 dwarf.debug_aranges.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
4757 switch (dwarf.format) {
4758 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
4759 .@"64" => {
4760 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
4761 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
4762 },
4763 }
4764 hw.writeInt(u16, 2, dwarf.endian) catch unreachable;
4765 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4766 .source_off = @intCast(hw.end),
4767 .target_sec = .debug_info,
4768 .target_unit = unit,
4769 });
4770 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4771 hw.writeByte(@backingInt(dwarf.address_size)) catch unreachable;
4772 hw.writeByte(0) catch unreachable;
4773 hw.splatByteAll(0, unit_ptr.header_len - hw.end) catch unreachable;
4774 try unit_ptr.replaceHeader(&dwarf.debug_aranges.section, dwarf, header_aw.written());
4775 try unit_ptr.writeTrailer(&dwarf.debug_aranges.section, dwarf);
4776 }
4777 dwarf.debug_aranges.section.dirty = false;
4778 }
4779 if (dwarf.debug_frame.section.dirty) {
4780 const target = &dwarf.bin_file.comp.root_mod.resolved_target.result;
4781 switch (dwarf.debug_frame.header.format) {
4782 .none => {},
4783 .debug_frame => unreachable,
4784 .eh_frame => switch (target.cpu.arch) {
4785 .x86_64 => {
4786 dev.check(.x86_64_backend);
4787 const Register = @import("../codegen/x86_64/bits.zig").Register;
4788 for (dwarf.debug_frame.section.units.items) |*unit| {
4789 header_aw.clearRetainingCapacity();
4790 try header_aw.ensureTotalCapacity(unit.header_len);
4791 const unit_len = unit.header_len - dwarf.unitLengthBytes();
4792 switch (dwarf.format) {
4793 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
4794 .@"64" => {
4795 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
4796 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
4797 },
4798 }
4799 hw.splatByteAll(0, 4) catch unreachable;
4800 hw.writeByte(1) catch unreachable;
4801 hw.writeAll("zR\x00") catch unreachable;
4802 hw.writeUleb128(dwarf.debug_frame.header.code_alignment_factor) catch unreachable;
4803 hw.writeSleb128(dwarf.debug_frame.header.data_alignment_factor) catch unreachable;
4804 hw.writeUleb128(dwarf.debug_frame.header.return_address_register) catch unreachable;
4805 hw.writeUleb128(1) catch unreachable;
4806 hw.writeByte(@bitCast(@as(DW.EH.PE, .{ .type = .sdata4, .rel = .pcrel }))) catch unreachable;
4807 hw.writeByte(DW.CFA.def_cfa_sf) catch unreachable;
4808 hw.writeUleb128(Register.rsp.dwarfNum()) catch unreachable;
4809 hw.writeSleb128(-1) catch unreachable;
4810 hw.writeByte(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum()) catch unreachable;
4811 hw.writeUleb128(1) catch unreachable;
4812 hw.splatByteAll(DW.CFA.nop, unit.header_len - hw.end) catch unreachable;
4813 try unit.replaceHeader(&dwarf.debug_frame.section, dwarf, header_aw.written());
4814 try unit.writeTrailer(&dwarf.debug_frame.section, dwarf);
4815 }
4816 },
4817 else => unreachable,
4818 },
4819 }
4820 dwarf.debug_frame.section.dirty = false;
4821 }
4822 if (dwarf.debug_info.section.dirty) {
4823 for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| {
4824 const unit: Unit.Index = @fromBackingInt(@intCast(unit_index));
4825 unit_ptr.clear();
4826 try unit_ptr.cross_unit_relocs.ensureTotalCapacity(dwarf.gpa, 1);
4827 try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 7);
4828 header_aw.clearRetainingCapacity();
4829 try header_aw.ensureTotalCapacity(unit_ptr.header_len);
4830 const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
4831 dwarf.debug_info.section.getUnit(next_unit).off
4832 else
4833 dwarf.debug_info.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
4834 switch (dwarf.format) {
4835 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
4836 .@"64" => {
4837 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
4838 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
4839 },
4840 }
4841 hw.writeInt(u16, 5, dwarf.endian) catch unreachable;
4842 hw.writeByte(DW.UT.compile) catch unreachable;
4843 hw.writeByte(@backingInt(dwarf.address_size)) catch unreachable;
4844 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4845 .source_off = @intCast(hw.end),
4846 .target_sec = .debug_abbrev,
4847 .target_unit = DebugAbbrev.unit,
4848 });
4849 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4850 const compile_unit_off: u32 = @intCast(hw.end);
4851 hw.writeUleb128(try dwarf.refAbbrevCode(.compile_unit)) catch unreachable;
4852 hw.writeByte(DW.LANG.Zig) catch unreachable;
4853 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4854 .source_off = @intCast(hw.end),
4855 .target_sec = .debug_line_str,
4856 .target_unit = StringSection.unit,
4857 .target_entry = (try dwarf.debug_line_str.addString(dwarf, "zig " ++ @import("build_options").version)).toOptional(),
4858 });
4859 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4860 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4861 .source_off = @intCast(hw.end),
4862 .target_sec = .debug_line_str,
4863 .target_unit = StringSection.unit,
4864 .target_entry = mod_info.root_dir_path.toOptional(),
4865 });
4866 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4867 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4868 .source_off = @intCast(hw.end),
4869 .target_sec = .debug_line_str,
4870 .target_unit = StringSection.unit,
4871 .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod.root_src_path)).toOptional(),
4872 });
4873 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4874 unit_ptr.cross_unit_relocs.appendAssumeCapacity(.{
4875 .source_off = @intCast(hw.end),
4876 .target_unit = .main,
4877 .target_off = compile_unit_off,
4878 });
4879 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4880 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4881 .source_off = @intCast(hw.end),
4882 .target_sec = .debug_line,
4883 .target_unit = unit,
4884 });
4885 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4886 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4887 .source_off = @intCast(hw.end),
4888 .target_sec = .debug_rnglists,
4889 .target_unit = unit,
4890 .target_off = DebugRngLists.baseOffset(dwarf),
4891 });
4892 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4893 hw.writeUleb128(0) catch unreachable;
4894 hw.writeUleb128(try dwarf.refAbbrevCode(.module)) catch unreachable;
4895 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4896 .source_off = @intCast(hw.end),
4897 .target_sec = .debug_str,
4898 .target_unit = StringSection.unit,
4899 .target_entry = (try dwarf.debug_str.addString(dwarf, mod.fully_qualified_name)).toOptional(),
4900 });
4901 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4902 hw.writeUleb128(0) catch unreachable;
4903 try unit_ptr.replaceHeader(&dwarf.debug_info.section, dwarf, header_aw.written());
4904 try unit_ptr.writeTrailer(&dwarf.debug_info.section, dwarf);
4905 }
4906 dwarf.debug_info.section.dirty = false;
4907 }
4908 if (dwarf.debug_abbrev.section.dirty) {
4909 assert(!dwarf.debug_info.section.dirty);
4910 try dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).writeTrailer(&dwarf.debug_abbrev.section, dwarf);
4911 dwarf.debug_abbrev.section.dirty = false;
4912 }
4913 if (dwarf.debug_str.section.dirty) {
4914 const contents = dwarf.debug_str.contents.items;
4915 try dwarf.debug_str.section.resize(dwarf, contents.len);
4916 try dwarf.getFile().?.writePositionalAll(io, contents, dwarf.debug_str.section.off(dwarf));
4917 dwarf.debug_str.section.dirty = false;
4918 }
4919 if (dwarf.debug_line.section.dirty) {
4920 for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| try unit.resizeHeader(
4921 &dwarf.debug_line.section,
4922 dwarf,
4923 DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count())),
4924 );
4925 for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| {
4926 unit.clear();
4927 try unit.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, mod_info.dirs.count() + 2 * (mod_info.files.count()));
4928 header_aw.clearRetainingCapacity();
4929 try header_aw.ensureTotalCapacity(unit.header_len);
4930 const unit_len = (if (unit.next.unwrap()) |next_unit|
4931 dwarf.debug_line.section.getUnit(next_unit).off
4932 else
4933 dwarf.debug_line.section.len) - unit.off - dwarf.unitLengthBytes();
4934 switch (dwarf.format) {
4935 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
4936 .@"64" => {
4937 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
4938 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
4939 },
4940 }
4941 hw.writeInt(u16, 5, dwarf.endian) catch unreachable;
4942 hw.writeByte(@backingInt(dwarf.address_size)) catch unreachable;
4943 hw.writeByte(0) catch unreachable;
4944 switch (dwarf.format) {
4945 .@"32" => hw.writeInt(u32, @intCast(unit.header_len - hw.end - 4), dwarf.endian) catch unreachable,
4946 .@"64" => hw.writeInt(u64, @intCast(unit.header_len - hw.end - 8), dwarf.endian) catch unreachable,
4947 }
4948 const StandardOpcode = DeclValEnum(DW.LNS);
4949 hw.writeAll(&.{
4950 dwarf.debug_line.header.minimum_instruction_length,
4951 dwarf.debug_line.header.maximum_operations_per_instruction,
4952 @intFromBool(dwarf.debug_line.header.default_is_stmt),
4953 @bitCast(dwarf.debug_line.header.line_base),
4954 dwarf.debug_line.header.line_range,
4955 dwarf.debug_line.header.opcode_base,
4956 }) catch unreachable;
4957 hw.writeAll(std.enums.EnumArray(StandardOpcode, u8).init(.{
4958 .extended_op = undefined,
4959 .copy = 0,
4960 .advance_pc = 1,
4961 .advance_line = 1,
4962 .set_file = 1,
4963 .set_column = 1,
4964 .negate_stmt = 0,
4965 .set_basic_block = 0,
4966 .const_add_pc = 0,
4967 .fixed_advance_pc = 1,
4968 .set_prologue_end = 0,
4969 .set_epilogue_begin = 0,
4970 .set_isa = 1,
4971 }).values[1..dwarf.debug_line.header.opcode_base]) catch unreachable;
4972 hw.writeByte(1) catch unreachable;
4973 hw.writeUleb128(DW.LNCT.path) catch unreachable;
4974 hw.writeUleb128(DW.FORM.line_strp) catch unreachable;
4975 hw.writeUleb128(mod_info.dirs.count()) catch unreachable;
4976 for (mod_info.dirs.keys()) |dir_unit| {
4977 unit.cross_section_relocs.appendAssumeCapacity(.{
4978 .source_off = @intCast(hw.end),
4979 .target_sec = .debug_line_str,
4980 .target_unit = StringSection.unit,
4981 .target_entry = dwarf.getModInfo(dir_unit).root_dir_path.toOptional(),
4982 });
4983 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4984 }
4985 const dir_index_info = DebugLine.dirIndexInfo(@intCast(mod_info.dirs.count()));
4986 hw.writeByte(3) catch unreachable;
4987 hw.writeUleb128(DW.LNCT.path) catch unreachable;
4988 hw.writeUleb128(DW.FORM.line_strp) catch unreachable;
4989 hw.writeUleb128(DW.LNCT.directory_index) catch unreachable;
4990 hw.writeUleb128(@backingInt(dir_index_info.form)) catch unreachable;
4991 hw.writeUleb128(DW.LNCT.LLVM_source) catch unreachable;
4992 hw.writeUleb128(DW.FORM.line_strp) catch unreachable;
4993 hw.writeUleb128(mod_info.files.count()) catch unreachable;
4994 for (mod_info.files.keys()) |file_index| {
4995 const file = zcu.fileByIndex(file_index);
4996 unit.cross_section_relocs.appendAssumeCapacity(.{
4997 .source_off = @intCast(hw.end),
4998 .target_sec = .debug_line_str,
4999 .target_unit = StringSection.unit,
5000 .target_entry = (try dwarf.debug_line_str.addString(dwarf, file.sub_file_path)).toOptional(),
5001 });
5002 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
5003 const dir_index = mod_info.dirs.getIndex(dwarf.getUnitIfExists(file.mod.?).?) orelse 0;
5004 switch (dir_index_info.bytes) {
5005 else => unreachable,
5006 1 => hw.writeByte(@intCast(dir_index)) catch unreachable,
5007 2 => hw.writeInt(u16, @intCast(dir_index), dwarf.endian) catch unreachable,
5008 }
5009 unit.cross_section_relocs.appendAssumeCapacity(.{
5010 .source_off = @intCast(hw.end),
5011 .target_sec = .debug_line_str,
5012 .target_unit = StringSection.unit,
5013 .target_entry = (try dwarf.debug_line_str.addString(
5014 dwarf,
5015 if (file.is_builtin) file.source.? else "",
5016 )).toOptional(),
5017 });
5018 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
5019 }
5020 try unit.replaceHeader(&dwarf.debug_line.section, dwarf, header_aw.written());
5021 try unit.writeTrailer(&dwarf.debug_line.section, dwarf);
5022 }
5023 dwarf.debug_line.section.dirty = false;
5024 }
5025 if (dwarf.debug_line_str.section.dirty) {
5026 const contents = dwarf.debug_line_str.contents.items;
5027 try dwarf.debug_line_str.section.resize(dwarf, contents.len);
5028 try dwarf.getFile().?.writePositionalAll(io, contents, dwarf.debug_line_str.section.off(dwarf));
5029 dwarf.debug_line_str.section.dirty = false;
5030 }
5031 if (dwarf.debug_loclists.section.dirty) {
5032 dwarf.debug_loclists.section.dirty = false;
5033 }
5034 if (dwarf.debug_rnglists.section.dirty) {
5035 for (dwarf.debug_rnglists.section.units.items) |*unit| {
5036 header_aw.clearRetainingCapacity();
5037 try header_aw.ensureTotalCapacity(unit.header_len);
5038 const unit_len = (if (unit.next.unwrap()) |next_unit|
5039 dwarf.debug_rnglists.section.getUnit(next_unit).off
5040 else
5041 dwarf.debug_rnglists.section.len) - unit.off - dwarf.unitLengthBytes();
5042 switch (dwarf.format) {
5043 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
5044 .@"64" => {
5045 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
5046 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
5047 },
5048 }
5049 hw.writeInt(u16, 5, dwarf.endian) catch unreachable;
5050 hw.writeByte(@backingInt(dwarf.address_size)) catch unreachable;
5051 hw.writeByte(0) catch unreachable;
5052 hw.writeInt(u32, 1, dwarf.endian) catch unreachable;
5053 switch (dwarf.format) {
5054 .@"32" => hw.writeInt(u32, dwarf.sectionOffsetBytes() * 1, dwarf.endian) catch unreachable,
5055 .@"64" => hw.writeInt(u64, dwarf.sectionOffsetBytes() * 1, dwarf.endian) catch unreachable,
5056 }
5057 try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header_aw.written());
5058 try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf);
5059 }
5060 dwarf.debug_rnglists.section.dirty = false;
5061 }
5062 assert(!dwarf.debug_abbrev.section.dirty);
5063 assert(!dwarf.debug_aranges.section.dirty);
5064 assert(!dwarf.debug_frame.section.dirty);
5065 assert(!dwarf.debug_info.section.dirty);
5066 assert(!dwarf.debug_line.section.dirty);
5067 assert(!dwarf.debug_line_str.section.dirty);
5068 assert(!dwarf.debug_loclists.section.dirty);
5069 assert(!dwarf.debug_rnglists.section.dirty);
5070 assert(!dwarf.debug_str.section.dirty);
5071}
5072
5073pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void {
5074 for ([_]*Section{
5075 &dwarf.debug_abbrev.section,
5076 &dwarf.debug_aranges.section,
5077 &dwarf.debug_frame.section,
5078 &dwarf.debug_info.section,
5079 &dwarf.debug_line.section,
5080 &dwarf.debug_line_str.section,
5081 &dwarf.debug_loclists.section,
5082 &dwarf.debug_rnglists.section,
5083 &dwarf.debug_str.section,
5084 }) |sec| try sec.resolveRelocs(dwarf);
5085}
5086
5087fn DeclValEnum(comptime T: type) type {
5088 const decl_names = @typeInfo(T).@"struct".decl_names;
5089 @setEvalBranchQuota(10 * decl_names.len);
5090 var field_names: [decl_names.len][]const u8 = undefined;
5091 var fields_len = 0;
5092 var min_value: ?comptime_int = null;
5093 var max_value: ?comptime_int = null;
5094 for (decl_names) |decl_name| {
5095 if (std.mem.startsWith(u8, decl_name, "HP_") or std.mem.endsWith(u8, decl_name, "_user")) continue;
5096 const value = @field(T, decl_name);
5097 field_names[fields_len] = decl_name;
5098 fields_len += 1;
5099 if (min_value == null or min_value.? > value) min_value = value;
5100 if (max_value == null or max_value.? < value) max_value = value;
5101 }
5102 if (fields_len == 0) return enum {};
5103 const TagInt = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0);
5104 var field_vals: [fields_len]TagInt = undefined;
5105 for (field_names[0..fields_len], &field_vals) |name, *val| val.* = @field(T, name);
5106 return @Enum(TagInt, .exhaustive, field_names[0..fields_len], &field_vals);
5107}
5108
5109const AbbrevCode = enum {
5110 null,
5111 // padding codes must be one byte uleb128 values to function
5112 pad_1,
5113 pad_n,
5114 // decl, generic decl, and instance codes are assumed to all have the same uleb128 length
5115 decl_alias,
5116 decl_empty_enum,
5117 decl_enum,
5118 decl_namespace_struct,
5119 decl_struct,
5120 decl_packed_struct,
5121 decl_union,
5122 decl_packed_union,
5123 decl_var,
5124 decl_const,
5125 decl_const_runtime_bits,
5126 decl_const_comptime_state,
5127 decl_const_runtime_bits_comptime_state,
5128 decl_nullary_func,
5129 decl_func,
5130 decl_nullary_func_generic,
5131 decl_func_generic,
5132 decl_extern_nullary_func,
5133 decl_extern_func,
5134 generic_decl_var,
5135 generic_decl_const,
5136 generic_decl_func,
5137 decl_instance_alias,
5138 decl_instance_empty_enum,
5139 decl_instance_enum,
5140 decl_instance_namespace_struct,
5141 decl_instance_struct,
5142 decl_instance_packed_struct,
5143 decl_instance_union,
5144 decl_instance_packed_union,
5145 decl_instance_var,
5146 decl_instance_const,
5147 decl_instance_const_runtime_bits,
5148 decl_instance_const_comptime_state,
5149 decl_instance_const_runtime_bits_comptime_state,
5150 decl_instance_nullary_func,
5151 decl_instance_func,
5152 decl_instance_nullary_func_generic,
5153 decl_instance_func_generic,
5154 decl_instance_extern_nullary_func,
5155 decl_instance_extern_func,
5156 // the rest are unrestricted other than empty variants must not be longer
5157 // than the non-empty variant, and so should appear first
5158 compile_unit,
5159 module,
5160 empty_file,
5161 file,
5162 access,
5163 enum_field,
5164 generated_field,
5165 field,
5166 field_default_runtime_bits,
5167 field_default_comptime_state,
5168 field_comptime,
5169 field_comptime_runtime_bits,
5170 field_comptime_comptime_state,
5171 packed_field,
5172 tagged_union,
5173 tagged_union_field,
5174 tagged_union_default_field,
5175 void_type,
5176 numeric_type,
5177 inferred_error_set_type,
5178 ptr_type,
5179 ptr_sentinel_type,
5180 ptr_aligned_type,
5181 ptr_aligned_sentinel_type,
5182 is_const,
5183 is_volatile,
5184 array_type,
5185 array_sentinel_type,
5186 vector_type,
5187 array_index,
5188 array_len,
5189 nullary_func_type,
5190 func_type,
5191 func_type_param,
5192 is_var_args,
5193 generated_empty_enum_type,
5194 generated_enum_type,
5195 generated_empty_struct_type,
5196 generated_struct_type,
5197 generated_union_type,
5198 empty_enum_type,
5199 enum_type,
5200 empty_struct_type,
5201 struct_type,
5202 empty_packed_struct_type,
5203 packed_struct_type,
5204 empty_union_type,
5205 union_type,
5206 empty_packed_union_type,
5207 packed_union_type,
5208 builtin_extern_nullary_func,
5209 builtin_extern_func,
5210 builtin_extern_var,
5211 empty_block,
5212 block,
5213 empty_inlined_func,
5214 inlined_func,
5215 arg,
5216 unnamed_arg,
5217 comptime_arg,
5218 unnamed_comptime_arg,
5219 comptime_arg_runtime_bits,
5220 unnamed_comptime_arg_runtime_bits,
5221 comptime_arg_comptime_state,
5222 unnamed_comptime_arg_comptime_state,
5223 comptime_arg_runtime_bits_comptime_state,
5224 unnamed_comptime_arg_runtime_bits_comptime_state,
5225 extern_param,
5226 local_var,
5227 local_const,
5228 local_const_runtime_bits,
5229 local_const_comptime_state,
5230 local_const_runtime_bits_comptime_state,
5231 undefined_comptime_value,
5232 comptime_value,
5233 location_comptime_value,
5234 aggregate_undefined_comptime_value,
5235 aggregate_comptime_value,
5236 aggregate_location_comptime_value,
5237 comptime_value_field_runtime_bits,
5238 comptime_value_field_comptime_state,
5239 comptime_value_elem_runtime_bits,
5240 comptime_value_elem_comptime_state,
5241
5242 const decl_bytes = uleb128Bytes(@backingInt(AbbrevCode.decl_instance_extern_func));
5243 comptime {
5244 assert(uleb128Bytes(@backingInt(AbbrevCode.pad_1)) == 1);
5245 assert(uleb128Bytes(@backingInt(AbbrevCode.pad_n)) == 1);
5246 assert(uleb128Bytes(@backingInt(AbbrevCode.decl_alias)) == decl_bytes);
5247 }
5248
5249 const Attr = struct {
5250 DeclValEnum(DW.AT),
5251 DeclValEnum(DW.FORM),
5252 };
5253 const decl_abbrev_common_attrs = &[_]Attr{
5254 .{ .ZIG_parent, .ref_addr },
5255 .{ .decl_line, .data4 },
5256 .{ .decl_column, .udata },
5257 .{ .accessibility, .data1 },
5258 .{ .name, .strp },
5259 };
5260 const generic_decl_abbrev_common_attrs = decl_abbrev_common_attrs ++ &[_]Attr{
5261 .{ .declaration, .flag_present },
5262 };
5263 const decl_instance_abbrev_common_attrs = &[_]Attr{
5264 .{ .ZIG_parent, .ref_addr },
5265 .{ .abstract_origin, .ref_addr },
5266 };
5267 const abbrevs = std.EnumArray(AbbrevCode, struct {
5268 tag: DeclValEnum(DW.TAG),
5269 children: bool = false,
5270 attrs: []const Attr = &.{},
5271 }).init(.{
5272 .pad_1 = .{
5273 .tag = .ZIG_padding,
5274 },
5275 .pad_n = .{
5276 .tag = .ZIG_padding,
5277 .attrs = &.{
5278 .{ .ZIG_padding, .block },
5279 },
5280 },
5281 .decl_alias = .{
5282 .tag = .imported_declaration,
5283 .attrs = decl_abbrev_common_attrs ++ .{
5284 .{ .import, .ref_addr },
5285 },
5286 },
5287 .decl_empty_enum = .{
5288 .tag = .enumeration_type,
5289 .attrs = decl_abbrev_common_attrs ++ .{
5290 .{ .type, .ref_addr },
5291 },
5292 },
5293 .decl_enum = .{
5294 .tag = .enumeration_type,
5295 .children = true,
5296 .attrs = decl_abbrev_common_attrs ++ .{
5297 .{ .type, .ref_addr },
5298 },
5299 },
5300 .decl_namespace_struct = .{
5301 .tag = .structure_type,
5302 .attrs = decl_abbrev_common_attrs ++ .{
5303 .{ .declaration, .flag },
5304 },
5305 },
5306 .decl_struct = .{
5307 .tag = .structure_type,
5308 .children = true,
5309 .attrs = decl_abbrev_common_attrs ++ .{
5310 .{ .byte_size, .udata },
5311 .{ .alignment, .udata },
5312 },
5313 },
5314 .decl_packed_struct = .{
5315 .tag = .structure_type,
5316 .children = true,
5317 .attrs = decl_abbrev_common_attrs ++ .{
5318 .{ .type, .ref_addr },
5319 },
5320 },
5321 .decl_union = .{
5322 .tag = .union_type,
5323 .children = true,
5324 .attrs = decl_abbrev_common_attrs ++ .{
5325 .{ .byte_size, .udata },
5326 .{ .alignment, .udata },
5327 },
5328 },
5329 .decl_packed_union = .{
5330 .tag = .union_type,
5331 .children = true,
5332 .attrs = decl_abbrev_common_attrs ++ .{
5333 .{ .type, .ref_addr },
5334 },
5335 },
5336 .decl_var = .{
5337 .tag = .variable,
5338 .attrs = decl_abbrev_common_attrs ++ .{
5339 .{ .linkage_name, .strp },
5340 .{ .type, .ref_addr },
5341 .{ .location, .exprloc },
5342 .{ .alignment, .udata },
5343 .{ .external, .flag },
5344 },
5345 },
5346 .decl_const = .{
5347 .tag = .constant,
5348 .attrs = decl_abbrev_common_attrs ++ .{
5349 .{ .linkage_name, .strp },
5350 .{ .type, .ref_addr },
5351 .{ .alignment, .udata },
5352 .{ .external, .flag },
5353 },
5354 },
5355 .decl_const_runtime_bits = .{
5356 .tag = .constant,
5357 .attrs = decl_abbrev_common_attrs ++ .{
5358 .{ .linkage_name, .strp },
5359 .{ .type, .ref_addr },
5360 .{ .alignment, .udata },
5361 .{ .external, .flag },
5362 .{ .const_value, .block },
5363 },
5364 },
5365 .decl_const_comptime_state = .{
5366 .tag = .constant,
5367 .attrs = decl_abbrev_common_attrs ++ .{
5368 .{ .linkage_name, .strp },
5369 .{ .type, .ref_addr },
5370 .{ .alignment, .udata },
5371 .{ .external, .flag },
5372 .{ .ZIG_comptime_value, .ref_addr },
5373 },
5374 },
5375 .decl_const_runtime_bits_comptime_state = .{
5376 .tag = .constant,
5377 .attrs = decl_abbrev_common_attrs ++ .{
5378 .{ .linkage_name, .strp },
5379 .{ .type, .ref_addr },
5380 .{ .alignment, .udata },
5381 .{ .external, .flag },
5382 .{ .const_value, .block },
5383 .{ .ZIG_comptime_value, .ref_addr },
5384 },
5385 },
5386 .decl_nullary_func = .{
5387 .tag = .subprogram,
5388 .attrs = decl_abbrev_common_attrs ++ .{
5389 .{ .linkage_name, .strp },
5390 .{ .type, .ref_addr },
5391 .{ .low_pc, .addr },
5392 .{ .high_pc, .data4 },
5393 .{ .alignment, .udata },
5394 .{ .external, .flag },
5395 .{ .noreturn, .flag },
5396 },
5397 },
5398 .decl_func = .{
5399 .tag = .subprogram,
5400 .children = true,
5401 .attrs = decl_abbrev_common_attrs ++ .{
5402 .{ .linkage_name, .strp },
5403 .{ .type, .ref_addr },
5404 .{ .low_pc, .addr },
5405 .{ .high_pc, .data4 },
5406 .{ .alignment, .udata },
5407 .{ .external, .flag },
5408 .{ .noreturn, .flag },
5409 },
5410 },
5411 .decl_nullary_func_generic = .{
5412 .tag = .subprogram,
5413 .attrs = decl_abbrev_common_attrs ++ .{
5414 .{ .type, .ref_addr },
5415 },
5416 },
5417 .decl_func_generic = .{
5418 .tag = .subprogram,
5419 .children = true,
5420 .attrs = decl_abbrev_common_attrs ++ .{
5421 .{ .type, .ref_addr },
5422 },
5423 },
5424 .decl_extern_nullary_func = .{
5425 .tag = .subprogram,
5426 .attrs = decl_abbrev_common_attrs ++ .{
5427 .{ .linkage_name, .strp },
5428 .{ .type, .ref_addr },
5429 .{ .low_pc, .addr },
5430 .{ .external, .flag_present },
5431 .{ .noreturn, .flag },
5432 },
5433 },
5434 .decl_extern_func = .{
5435 .tag = .subprogram,
5436 .children = true,
5437 .attrs = decl_abbrev_common_attrs ++ .{
5438 .{ .linkage_name, .strp },
5439 .{ .type, .ref_addr },
5440 .{ .low_pc, .addr },
5441 .{ .external, .flag_present },
5442 .{ .noreturn, .flag },
5443 },
5444 },
5445 .generic_decl_var = .{
5446 .tag = .variable,
5447 .attrs = generic_decl_abbrev_common_attrs,
5448 },
5449 .generic_decl_const = .{
5450 .tag = .constant,
5451 .attrs = generic_decl_abbrev_common_attrs,
5452 },
5453 .generic_decl_func = .{
5454 .tag = .subprogram,
5455 .attrs = generic_decl_abbrev_common_attrs,
5456 },
5457 .decl_instance_alias = .{
5458 .tag = .imported_declaration,
5459 .attrs = decl_instance_abbrev_common_attrs ++ .{
5460 .{ .import, .ref_addr },
5461 },
5462 },
5463 .decl_instance_empty_enum = .{
5464 .tag = .enumeration_type,
5465 .attrs = decl_instance_abbrev_common_attrs ++ .{
5466 .{ .type, .ref_addr },
5467 },
5468 },
5469 .decl_instance_enum = .{
5470 .tag = .enumeration_type,
5471 .children = true,
5472 .attrs = decl_instance_abbrev_common_attrs ++ .{
5473 .{ .type, .ref_addr },
5474 },
5475 },
5476 .decl_instance_namespace_struct = .{
5477 .tag = .structure_type,
5478 .attrs = decl_instance_abbrev_common_attrs ++ .{
5479 .{ .declaration, .flag },
5480 },
5481 },
5482 .decl_instance_struct = .{
5483 .tag = .structure_type,
5484 .children = true,
5485 .attrs = decl_instance_abbrev_common_attrs ++ .{
5486 .{ .byte_size, .udata },
5487 .{ .alignment, .udata },
5488 },
5489 },
5490 .decl_instance_packed_struct = .{
5491 .tag = .structure_type,
5492 .children = true,
5493 .attrs = decl_instance_abbrev_common_attrs ++ .{
5494 .{ .type, .ref_addr },
5495 },
5496 },
5497 .decl_instance_union = .{
5498 .tag = .union_type,
5499 .children = true,
5500 .attrs = decl_instance_abbrev_common_attrs ++ .{
5501 .{ .byte_size, .udata },
5502 .{ .alignment, .udata },
5503 },
5504 },
5505 .decl_instance_packed_union = .{
5506 .tag = .union_type,
5507 .children = true,
5508 .attrs = decl_instance_abbrev_common_attrs ++ .{
5509 .{ .type, .ref_addr },
5510 },
5511 },
5512 .decl_instance_var = .{
5513 .tag = .variable,
5514 .attrs = decl_instance_abbrev_common_attrs ++ .{
5515 .{ .linkage_name, .strp },
5516 .{ .type, .ref_addr },
5517 .{ .location, .exprloc },
5518 .{ .alignment, .udata },
5519 .{ .external, .flag },
5520 },
5521 },
5522 .decl_instance_const = .{
5523 .tag = .constant,
5524 .attrs = decl_instance_abbrev_common_attrs ++ .{
5525 .{ .linkage_name, .strp },
5526 .{ .type, .ref_addr },
5527 .{ .alignment, .udata },
5528 .{ .external, .flag },
5529 },
5530 },
5531 .decl_instance_const_runtime_bits = .{
5532 .tag = .constant,
5533 .attrs = decl_instance_abbrev_common_attrs ++ .{
5534 .{ .linkage_name, .strp },
5535 .{ .type, .ref_addr },
5536 .{ .alignment, .udata },
5537 .{ .external, .flag },
5538 .{ .const_value, .block },
5539 },
5540 },
5541 .decl_instance_const_comptime_state = .{
5542 .tag = .constant,
5543 .attrs = decl_instance_abbrev_common_attrs ++ .{
5544 .{ .linkage_name, .strp },
5545 .{ .type, .ref_addr },
5546 .{ .alignment, .udata },
5547 .{ .external, .flag },
5548 .{ .ZIG_comptime_value, .ref_addr },
5549 },
5550 },
5551 .decl_instance_const_runtime_bits_comptime_state = .{
5552 .tag = .constant,
5553 .attrs = decl_instance_abbrev_common_attrs ++ .{
5554 .{ .linkage_name, .strp },
5555 .{ .type, .ref_addr },
5556 .{ .alignment, .udata },
5557 .{ .external, .flag },
5558 .{ .const_value, .block },
5559 .{ .ZIG_comptime_value, .ref_addr },
5560 },
5561 },
5562 .decl_instance_nullary_func = .{
5563 .tag = .subprogram,
5564 .attrs = decl_instance_abbrev_common_attrs ++ .{
5565 .{ .linkage_name, .strp },
5566 .{ .type, .ref_addr },
5567 .{ .low_pc, .addr },
5568 .{ .high_pc, .data4 },
5569 .{ .alignment, .udata },
5570 .{ .external, .flag },
5571 .{ .noreturn, .flag },
5572 },
5573 },
5574 .decl_instance_func = .{
5575 .tag = .subprogram,
5576 .children = true,
5577 .attrs = decl_instance_abbrev_common_attrs ++ .{
5578 .{ .linkage_name, .strp },
5579 .{ .type, .ref_addr },
5580 .{ .low_pc, .addr },
5581 .{ .high_pc, .data4 },
5582 .{ .alignment, .udata },
5583 .{ .external, .flag },
5584 .{ .noreturn, .flag },
5585 },
5586 },
5587 .decl_instance_nullary_func_generic = .{
5588 .tag = .subprogram,
5589 .attrs = decl_instance_abbrev_common_attrs ++ .{
5590 .{ .type, .ref_addr },
5591 },
5592 },
5593 .decl_instance_func_generic = .{
5594 .tag = .subprogram,
5595 .children = true,
5596 .attrs = decl_instance_abbrev_common_attrs ++ .{
5597 .{ .type, .ref_addr },
5598 },
5599 },
5600 .decl_instance_extern_nullary_func = .{
5601 .tag = .subprogram,
5602 .attrs = decl_instance_abbrev_common_attrs ++ .{
5603 .{ .linkage_name, .strp },
5604 .{ .type, .ref_addr },
5605 .{ .low_pc, .addr },
5606 .{ .external, .flag_present },
5607 .{ .noreturn, .flag },
5608 },
5609 },
5610 .decl_instance_extern_func = .{
5611 .tag = .subprogram,
5612 .children = true,
5613 .attrs = decl_instance_abbrev_common_attrs ++ .{
5614 .{ .linkage_name, .strp },
5615 .{ .type, .ref_addr },
5616 .{ .low_pc, .addr },
5617 .{ .external, .flag_present },
5618 .{ .noreturn, .flag },
5619 },
5620 },
5621 .compile_unit = .{
5622 .tag = .compile_unit,
5623 .children = true,
5624 .attrs = &.{
5625 .{ .language, .data1 },
5626 .{ .producer, .line_strp },
5627 .{ .comp_dir, .line_strp },
5628 .{ .name, .line_strp },
5629 .{ .base_types, .ref_addr },
5630 .{ .stmt_list, .sec_offset },
5631 .{ .rnglists_base, .sec_offset },
5632 .{ .ranges, .rnglistx },
5633 },
5634 },
5635 .module = .{
5636 .tag = .module,
5637 .children = true,
5638 .attrs = &.{
5639 .{ .name, .strp },
5640 .{ .ranges, .rnglistx },
5641 },
5642 },
5643 .empty_file = .{
5644 .tag = .structure_type,
5645 .attrs = &.{
5646 .{ .decl_file, .udata },
5647 .{ .name, .strp },
5648 },
5649 },
5650 .file = .{
5651 .tag = .structure_type,
5652 .children = true,
5653 .attrs = &.{
5654 .{ .decl_file, .udata },
5655 .{ .name, .strp },
5656 .{ .byte_size, .udata },
5657 .{ .alignment, .udata },
5658 },
5659 },
5660 .access = .{
5661 .tag = .member,
5662 .attrs = &.{
5663 .{ .name, .strp },
5664 },
5665 },
5666 .enum_field = .{
5667 .tag = .enumerator,
5668 .attrs = &.{
5669 .{ .const_value, .indirect },
5670 .{ .name, .strp },
5671 },
5672 },
5673 .generated_field = .{
5674 .tag = .member,
5675 .attrs = &.{
5676 .{ .name, .strp },
5677 .{ .type, .ref_addr },
5678 .{ .data_member_location, .udata },
5679 .{ .artificial, .flag_present },
5680 },
5681 },
5682 .field = .{
5683 .tag = .member,
5684 .attrs = &.{
5685 .{ .name, .strp },
5686 .{ .type, .ref_addr },
5687 .{ .data_member_location, .udata },
5688 .{ .alignment, .udata },
5689 },
5690 },
5691 .field_default_runtime_bits = .{
5692 .tag = .member,
5693 .attrs = &.{
5694 .{ .name, .strp },
5695 .{ .type, .ref_addr },
5696 .{ .data_member_location, .udata },
5697 .{ .alignment, .udata },
5698 .{ .default_value, .block },
5699 },
5700 },
5701 .field_default_comptime_state = .{
5702 .tag = .member,
5703 .attrs = &.{
5704 .{ .name, .strp },
5705 .{ .type, .ref_addr },
5706 .{ .data_member_location, .udata },
5707 .{ .alignment, .udata },
5708 .{ .ZIG_comptime_value, .ref_addr },
5709 },
5710 },
5711 .field_comptime = .{
5712 .tag = .member,
5713 .attrs = &.{
5714 .{ .const_expr, .flag_present },
5715 .{ .name, .strp },
5716 .{ .type, .ref_addr },
5717 },
5718 },
5719 .field_comptime_runtime_bits = .{
5720 .tag = .member,
5721 .attrs = &.{
5722 .{ .const_expr, .flag_present },
5723 .{ .name, .strp },
5724 .{ .type, .ref_addr },
5725 .{ .const_value, .block },
5726 },
5727 },
5728 .field_comptime_comptime_state = .{
5729 .tag = .member,
5730 .attrs = &.{
5731 .{ .const_expr, .flag_present },
5732 .{ .name, .strp },
5733 .{ .type, .ref_addr },
5734 .{ .ZIG_comptime_value, .ref_addr },
5735 },
5736 },
5737 .packed_field = .{
5738 .tag = .member,
5739 .attrs = &.{
5740 .{ .name, .strp },
5741 .{ .type, .ref_addr },
5742 .{ .data_bit_offset, .udata },
5743 },
5744 },
5745 .tagged_union = .{
5746 .tag = .variant_part,
5747 .children = true,
5748 .attrs = &.{
5749 .{ .discr, .ref_addr },
5750 },
5751 },
5752 .tagged_union_field = .{
5753 .tag = .variant,
5754 .children = true,
5755 .attrs = &.{
5756 .{ .discr_value, .indirect },
5757 },
5758 },
5759 .tagged_union_default_field = .{
5760 .tag = .variant,
5761 .children = true,
5762 .attrs = &.{},
5763 },
5764 .void_type = .{
5765 .tag = .unspecified_type,
5766 .attrs = &.{
5767 .{ .name, .strp },
5768 },
5769 },
5770 .numeric_type = .{
5771 .tag = .base_type,
5772 .attrs = &.{
5773 .{ .name, .strp },
5774 .{ .encoding, .data1 },
5775 .{ .bit_size, .udata },
5776 .{ .byte_size, .udata },
5777 .{ .alignment, .udata },
5778 },
5779 },
5780 .inferred_error_set_type = .{
5781 .tag = .typedef,
5782 .attrs = &.{
5783 .{ .name, .strp },
5784 .{ .type, .ref_addr },
5785 },
5786 },
5787 .ptr_type = .{
5788 .tag = .pointer_type,
5789 .attrs = &.{
5790 .{ .name, .strp },
5791 .{ .address_class, .data1 },
5792 .{ .type, .ref_addr },
5793 },
5794 },
5795 .ptr_sentinel_type = .{
5796 .tag = .pointer_type,
5797 .attrs = &.{
5798 .{ .name, .strp },
5799 .{ .ZIG_sentinel, .block },
5800 .{ .address_class, .data1 },
5801 .{ .type, .ref_addr },
5802 },
5803 },
5804 .ptr_aligned_type = .{
5805 .tag = .pointer_type,
5806 .attrs = &.{
5807 .{ .name, .strp },
5808 .{ .alignment, .udata },
5809 .{ .address_class, .data1 },
5810 .{ .type, .ref_addr },
5811 },
5812 },
5813 .ptr_aligned_sentinel_type = .{
5814 .tag = .pointer_type,
5815 .attrs = &.{
5816 .{ .name, .strp },
5817 .{ .ZIG_sentinel, .block },
5818 .{ .alignment, .udata },
5819 .{ .address_class, .data1 },
5820 .{ .type, .ref_addr },
5821 },
5822 },
5823 .is_const = .{
5824 .tag = .const_type,
5825 .attrs = &.{
5826 .{ .type, .ref_addr },
5827 },
5828 },
5829 .is_volatile = .{
5830 .tag = .volatile_type,
5831 .attrs = &.{
5832 .{ .type, .ref_addr },
5833 },
5834 },
5835 .array_type = .{
5836 .tag = .array_type,
5837 .children = true,
5838 .attrs = &.{
5839 .{ .name, .strp },
5840 .{ .type, .ref_addr },
5841 },
5842 },
5843 .array_sentinel_type = .{
5844 .tag = .array_type,
5845 .children = true,
5846 .attrs = &.{
5847 .{ .name, .strp },
5848 .{ .ZIG_sentinel, .block },
5849 .{ .type, .ref_addr },
5850 },
5851 },
5852 .vector_type = .{
5853 .tag = .array_type,
5854 .children = true,
5855 .attrs = &.{
5856 .{ .name, .strp },
5857 .{ .type, .ref_addr },
5858 .{ .GNU_vector, .flag_present },
5859 },
5860 },
5861 .array_index = .{
5862 .tag = .subrange_type,
5863 .attrs = &.{
5864 .{ .lower_bound, .udata },
5865 },
5866 },
5867 .array_len = .{
5868 .tag = .subrange_type,
5869 .attrs = &.{
5870 .{ .type, .ref_addr },
5871 .{ .count, .udata },
5872 },
5873 },
5874 .nullary_func_type = .{
5875 .tag = .subroutine_type,
5876 .attrs = &.{
5877 .{ .name, .strp },
5878 .{ .calling_convention, .data1 },
5879 .{ .type, .ref_addr },
5880 },
5881 },
5882 .func_type = .{
5883 .tag = .subroutine_type,
5884 .children = true,
5885 .attrs = &.{
5886 .{ .name, .strp },
5887 .{ .calling_convention, .data1 },
5888 .{ .type, .ref_addr },
5889 },
5890 },
5891 .func_type_param = .{
5892 .tag = .formal_parameter,
5893 .attrs = &.{
5894 .{ .type, .ref_addr },
5895 },
5896 },
5897 .is_var_args = .{
5898 .tag = .unspecified_parameters,
5899 },
5900 .generated_empty_enum_type = .{
5901 .tag = .enumeration_type,
5902 .attrs = &.{
5903 .{ .name, .strp },
5904 .{ .type, .ref_addr },
5905 },
5906 },
5907 .generated_enum_type = .{
5908 .tag = .enumeration_type,
5909 .children = true,
5910 .attrs = &.{
5911 .{ .name, .strp },
5912 .{ .type, .ref_addr },
5913 },
5914 },
5915 .generated_empty_struct_type = .{
5916 .tag = .structure_type,
5917 .attrs = &.{
5918 .{ .name, .strp },
5919 .{ .declaration, .flag },
5920 },
5921 },
5922 .generated_struct_type = .{
5923 .tag = .structure_type,
5924 .children = true,
5925 .attrs = &.{
5926 .{ .name, .strp },
5927 .{ .byte_size, .udata },
5928 .{ .alignment, .udata },
5929 },
5930 },
5931 .generated_union_type = .{
5932 .tag = .union_type,
5933 .children = true,
5934 .attrs = &.{
5935 .{ .name, .strp },
5936 .{ .byte_size, .udata },
5937 .{ .alignment, .udata },
5938 },
5939 },
5940 .empty_enum_type = .{
5941 .tag = .enumeration_type,
5942 .attrs = &.{
5943 .{ .decl_file, .udata },
5944 .{ .name, .strp },
5945 .{ .type, .ref_addr },
5946 },
5947 },
5948 .enum_type = .{
5949 .tag = .enumeration_type,
5950 .children = true,
5951 .attrs = &.{
5952 .{ .decl_file, .udata },
5953 .{ .name, .strp },
5954 .{ .type, .ref_addr },
5955 },
5956 },
5957 .empty_struct_type = .{
5958 .tag = .structure_type,
5959 .attrs = &.{
5960 .{ .decl_file, .udata },
5961 .{ .name, .strp },
5962 .{ .declaration, .flag },
5963 },
5964 },
5965 .struct_type = .{
5966 .tag = .structure_type,
5967 .children = true,
5968 .attrs = &.{
5969 .{ .decl_file, .udata },
5970 .{ .name, .strp },
5971 .{ .byte_size, .udata },
5972 .{ .alignment, .udata },
5973 },
5974 },
5975 .empty_packed_struct_type = .{
5976 .tag = .structure_type,
5977 .attrs = &.{
5978 .{ .decl_file, .udata },
5979 .{ .name, .strp },
5980 .{ .type, .ref_addr },
5981 },
5982 },
5983 .packed_struct_type = .{
5984 .tag = .structure_type,
5985 .children = true,
5986 .attrs = &.{
5987 .{ .decl_file, .udata },
5988 .{ .name, .strp },
5989 .{ .type, .ref_addr },
5990 },
5991 },
5992 .empty_union_type = .{
5993 .tag = .union_type,
5994 .attrs = &.{
5995 .{ .decl_file, .udata },
5996 .{ .name, .strp },
5997 .{ .byte_size, .udata },
5998 .{ .alignment, .udata },
5999 },
6000 },
6001 .union_type = .{
6002 .tag = .union_type,
6003 .children = true,
6004 .attrs = &.{
6005 .{ .decl_file, .udata },
6006 .{ .name, .strp },
6007 .{ .byte_size, .udata },
6008 .{ .alignment, .udata },
6009 },
6010 },
6011 .empty_packed_union_type = .{
6012 .tag = .union_type,
6013 .attrs = &.{
6014 .{ .decl_file, .udata },
6015 .{ .name, .strp },
6016 .{ .type, .ref_addr },
6017 },
6018 },
6019 .packed_union_type = .{
6020 .tag = .union_type,
6021 .children = true,
6022 .attrs = &.{
6023 .{ .decl_file, .udata },
6024 .{ .name, .strp },
6025 .{ .type, .ref_addr },
6026 },
6027 },
6028 .builtin_extern_nullary_func = .{
6029 .tag = .subprogram,
6030 .attrs = &.{
6031 .{ .ZIG_parent, .ref_addr },
6032 .{ .linkage_name, .strp },
6033 .{ .type, .ref_addr },
6034 .{ .low_pc, .addr },
6035 .{ .external, .flag_present },
6036 .{ .noreturn, .flag },
6037 },
6038 },
6039 .builtin_extern_func = .{
6040 .tag = .subprogram,
6041 .children = true,
6042 .attrs = &.{
6043 .{ .ZIG_parent, .ref_addr },
6044 .{ .linkage_name, .strp },
6045 .{ .type, .ref_addr },
6046 .{ .low_pc, .addr },
6047 .{ .external, .flag_present },
6048 .{ .noreturn, .flag },
6049 },
6050 },
6051 .builtin_extern_var = .{
6052 .tag = .variable,
6053 .attrs = &.{
6054 .{ .ZIG_parent, .ref_addr },
6055 .{ .linkage_name, .strp },
6056 .{ .type, .ref_addr },
6057 .{ .location, .exprloc },
6058 .{ .external, .flag_present },
6059 },
6060 },
6061 .empty_block = .{
6062 .tag = .lexical_block,
6063 .attrs = &.{
6064 .{ .low_pc, .addr },
6065 .{ .high_pc, .data4 },
6066 },
6067 },
6068 .block = .{
6069 .tag = .lexical_block,
6070 .children = true,
6071 .attrs = &.{
6072 .{ .low_pc, .addr },
6073 .{ .high_pc, .data4 },
6074 },
6075 },
6076 .empty_inlined_func = .{
6077 .tag = .inlined_subroutine,
6078 .attrs = &.{
6079 .{ .abstract_origin, .ref_addr },
6080 .{ .call_line, .udata },
6081 .{ .call_column, .udata },
6082 .{ .low_pc, .addr },
6083 .{ .high_pc, .data4 },
6084 },
6085 },
6086 .inlined_func = .{
6087 .tag = .inlined_subroutine,
6088 .children = true,
6089 .attrs = &.{
6090 .{ .abstract_origin, .ref_addr },
6091 .{ .call_line, .udata },
6092 .{ .call_column, .udata },
6093 .{ .low_pc, .addr },
6094 .{ .high_pc, .data4 },
6095 },
6096 },
6097 .arg = .{
6098 .tag = .formal_parameter,
6099 .attrs = &.{
6100 .{ .name, .strp },
6101 .{ .type, .ref_addr },
6102 .{ .location, .exprloc },
6103 },
6104 },
6105 .unnamed_arg = .{
6106 .tag = .formal_parameter,
6107 .attrs = &.{
6108 .{ .type, .ref_addr },
6109 .{ .location, .exprloc },
6110 },
6111 },
6112 .comptime_arg = .{
6113 .tag = .formal_parameter,
6114 .attrs = &.{
6115 .{ .const_expr, .flag_present },
6116 .{ .name, .strp },
6117 .{ .type, .ref_addr },
6118 },
6119 },
6120 .unnamed_comptime_arg = .{
6121 .tag = .formal_parameter,
6122 .attrs = &.{
6123 .{ .const_expr, .flag_present },
6124 .{ .type, .ref_addr },
6125 },
6126 },
6127 .comptime_arg_runtime_bits = .{
6128 .tag = .formal_parameter,
6129 .attrs = &.{
6130 .{ .const_expr, .flag_present },
6131 .{ .name, .strp },
6132 .{ .type, .ref_addr },
6133 .{ .const_value, .block },
6134 },
6135 },
6136 .unnamed_comptime_arg_runtime_bits = .{
6137 .tag = .formal_parameter,
6138 .attrs = &.{
6139 .{ .const_expr, .flag_present },
6140 .{ .type, .ref_addr },
6141 .{ .const_value, .block },
6142 },
6143 },
6144 .comptime_arg_comptime_state = .{
6145 .tag = .formal_parameter,
6146 .attrs = &.{
6147 .{ .const_expr, .flag_present },
6148 .{ .name, .strp },
6149 .{ .type, .ref_addr },
6150 .{ .ZIG_comptime_value, .ref_addr },
6151 },
6152 },
6153 .unnamed_comptime_arg_comptime_state = .{
6154 .tag = .formal_parameter,
6155 .attrs = &.{
6156 .{ .const_expr, .flag_present },
6157 .{ .type, .ref_addr },
6158 .{ .ZIG_comptime_value, .ref_addr },
6159 },
6160 },
6161 .comptime_arg_runtime_bits_comptime_state = .{
6162 .tag = .formal_parameter,
6163 .attrs = &.{
6164 .{ .const_expr, .flag_present },
6165 .{ .name, .strp },
6166 .{ .type, .ref_addr },
6167 .{ .const_value, .block },
6168 .{ .ZIG_comptime_value, .ref_addr },
6169 },
6170 },
6171 .unnamed_comptime_arg_runtime_bits_comptime_state = .{
6172 .tag = .formal_parameter,
6173 .attrs = &.{
6174 .{ .const_expr, .flag_present },
6175 .{ .type, .ref_addr },
6176 .{ .const_value, .block },
6177 .{ .ZIG_comptime_value, .ref_addr },
6178 },
6179 },
6180 .extern_param = .{
6181 .tag = .formal_parameter,
6182 .attrs = &.{
6183 .{ .type, .ref_addr },
6184 },
6185 },
6186 .local_var = .{
6187 .tag = .variable,
6188 .attrs = &.{
6189 .{ .name, .strp },
6190 .{ .type, .ref_addr },
6191 .{ .location, .exprloc },
6192 },
6193 },
6194 .local_const = .{
6195 .tag = .constant,
6196 .attrs = &.{
6197 .{ .name, .strp },
6198 .{ .type, .ref_addr },
6199 },
6200 },
6201 .local_const_runtime_bits = .{
6202 .tag = .constant,
6203 .attrs = &.{
6204 .{ .name, .strp },
6205 .{ .type, .ref_addr },
6206 .{ .const_value, .block },
6207 },
6208 },
6209 .local_const_comptime_state = .{
6210 .tag = .constant,
6211 .attrs = &.{
6212 .{ .name, .strp },
6213 .{ .type, .ref_addr },
6214 .{ .ZIG_comptime_value, .ref_addr },
6215 },
6216 },
6217 .local_const_runtime_bits_comptime_state = .{
6218 .tag = .constant,
6219 .attrs = &.{
6220 .{ .name, .strp },
6221 .{ .type, .ref_addr },
6222 .{ .const_value, .block },
6223 .{ .ZIG_comptime_value, .ref_addr },
6224 },
6225 },
6226 .undefined_comptime_value = .{
6227 .tag = .ZIG_comptime_value,
6228 .attrs = &.{
6229 .{ .type, .ref_addr },
6230 },
6231 },
6232 .aggregate_undefined_comptime_value = .{
6233 .tag = .ZIG_comptime_value,
6234 .children = true,
6235 .attrs = &.{
6236 .{ .type, .ref_addr },
6237 },
6238 },
6239 .comptime_value = .{
6240 .tag = .ZIG_comptime_value,
6241 .attrs = &.{
6242 .{ .type, .ref_addr },
6243 .{ .const_value, .indirect },
6244 },
6245 },
6246 .aggregate_comptime_value = .{
6247 .tag = .ZIG_comptime_value,
6248 .children = true,
6249 .attrs = &.{
6250 .{ .type, .ref_addr },
6251 .{ .const_value, .indirect },
6252 },
6253 },
6254 .location_comptime_value = .{
6255 .tag = .ZIG_comptime_value,
6256 .attrs = &.{
6257 .{ .type, .ref_addr },
6258 .{ .location, .exprloc },
6259 },
6260 },
6261 .aggregate_location_comptime_value = .{
6262 .tag = .ZIG_comptime_value,
6263 .children = true,
6264 .attrs = &.{
6265 .{ .type, .ref_addr },
6266 .{ .location, .exprloc },
6267 },
6268 },
6269 .comptime_value_field_runtime_bits = .{
6270 .tag = .member,
6271 .attrs = &.{
6272 .{ .name, .strp },
6273 .{ .const_value, .block },
6274 },
6275 },
6276 .comptime_value_field_comptime_state = .{
6277 .tag = .member,
6278 .attrs = &.{
6279 .{ .name, .strp },
6280 .{ .ZIG_comptime_value, .ref_addr },
6281 },
6282 },
6283 .comptime_value_elem_runtime_bits = .{
6284 .tag = .member,
6285 .attrs = &.{
6286 .{ .const_value, .block },
6287 },
6288 },
6289 .comptime_value_elem_comptime_state = .{
6290 .tag = .member,
6291 .attrs = &.{
6292 .{ .ZIG_comptime_value, .ref_addr },
6293 },
6294 },
6295 .null = undefined,
6296 });
6297};
6298
6299fn getFile(dwarf: *Dwarf) ?Io.File {
6300 if (dwarf.bin_file.cast(.macho)) |macho_file| if (macho_file.d_sym) |*d_sym| return d_sym.file;
6301 return dwarf.bin_file.file;
6302}
6303
6304fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {
6305 const entry = try dwarf.debug_aranges.section.getUnit(unit).addEntry(dwarf.gpa);
6306 assert(try dwarf.debug_frame.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6307 assert(try dwarf.debug_info.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6308 assert(try dwarf.debug_line.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6309 assert(try dwarf.debug_loclists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6310 assert(try dwarf.debug_rnglists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6311 return entry;
6312}
6313
6314fn freeCommonEntry(
6315 dwarf: *Dwarf,
6316 unit: Unit.Index,
6317 entry: Entry.Index,
6318) (UpdateError || Writer.Error)!void {
6319 try dwarf.debug_aranges.section.freeEntry(unit, entry, dwarf);
6320 try dwarf.debug_frame.section.freeEntry(unit, entry, dwarf);
6321 try dwarf.debug_info.section.freeEntry(unit, entry, dwarf);
6322 try dwarf.debug_line.section.freeEntry(unit, entry, dwarf);
6323 try dwarf.debug_loclists.section.freeEntry(unit, entry, dwarf);
6324 try dwarf.debug_rnglists.section.freeEntry(unit, entry, dwarf);
6325}
6326
6327fn writeInt(dwarf: *Dwarf, buf: []u8, int: u64) void {
6328 switch (buf.len) {
6329 inline 0...8 => |len| std.mem.writeInt(
6330 @Int(.unsigned, len * 8),
6331 buf[0..len],
6332 @intCast(int),
6333 dwarf.endian,
6334 ),
6335 else => unreachable,
6336 }
6337}
6338
6339fn resolveReloc(dwarf: *Dwarf, source: u64, target: u64, size: u32) RelocError!void {
6340 const comp = dwarf.bin_file.comp;
6341 const io = comp.io;
6342 var buf: [8]u8 = undefined;
6343 dwarf.writeInt(buf[0..size], target);
6344 try dwarf.getFile().?.writePositionalAll(io, buf[0..size], source);
6345}
6346
6347fn unitLengthBytes(dwarf: *Dwarf) u32 {
6348 return switch (dwarf.format) {
6349 .@"32" => 4,
6350 .@"64" => 4 + 8,
6351 };
6352}
6353
6354fn sectionOffsetBytes(dwarf: *Dwarf) u32 {
6355 return switch (dwarf.format) {
6356 .@"32" => 4,
6357 .@"64" => 8,
6358 };
6359}
6360
6361fn uleb128Bytes(value: anytype) u32 {
6362 var buf: [64]u8 = undefined;
6363 var dw: Writer.Discarding = .init(&buf);
6364 dw.writer.writeUleb128(value) catch unreachable;
6365 return @intCast(dw.count + dw.writer.end);
6366}
6367
6368fn sleb128Bytes(value: anytype) u32 {
6369 var buf: [64]u8 = undefined;
6370 var dw: Writer.Discarding = .init(&buf);
6371 dw.writer.writeSleb128(value) catch unreachable;
6372 return @intCast(dw.count + dw.writer.end);
6373}
6374
6375/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
6376const force_incremental = false;
6377inline fn incremental(dwarf: Dwarf) bool {
6378 return force_incremental or dwarf.bin_file.comp.config.incremental;
6379}