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.checkAny(&.{ .llvm_backend, .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 advanceLineAndPc(
1630 wip_nav: *WipNav,
1631 delta_line: i33,
1632 delta_pc: u64,
1633 end: bool,
1634 ) Allocator.Error!void {
1635 return wip_nav.advanceLineAndPcWriterError(
1636 delta_line,
1637 delta_pc,
1638 end,
1639 ) catch |err| switch (err) {
1640 error.WriteFailed => error.OutOfMemory,
1641 };
1642 }
1643 fn advanceLineAndPcWriterError(
1644 wip_nav: *WipNav,
1645 delta_line: i33,
1646 delta_pc: u64,
1647 end: bool,
1648 ) Writer.Error!void {
1649 const dlw = &wip_nav.debug_line.writer;
1650
1651 const header = wip_nav.dwarf.debug_line.header;
1652 assert(header.maximum_operations_per_instruction == 1);
1653 const delta_op: u64 = 0;
1654
1655 const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or
1656 delta_line - header.line_base >= header.line_range)
1657 remaining: {
1658 assert(delta_line != 0);
1659 try dlw.writeByte(DW.LNS.advance_line);
1660 try dlw.writeSleb128(delta_line);
1661 break :remaining 0;
1662 } else delta_line);
1663
1664 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
1665 header.maximum_operations_per_instruction + delta_op;
1666 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
1667 const remaining_op_advance: u8 = @intCast(if (end or
1668 op_advance >= 2 * max_op_advance)
1669 remaining: {
1670 if (op_advance == max_op_advance) {
1671 try dlw.writeByte(DW.LNS.const_add_pc);
1672 } else if (op_advance != 0) {
1673 try dlw.writeByte(DW.LNS.advance_pc);
1674 try dlw.writeUleb128(op_advance);
1675 } else assert(end);
1676 break :remaining 0;
1677 } else if (op_advance >= max_op_advance) remaining: {
1678 try dlw.writeByte(DW.LNS.const_add_pc);
1679 break :remaining op_advance - max_op_advance;
1680 } else op_advance);
1681
1682 if (remaining_delta_line != 0 or remaining_op_advance != 0) {
1683 assert(!end);
1684 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +
1685 (header.line_range * remaining_op_advance) + header.opcode_base));
1686 } else if (end) {
1687 try dlw.writeByte(DW.LNS.extended_op);
1688 try dlw.writeUleb128(1);
1689 try dlw.writeByte(DW.LNE.end_sequence);
1690 } else try dlw.writeByte(DW.LNS.copy);
1691 }
1692
1693 pub fn setColumn(wip_nav: *WipNav, column: u32) Allocator.Error!void {
1694 return wip_nav.setColumnWriterError(column) catch |err| switch (err) {
1695 error.WriteFailed => error.OutOfMemory,
1696 };
1697 }
1698 fn setColumnWriterError(wip_nav: *WipNav, column: u32) Writer.Error!void {
1699 const dlw = &wip_nav.debug_line.writer;
1700 try dlw.writeByte(DW.LNS.set_column);
1701 try dlw.writeUleb128(column + 1);
1702 }
1703
1704 pub fn negateStmt(wip_nav: *WipNav) Allocator.Error!void {
1705 return wip_nav.negateStmtWriterError() catch |err| switch (err) {
1706 error.WriteFailed => error.OutOfMemory,
1707 };
1708 }
1709 fn negateStmtWriterError(wip_nav: *WipNav) Writer.Error!void {
1710 try wip_nav.debug_line.writer.writeByte(DW.LNS.negate_stmt);
1711 }
1712
1713 pub fn setPrologueEnd(wip_nav: *WipNav) Allocator.Error!void {
1714 return wip_nav.setPrologueEndWriterError() catch |err| switch (err) {
1715 error.WriteFailed => error.OutOfMemory,
1716 };
1717 }
1718 fn setPrologueEndWriterError(wip_nav: *WipNav) Writer.Error!void {
1719 try wip_nav.debug_line.writer.writeByte(DW.LNS.set_prologue_end);
1720 }
1721
1722 pub fn setEpilogueBegin(wip_nav: *WipNav) Allocator.Error!void {
1723 return wip_nav.setEpilogueBeginWriterError() catch |err| switch (err) {
1724 error.WriteFailed => error.OutOfMemory,
1725 };
1726 }
1727 fn setEpilogueBeginWriterError(wip_nav: *WipNav) Writer.Error!void {
1728 try wip_nav.debug_line.writer.writeByte(DW.LNS.set_epilogue_begin);
1729 }
1730
1731 pub fn enterBlock(wip_nav: *WipNav, code_off: u64) UpdateError!void {
1732 return wip_nav.enterBlockWriterError(code_off) catch |err| switch (err) {
1733 error.WriteFailed => error.OutOfMemory,
1734 else => |e| e,
1735 };
1736 }
1737 fn enterBlockWriterError(wip_nav: *WipNav, code_off: u64) (UpdateError || Writer.Error)!void {
1738 const dwarf = wip_nav.dwarf;
1739 const diw = &wip_nav.debug_info.writer;
1740 const block = try wip_nav.blocks.addOne(dwarf.gpa);
1741
1742 block.abbrev_code = @intCast(diw.end);
1743 try wip_nav.abbrevCode(.block);
1744 block.low_pc_off = code_off;
1745 try wip_nav.infoAddrSym(wip_nav.func_sym_index, code_off);
1746 block.high_pc = @intCast(diw.end);
1747 try diw.writeInt(u32, 0, dwarf.endian);
1748 wip_nav.any_children = false;
1749 }
1750
1751 pub fn leaveBlock(wip_nav: *WipNav, code_off: u64) UpdateError!void {
1752 return wip_nav.leaveBlockWriterError(code_off) catch |err| switch (err) {
1753 error.WriteFailed => error.OutOfMemory,
1754 else => |e| e,
1755 };
1756 }
1757 fn leaveBlockWriterError(wip_nav: *WipNav, code_off: u64) (UpdateError || Writer.Error)!void {
1758 const block_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.block));
1759 const block = wip_nav.blocks.pop().?;
1760 if (wip_nav.any_children)
1761 try wip_nav.debug_info.writer.writeUleb128(@backingInt(AbbrevCode.null))
1762 else
1763 std.leb.writeUnsignedFixed(
1764 block_bytes,
1765 wip_nav.debug_info.written()[block.abbrev_code..][0..block_bytes],
1766 @intCast(try wip_nav.dwarf.refAbbrevCode(.empty_block)),
1767 );
1768 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);
1769 wip_nav.any_children = true;
1770 }
1771
1772 pub fn enterInlineFunc(
1773 wip_nav: *WipNav,
1774 func: InternPool.Index,
1775 code_off: u64,
1776 line: u32,
1777 column: u32,
1778 ) UpdateError!void {
1779 return wip_nav.enterInlineFuncWriterError(func, code_off, line, column) catch |err| switch (err) {
1780 error.WriteFailed => error.OutOfMemory,
1781 else => |e| e,
1782 };
1783 }
1784 fn enterInlineFuncWriterError(
1785 wip_nav: *WipNav,
1786 func: InternPool.Index,
1787 code_off: u64,
1788 line: u32,
1789 column: u32,
1790 ) (UpdateError || Writer.Error)!void {
1791 const dwarf = wip_nav.dwarf;
1792 const zcu = wip_nav.pt.zcu;
1793 const diw = &wip_nav.debug_info.writer;
1794 const block = try wip_nav.blocks.addOne(dwarf.gpa);
1795
1796 block.abbrev_code = @intCast(diw.end);
1797 try wip_nav.abbrevCode(.inlined_func);
1798 try wip_nav.refNav(zcu.funcInfo(func).owner_nav);
1799 try diw.writeUleb128(zcu.navSrcLine(zcu.funcInfo(wip_nav.func).owner_nav) + line + 1);
1800 try diw.writeUleb128(column + 1);
1801 block.low_pc_off = code_off;
1802 try wip_nav.infoAddrSym(wip_nav.func_sym_index, code_off);
1803 block.high_pc = @intCast(diw.end);
1804 try diw.writeInt(u32, 0, dwarf.endian);
1805 try wip_nav.setInlineFunc(func);
1806 wip_nav.any_children = false;
1807 }
1808
1809 pub fn leaveInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64) UpdateError!void {
1810 return wip_nav.leaveInlineFuncWriterError(func, code_off) catch |err| switch (err) {
1811 error.WriteFailed => error.OutOfMemory,
1812 else => |e| e,
1813 };
1814 }
1815 fn leaveInlineFuncWriterError(
1816 wip_nav: *WipNav,
1817 func: InternPool.Index,
1818 code_off: u64,
1819 ) (UpdateError || Writer.Error)!void {
1820 const inlined_func_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.inlined_func));
1821 const block = wip_nav.blocks.pop().?;
1822 if (wip_nav.any_children)
1823 try wip_nav.debug_info.writer.writeUleb128(@backingInt(AbbrevCode.null))
1824 else
1825 std.leb.writeUnsignedFixed(
1826 inlined_func_bytes,
1827 wip_nav.debug_info.written()[block.abbrev_code..][0..inlined_func_bytes],
1828 @intCast(try wip_nav.dwarf.refAbbrevCode(.empty_inlined_func)),
1829 );
1830 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);
1831 try wip_nav.setInlineFunc(func);
1832 wip_nav.any_children = true;
1833 }
1834
1835 pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void {
1836 return wip_nav.setInlineFuncWriterError(func) catch |err| switch (err) {
1837 error.WriteFailed => error.OutOfMemory,
1838 else => |e| e,
1839 };
1840 }
1841 fn setInlineFuncWriterError(wip_nav: *WipNav, func: InternPool.Index) (UpdateError || Writer.Error)!void {
1842 const zcu = wip_nav.pt.zcu;
1843 const dwarf = wip_nav.dwarf;
1844 if (wip_nav.func == func) return;
1845
1846 const new_func_info = zcu.funcInfo(func);
1847 const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav);
1848 const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod.?);
1849
1850 const dlw = &wip_nav.debug_line.writer;
1851 if (dwarf.incremental()) {
1852 const new_nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, new_func_info.owner_nav);
1853 errdefer _ = if (!new_nav_gop.found_existing) dwarf.navs.pop();
1854 if (!new_nav_gop.found_existing) new_nav_gop.value_ptr.* = try dwarf.addCommonEntry(new_unit);
1855
1856 try dlw.writeByte(DW.LNS.extended_op);
1857 try dlw.writeUleb128(1 + dwarf.sectionOffsetBytes());
1858 try dlw.writeByte(DW.LNE.ZIG_set_decl);
1859 try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{
1860 .source_off = @intCast(dlw.end),
1861 .target_sec = .debug_info,
1862 .target_unit = new_unit,
1863 .target_entry = new_nav_gop.value_ptr.toOptional(),
1864 });
1865 try dlw.splatByteAll(0, dwarf.sectionOffsetBytes());
1866 return;
1867 }
1868
1869 const old_func_info = zcu.funcInfo(wip_nav.func);
1870 const old_file = zcu.navFileScopeIndex(old_func_info.owner_nav);
1871 if (old_file != new_file) {
1872 const mod_info = dwarf.getModInfo(wip_nav.unit);
1873 try mod_info.dirs.put(dwarf.gpa, new_unit, {});
1874 const file_gop = try mod_info.files.getOrPut(dwarf.gpa, new_file);
1875
1876 try dlw.writeByte(DW.LNS.set_file);
1877 try dlw.writeUleb128(file_gop.index);
1878 }
1879
1880 const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav);
1881 const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav);
1882 if (new_src_line != old_src_line) {
1883 try dlw.writeByte(DW.LNS.advance_line);
1884 try dlw.writeSleb128(new_src_line - old_src_line);
1885 }
1886
1887 wip_nav.func = func;
1888 }
1889
1890 fn externalReloc(wip_nav: *WipNav, sec: *Section, reloc: ExternalReloc) Allocator.Error!void {
1891 try sec.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(wip_nav.dwarf.gpa, reloc);
1892 }
1893
1894 pub fn infoExternalReloc(wip_nav: *WipNav, reloc: ExternalReloc) Allocator.Error!void {
1895 try wip_nav.externalReloc(&wip_nav.dwarf.debug_info.section, reloc);
1896 }
1897
1898 fn frameExternalReloc(wip_nav: *WipNav, reloc: ExternalReloc) Allocator.Error!void {
1899 try wip_nav.externalReloc(&wip_nav.dwarf.debug_frame.section, reloc);
1900 }
1901
1902 fn abbrevCode(wip_nav: *WipNav, abbrev_code: AbbrevCode) (UpdateError || Writer.Error)!void {
1903 try wip_nav.debug_info.writer.writeUleb128(try wip_nav.dwarf.refAbbrevCode(abbrev_code));
1904 }
1905
1906 fn sectionOffset(
1907 wip_nav: *WipNav,
1908 comptime sec: Section.Index,
1909 target_sec: Section.Index,
1910 target_unit: Unit.Index,
1911 target_entry: Entry.Index,
1912 target_off: u32,
1913 ) (UpdateError || Writer.Error)!void {
1914 const dwarf = wip_nav.dwarf;
1915 const gpa = dwarf.gpa;
1916 const entry_ptr = @field(dwarf, @tagName(sec)).section.getUnit(wip_nav.unit).getEntry(wip_nav.entry);
1917 const sw = &@field(wip_nav, @tagName(sec)).writer;
1918 const source_off: u32 = @intCast(sw.end);
1919 if (target_sec != sec) {
1920 try entry_ptr.cross_section_relocs.append(gpa, .{
1921 .source_off = source_off,
1922 .target_sec = target_sec,
1923 .target_unit = target_unit,
1924 .target_entry = target_entry.toOptional(),
1925 .target_off = target_off,
1926 });
1927 } else if (target_unit != wip_nav.unit) {
1928 try entry_ptr.cross_unit_relocs.append(gpa, .{
1929 .source_off = source_off,
1930 .target_unit = target_unit,
1931 .target_entry = target_entry.toOptional(),
1932 .target_off = target_off,
1933 });
1934 } else {
1935 try entry_ptr.cross_entry_relocs.append(gpa, .{
1936 .source_off = source_off,
1937 .target_entry = target_entry.toOptional(),
1938 .target_off = target_off,
1939 });
1940 }
1941 try sw.splatByteAll(0, dwarf.sectionOffsetBytes());
1942 }
1943
1944 fn infoSectionOffset(
1945 wip_nav: *WipNav,
1946 target_sec: Section.Index,
1947 target_unit: Unit.Index,
1948 target_entry: Entry.Index,
1949 target_off: u32,
1950 ) (UpdateError || Writer.Error)!void {
1951 try wip_nav.sectionOffset(.debug_info, target_sec, target_unit, target_entry, target_off);
1952 }
1953
1954 fn strp(wip_nav: *WipNav, str: []const u8) (UpdateError || Writer.Error)!void {
1955 try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0);
1956 }
1957
1958 fn strpFmt(wip_nav: *WipNav, comptime fmt: []const u8, args: anytype) (UpdateError || Writer.Error)!void {
1959 const str = try std.fmt.allocPrint(wip_nav.dwarf.gpa, fmt, args);
1960 defer wip_nav.dwarf.gpa.free(str);
1961 return wip_nav.strp(str);
1962 }
1963
1964 const ExprLocCounter = struct {
1965 dw: Writer.Discarding,
1966 section_offset_bytes: u32,
1967 address_size: AddressSize,
1968 fn init(dwarf: *Dwarf, buf: []u8) ExprLocCounter {
1969 return .{
1970 .dw = .init(buf),
1971 .section_offset_bytes = dwarf.sectionOffsetBytes(),
1972 .address_size = dwarf.address_size,
1973 };
1974 }
1975 fn writer(counter: *ExprLocCounter) *Writer {
1976 return &counter.dw.writer;
1977 }
1978 fn endian(_: ExprLocCounter) std.lang.Endian {
1979 return @import("builtin").cpu.arch.endian();
1980 }
1981 fn addrSym(counter: *ExprLocCounter, _: link.File.SymbolId) Writer.Error!void {
1982 try counter.dw.writer.splatByteAll(undefined, @backingInt(counter.address_size));
1983 }
1984 fn infoEntry(counter: *ExprLocCounter, _: Unit.Index, _: Entry.Index) Writer.Error!void {
1985 try counter.dw.writer.splatByteAll(undefined, counter.section_offset_bytes);
1986 }
1987 };
1988
1989 fn infoExprLoc(wip_nav: *WipNav, loc: Loc) (UpdateError || Writer.Error)!void {
1990 var buf: [64]u8 = undefined;
1991 var counter: ExprLocCounter = .init(wip_nav.dwarf, &buf);
1992 try loc.write(&counter);
1993
1994 const adapter: struct {
1995 wip_nav: *WipNav,
1996 fn writer(ctx: @This()) *Writer {
1997 return &ctx.wip_nav.debug_info.writer;
1998 }
1999 fn endian(ctx: @This()) std.lang.Endian {
2000 return ctx.wip_nav.dwarf.endian;
2001 }
2002 fn addrSym(ctx: @This(), sym_index: link.File.SymbolId) (UpdateError || Writer.Error)!void {
2003 try ctx.wip_nav.infoAddrSym(sym_index, 0);
2004 }
2005 fn infoEntry(
2006 ctx: @This(),
2007 unit: Unit.Index,
2008 entry: Entry.Index,
2009 ) (UpdateError || Writer.Error)!void {
2010 try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
2011 }
2012 } = .{ .wip_nav = wip_nav };
2013 try adapter.writer().writeUleb128(counter.dw.fullCount());
2014 try loc.write(adapter);
2015 }
2016
2017 fn infoAddrSym(
2018 wip_nav: *WipNav,
2019 sym_index: link.File.SymbolId,
2020 sym_off: u64,
2021 ) (UpdateError || Writer.Error)!void {
2022 const diw = &wip_nav.debug_info.writer;
2023 try wip_nav.infoExternalReloc(.{
2024 .source_off = @intCast(diw.end),
2025 .target_sym = sym_index,
2026 .target_off = sym_off,
2027 });
2028 try diw.splatByteAll(0, @backingInt(wip_nav.dwarf.address_size));
2029 }
2030
2031 fn frameExprLoc(wip_nav: *WipNav, loc: Loc) (UpdateError || Writer.Error)!void {
2032 var buf: [64]u8 = undefined;
2033 var counter: ExprLocCounter = .init(wip_nav.dwarf, &buf);
2034 try loc.write(&counter);
2035
2036 const adapter: struct {
2037 wip_nav: *WipNav,
2038 fn writer(ctx: @This()) *Writer {
2039 return &ctx.wip_nav.debug_frame.writer;
2040 }
2041 fn endian(ctx: @This()) std.lang.Endian {
2042 return ctx.wip_nav.dwarf.endian;
2043 }
2044 fn addrSym(ctx: @This(), sym_index: link.File.SymbolId) (UpdateError || Writer.Error)!void {
2045 try ctx.wip_nav.frameAddrSym(sym_index, 0);
2046 }
2047 fn infoEntry(
2048 ctx: @This(),
2049 unit: Unit.Index,
2050 entry: Entry.Index,
2051 ) (UpdateError || Writer.Error)!void {
2052 try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0);
2053 }
2054 } = .{ .wip_nav = wip_nav };
2055 try adapter.writer().writeUleb128(counter.dw.fullCount());
2056 try loc.write(adapter);
2057 }
2058
2059 fn frameAddrSym(
2060 wip_nav: *WipNav,
2061 sym_index: link.File.SymbolId,
2062 sym_off: u64,
2063 ) (UpdateError || Writer.Error)!void {
2064 const dfw = &wip_nav.debug_frame.writer;
2065 try wip_nav.frameExternalReloc(.{
2066 .source_off = @intCast(dfw.end),
2067 .target_sym = sym_index,
2068 .target_off = sym_off,
2069 });
2070 try dfw.splatByteAll(0, @backingInt(wip_nav.dwarf.address_size));
2071 }
2072
2073 fn refNav(
2074 wip_nav: *WipNav,
2075 nav_index: InternPool.Nav.Index,
2076 ) (UpdateError || Writer.Error)!void {
2077 const unit, const entry = try wip_nav.dwarf.getNavEntry(nav_index);
2078 try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
2079 }
2080
2081 fn refType(wip_nav: *WipNav, ty: Type) (UpdateError || Writer.Error)!void {
2082 return wip_nav.refValue(ty.toValue());
2083 }
2084
2085 fn refValue(wip_nav: *WipNav, value: Value) (UpdateError || Writer.Error)!void {
2086 const unit, const entry = try wip_nav.getValueEntry(value);
2087 try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
2088 }
2089
2090 fn getValueEntry(wip_nav: *WipNav, value: Value) UpdateError!struct { Unit.Index, Entry.Index } {
2091 if (value.typeOf(wip_nav.pt.zcu).toIntern() != .type_type) {
2092 assert(value.typeOf(wip_nav.pt.zcu).comptimeOnly(wip_nav.pt.zcu));
2093 }
2094 const dwarf = wip_nav.dwarf;
2095 const index = try dwarf.const_pool.get(wip_nav.pt, dwarf.constPoolUser(), value.toIntern());
2096 return dwarf.values.items[@backingInt(index)];
2097 }
2098
2099 fn refForward(wip_nav: *WipNav) (Allocator.Error || Writer.Error)!u32 {
2100 const dwarf = wip_nav.dwarf;
2101 const diw = &wip_nav.debug_info.writer;
2102 const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs;
2103 const reloc_index: u32 = @intCast(cross_entry_relocs.items.len);
2104 try cross_entry_relocs.append(dwarf.gpa, .{
2105 .source_off = @intCast(diw.end),
2106 .target_entry = undefined,
2107 .target_off = undefined,
2108 });
2109 try diw.splatByteAll(0, dwarf.sectionOffsetBytes());
2110 return reloc_index;
2111 }
2112
2113 fn finishForward(wip_nav: *WipNav, reloc_index: u32) void {
2114 const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs.items[reloc_index];
2115 reloc.target_entry = wip_nav.entry.toOptional();
2116 reloc.target_off = @intCast(wip_nav.debug_info.writer.end);
2117 }
2118
2119 fn blockValue(
2120 wip_nav: *WipNav,
2121 val: Value,
2122 ) (UpdateError || Writer.Error)!void {
2123 const ty = val.typeOf(wip_nav.pt.zcu);
2124 const diw = &wip_nav.debug_info.writer;
2125 const size = ty.abiSize(wip_nav.pt.zcu);
2126 try diw.writeUleb128(size);
2127 if (size == 0) return;
2128 const old_end = diw.end;
2129 try codegen.generateSymbol(
2130 wip_nav.dwarf.bin_file,
2131 wip_nav.pt,
2132 val,
2133 diw,
2134 .{ .debug_output = .{ .dwarf = wip_nav } },
2135 );
2136 if (old_end + size != diw.end) {
2137 std.debug.print("{f} [{}]: {} != {}\n", .{
2138 ty.fmt(wip_nav.pt),
2139 ty.toIntern(),
2140 size,
2141 diw.end - old_end,
2142 });
2143 unreachable;
2144 }
2145 }
2146
2147 fn bigIntConstValue(wip_nav: *WipNav, ty: Type, big_int: std.math.big.int.Const) (UpdateError || Writer.Error)!void {
2148 const zcu = wip_nav.pt.zcu;
2149 const diw = &wip_nav.debug_info.writer;
2150 const signedness = switch (ty.toIntern()) {
2151 .comptime_int_type => .signed,
2152 else => ty.intInfo(zcu).signedness,
2153 };
2154 const bits = @max(1, big_int.bitCountTwosCompForSignedness(signedness));
2155 if (bits <= 64) {
2156 try diw.writeUleb128(@as(u13, switch (signedness) {
2157 .signed => DW.FORM.sdata,
2158 .unsigned => DW.FORM.udata,
2159 }));
2160 try wip_nav.debug_info.ensureUnusedCapacity(@divCeil(bits, 7));
2161 var bit: usize = 0;
2162 var carry: u1 = 1;
2163 while (bit < bits) {
2164 const limb_bits = @typeInfo(std.math.big.Limb).int.bits;
2165 const limb_index = bit / limb_bits;
2166 const limb_shift: std.math.Log2Int(std.math.big.Limb) = @intCast(bit % limb_bits);
2167 const low_abs_part: u7 = @truncate(big_int.limbs[limb_index] >> limb_shift);
2168 const abs_part = if (limb_shift > limb_bits - 7 and limb_index + 1 < big_int.limbs.len) abs_part: {
2169 const high_abs_part: u7 = @truncate(big_int.limbs[limb_index + 1] << -%limb_shift);
2170 break :abs_part high_abs_part | low_abs_part;
2171 } else low_abs_part;
2172 const twos_comp_part = if (big_int.positive) abs_part else twos_comp_part: {
2173 const twos_comp_part, carry = @addWithOverflow(~abs_part, carry);
2174 break :twos_comp_part twos_comp_part;
2175 };
2176 bit += 7;
2177 diw.writeByte(@as(u8, if (bit < bits) 0x80 else 0x00) | twos_comp_part) catch unreachable;
2178 }
2179 } else {
2180 try diw.writeUleb128(DW.FORM.block);
2181 const bytes = @max(ty.abiSize(zcu), @divCeil(bits, 8));
2182 try diw.writeUleb128(bytes);
2183 try wip_nav.debug_info.ensureUnusedCapacity(@intCast(bytes));
2184 big_int.writeTwosComplement(
2185 try diw.writableSlice(@intCast(bytes)),
2186 wip_nav.dwarf.endian,
2187 );
2188 }
2189 }
2190
2191 fn enumConstValue(wip_nav: *WipNav, loaded_enum: InternPool.LoadedEnumType, field_index: usize) (UpdateError || Writer.Error)!void {
2192 const zcu = wip_nav.pt.zcu;
2193 const ip = &zcu.intern_pool;
2194 var big_int_space: Value.BigIntSpace = undefined;
2195 try wip_nav.bigIntConstValue(.fromInterned(loaded_enum.int_tag_type), if (loaded_enum.field_values.len > 0)
2196 Value.fromInterned(loaded_enum.field_values.get(ip)[field_index]).toBigInt(&big_int_space, zcu)
2197 else
2198 std.math.big.int.Mutable.init(&big_int_space.limbs, field_index).toConst());
2199 }
2200
2201 fn declCommon(
2202 wip_nav: *WipNav,
2203 abbrev_code: struct {
2204 decl: AbbrevCode,
2205 decl_specification: AbbrevCode,
2206 decl_instance: AbbrevCode,
2207 },
2208 nav: *const InternPool.Nav,
2209 file: Zcu.File.Index,
2210 decl: *const std.zig.Zir.Inst.Declaration.Unwrapped,
2211 ) (UpdateError || Writer.Error)!void {
2212 const zcu = wip_nav.pt.zcu;
2213 const ip = &zcu.intern_pool;
2214 const dwarf = wip_nav.dwarf;
2215 const diw = &wip_nav.debug_info.writer;
2216
2217 const orig_entry = wip_nav.entry;
2218 defer wip_nav.entry = orig_entry;
2219 const parent_type, const is_specification = if (nav.analysis) |analysis| parent_info: {
2220 const parent_type: Type = .fromInterned(zcu.namespacePtr(analysis.namespace).owner_type);
2221 const decl_gop = try dwarf.decls.getOrPut(dwarf.gpa, analysis.zir_index);
2222 errdefer _ = if (!decl_gop.found_existing) dwarf.decls.pop();
2223 const was_specification = decl_gop.found_existing and
2224 switch (try dwarf.debug_info.declAbbrevCode(wip_nav.unit, decl_gop.value_ptr.*)) {
2225 .null,
2226 .decl_alias,
2227 .decl_empty_enum,
2228 .decl_enum,
2229 .decl_namespace_struct,
2230 .decl_struct,
2231 .decl_packed_struct,
2232 .decl_union,
2233 .decl_var,
2234 .decl_const,
2235 .decl_const_runtime_bits,
2236 .decl_const_comptime_state,
2237 .decl_const_runtime_bits_comptime_state,
2238 .decl_nullary_func,
2239 .decl_func,
2240 .decl_nullary_func_generic,
2241 .decl_func_generic,
2242 .decl_extern_nullary_func,
2243 .decl_extern_func,
2244 => false,
2245 .decl_specification_var,
2246 .decl_specification_const,
2247 .decl_specification_func,
2248 => true,
2249
2250 // This comes from a decl which was previously generated as an incomplete value
2251 // (I think that must mean either a function or an extern which previously had
2252 // incomplete types).
2253 .undefined_comptime_value => false,
2254
2255 else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}),
2256 };
2257 if (parent_type.getCaptures(zcu).len == 0) {
2258 if (was_specification) try dwarf.freeCommonEntry(wip_nav.unit, decl_gop.value_ptr.*);
2259 decl_gop.value_ptr.* = orig_entry;
2260 break :parent_info .{ parent_type, false };
2261 } else {
2262 if (was_specification)
2263 dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(decl_gop.value_ptr.*).clear()
2264 else
2265 decl_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
2266 wip_nav.entry = decl_gop.value_ptr.*;
2267 break :parent_info .{ parent_type, true };
2268 }
2269 } else .{ null, false };
2270
2271 try wip_nav.abbrevCode(if (is_specification) abbrev_code.decl_specification else abbrev_code.decl);
2272 try wip_nav.refType((if (is_specification) null else parent_type) orelse
2273 .fromInterned(zcu.fileRootType(file)));
2274 assert(diw.end == DebugInfo.declEntryLineOff(dwarf));
2275 try diw.writeInt(u32, decl.src_line + 1, dwarf.endian);
2276 try diw.writeUleb128(decl.src_column + 1);
2277 try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private);
2278 try wip_nav.strp(nav.name.toSlice(ip));
2279
2280 if (!is_specification) return;
2281 const specification_entry = wip_nav.entry;
2282 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, specification_entry, dwarf, wip_nav.debug_info.written());
2283 wip_nav.debug_info.clearRetainingCapacity();
2284 wip_nav.entry = orig_entry;
2285 try wip_nav.abbrevCode(abbrev_code.decl_instance);
2286 try wip_nav.refType(parent_type.?);
2287 try wip_nav.infoSectionOffset(.debug_info, wip_nav.unit, specification_entry, 0);
2288 }
2289};
2290
2291/// When allocating, the ideal_capacity is calculated by
2292/// actual_capacity + (actual_capacity / ideal_factor)
2293const ideal_factor = 3;
2294
2295fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
2296 return actual_size +| (actual_size / ideal_factor);
2297}
2298
2299pub fn init(lf: *link.File, format: DW.Format) Dwarf {
2300 const comp = lf.comp;
2301 const target = &comp.root_mod.resolved_target.result;
2302 return .{
2303 .gpa = comp.gpa,
2304 .bin_file = lf,
2305 .format = format,
2306 .address_size = switch (target.ptrBitWidth()) {
2307 0...32 => .@"32",
2308 33...64 => .@"64",
2309 else => unreachable,
2310 },
2311 .endian = target.cpu.arch.endian(),
2312
2313 .const_pool = .empty,
2314
2315 .mods = .empty,
2316 .values = .empty,
2317 .navs = .empty,
2318 .decls = .empty,
2319
2320 .debug_abbrev = .{ .section = Section.init },
2321 .debug_aranges = .{ .section = Section.init },
2322 .debug_frame = .{
2323 .header = if (target.cpu.arch == .x86_64 and target.ofmt == .elf) header: {
2324 const Register = @import("../codegen/x86_64/bits.zig").Register;
2325 break :header comptime .{
2326 .format = .eh_frame,
2327 .code_alignment_factor = 1,
2328 .data_alignment_factor = -8,
2329 .return_address_register = Register.rip.dwarfNum(),
2330 .initial_instructions = &.{
2331 .{ .def_cfa = .{ .reg = Register.rsp.dwarfNum(), .off = 8 } },
2332 .{ .offset = .{ .reg = Register.rip.dwarfNum(), .off = -8 } },
2333 },
2334 };
2335 } else .{
2336 .format = .none,
2337 .code_alignment_factor = undefined,
2338 .data_alignment_factor = undefined,
2339 .return_address_register = undefined,
2340 .initial_instructions = &.{},
2341 },
2342 .section = Section.init,
2343 },
2344 .debug_info = .{ .section = Section.init },
2345 .debug_line = .{
2346 .header = switch (target.cpu.arch) {
2347 .x86_64, .aarch64 => .{
2348 .minimum_instruction_length = 1,
2349 .maximum_operations_per_instruction = 1,
2350 .default_is_stmt = true,
2351 .line_base = -5,
2352 .line_range = 14,
2353 .opcode_base = DW.LNS.set_isa + 1,
2354 },
2355 else => .{
2356 .minimum_instruction_length = 1,
2357 .maximum_operations_per_instruction = 1,
2358 .default_is_stmt = true,
2359 .line_base = 0,
2360 .line_range = 1,
2361 .opcode_base = DW.LNS.set_isa + 1,
2362 },
2363 },
2364 .section = Section.init,
2365 },
2366 .debug_line_str = StringSection.init,
2367 .debug_loclists = .{ .section = Section.init },
2368 .debug_rnglists = .{ .section = Section.init },
2369 .debug_str = StringSection.init,
2370 };
2371}
2372
2373pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
2374 if (dwarf.bin_file.cast(.macho)) |macho_file| {
2375 if (macho_file.d_sym) |*d_sym| {
2376 for ([_]*Section{
2377 &dwarf.debug_abbrev.section,
2378 &dwarf.debug_aranges.section,
2379 &dwarf.debug_info.section,
2380 &dwarf.debug_line.section,
2381 &dwarf.debug_line_str.section,
2382 &dwarf.debug_loclists.section,
2383 &dwarf.debug_rnglists.section,
2384 &dwarf.debug_str.section,
2385 }, [_]u8{
2386 d_sym.debug_abbrev_section_index.?,
2387 d_sym.debug_aranges_section_index.?,
2388 d_sym.debug_info_section_index.?,
2389 d_sym.debug_line_section_index.?,
2390 d_sym.debug_line_str_section_index.?,
2391 d_sym.debug_loclists_section_index.?,
2392 d_sym.debug_rnglists_section_index.?,
2393 d_sym.debug_str_section_index.?,
2394 }) |sec, sect_index| {
2395 const header = &d_sym.sections.items[sect_index];
2396 sec.index = sect_index;
2397 sec.len = header.size;
2398 }
2399 } else {
2400 for ([_]*Section{
2401 &dwarf.debug_abbrev.section,
2402 &dwarf.debug_aranges.section,
2403 &dwarf.debug_info.section,
2404 &dwarf.debug_line.section,
2405 &dwarf.debug_line_str.section,
2406 &dwarf.debug_loclists.section,
2407 &dwarf.debug_rnglists.section,
2408 &dwarf.debug_str.section,
2409 }, [_]u8{
2410 macho_file.debug_abbrev_sect_index.?,
2411 macho_file.debug_aranges_sect_index.?,
2412 macho_file.debug_info_sect_index.?,
2413 macho_file.debug_line_sect_index.?,
2414 macho_file.debug_line_str_sect_index.?,
2415 macho_file.debug_loclists_sect_index.?,
2416 macho_file.debug_rnglists_sect_index.?,
2417 macho_file.debug_str_sect_index.?,
2418 }) |sec, sect_index| {
2419 const header = &macho_file.sections.items(.header)[sect_index];
2420 sec.index = sect_index;
2421 sec.len = header.size;
2422 }
2423 }
2424 }
2425}
2426
2427pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
2428 if (dwarf.bin_file.cast(.elf)) |elf_file| {
2429 const zo = elf_file.zigObjectPtr().?;
2430 for ([_]*Section{
2431 &dwarf.debug_abbrev.section,
2432 &dwarf.debug_aranges.section,
2433 &dwarf.debug_frame.section,
2434 &dwarf.debug_info.section,
2435 &dwarf.debug_line.section,
2436 &dwarf.debug_line_str.section,
2437 &dwarf.debug_loclists.section,
2438 &dwarf.debug_rnglists.section,
2439 &dwarf.debug_str.section,
2440 }, [_]u32{
2441 zo.debug_abbrev_index.?,
2442 zo.debug_aranges_index.?,
2443 zo.eh_frame_index.?,
2444 zo.debug_info_index.?,
2445 zo.debug_line_index.?,
2446 zo.debug_line_str_index.?,
2447 zo.debug_loclists_index.?,
2448 zo.debug_rnglists_index.?,
2449 zo.debug_str_index.?,
2450 }) |sec, sym_index| {
2451 sec.index = sym_index;
2452 }
2453 }
2454 dwarf.reloadSectionMetadata();
2455
2456 dwarf.debug_abbrev.section.pad_entries_to_ideal = false;
2457 assert(try dwarf.debug_abbrev.section.addUnit(DebugAbbrev.header_bytes, DebugAbbrev.trailer_bytes, dwarf) == DebugAbbrev.unit);
2458 errdefer dwarf.debug_abbrev.section.popUnit(dwarf.gpa);
2459 for (std.enums.values(AbbrevCode)) |abbrev_code|
2460 assert(@backingInt(try dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).addEntry(dwarf.gpa)) == @backingInt(abbrev_code));
2461
2462 dwarf.debug_aranges.section.pad_entries_to_ideal = false;
2463 dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@backingInt(dwarf.address_size) * 2);
2464
2465 dwarf.debug_frame.section.alignment = switch (dwarf.debug_frame.header.format) {
2466 .none => .@"1",
2467 .debug_frame => InternPool.Alignment.fromNonzeroByteUnits(@backingInt(dwarf.address_size)),
2468 .eh_frame => .@"4",
2469 };
2470
2471 dwarf.debug_line_str.section.pad_entries_to_ideal = false;
2472 assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
2473 errdefer dwarf.debug_line_str.section.popUnit(dwarf.gpa);
2474
2475 dwarf.debug_str.section.pad_entries_to_ideal = false;
2476 assert(try dwarf.debug_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
2477 errdefer dwarf.debug_str.section.popUnit(dwarf.gpa);
2478
2479 dwarf.debug_loclists.section.pad_entries_to_ideal = false;
2480
2481 dwarf.debug_rnglists.section.pad_entries_to_ideal = false;
2482}
2483
2484pub fn deinit(dwarf: *Dwarf) void {
2485 const gpa = dwarf.gpa;
2486 dwarf.const_pool.deinit(gpa);
2487 for (dwarf.mods.values()) |*mod_info| mod_info.deinit(gpa);
2488 dwarf.mods.deinit(gpa);
2489 dwarf.values.deinit(gpa);
2490 dwarf.navs.deinit(gpa);
2491 dwarf.decls.deinit(gpa);
2492 dwarf.debug_abbrev.section.deinit(gpa);
2493 dwarf.debug_aranges.section.deinit(gpa);
2494 dwarf.debug_frame.section.deinit(gpa);
2495 dwarf.debug_info.section.deinit(gpa);
2496 dwarf.debug_line.section.deinit(gpa);
2497 dwarf.debug_line_str.deinit(gpa);
2498 dwarf.debug_loclists.section.deinit(gpa);
2499 dwarf.debug_rnglists.section.deinit(gpa);
2500 dwarf.debug_str.deinit(gpa);
2501 dwarf.* = undefined;
2502}
2503
2504fn getNavEntry(
2505 dwarf: *Dwarf,
2506 nav_index: InternPool.Nav.Index,
2507) UpdateError!struct { Unit.Index, Entry.Index } {
2508 const zcu = dwarf.bin_file.comp.zcu.?;
2509 const ip = &zcu.intern_pool;
2510 const nav = ip.getNav(nav_index);
2511 const unit = try dwarf.getUnit(zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?);
2512 const gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
2513 if (gop.found_existing) return .{ unit, gop.value_ptr.* };
2514 const entry = try dwarf.addCommonEntry(unit);
2515 gop.value_ptr.* = entry;
2516 return .{ unit, entry };
2517}
2518
2519fn getUnit(dwarf: *Dwarf, mod: *Module) !Unit.Index {
2520 const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod);
2521 const unit: Unit.Index = @fromBackingInt(@intCast(mod_gop.index));
2522 if (!mod_gop.found_existing) {
2523 errdefer _ = dwarf.mods.pop();
2524 mod_gop.value_ptr.* = .{
2525 .root_dir_path = undefined,
2526 .dirs = .empty,
2527 .files = .empty,
2528 };
2529 errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa);
2530 try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {});
2531 assert(try dwarf.debug_aranges.section.addUnit(
2532 DebugAranges.headerBytes(dwarf),
2533 DebugAranges.trailerBytes(dwarf),
2534 dwarf,
2535 ) == unit);
2536 errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa);
2537 assert(try dwarf.debug_frame.section.addUnit(
2538 DebugFrame.headerBytes(dwarf),
2539 DebugFrame.trailerBytes(dwarf),
2540 dwarf,
2541 ) == unit);
2542 errdefer dwarf.debug_frame.section.popUnit(dwarf.gpa);
2543 assert(try dwarf.debug_info.section.addUnit(
2544 DebugInfo.headerBytes(dwarf),
2545 DebugInfo.trailer_bytes,
2546 dwarf,
2547 ) == unit);
2548 errdefer dwarf.debug_info.section.popUnit(dwarf.gpa);
2549 assert(try dwarf.debug_line.section.addUnit(
2550 DebugLine.headerBytes(dwarf, 5, 25),
2551 DebugLine.trailer_bytes,
2552 dwarf,
2553 ) == unit);
2554 errdefer dwarf.debug_line.section.popUnit(dwarf.gpa);
2555 assert(try dwarf.debug_loclists.section.addUnit(
2556 DebugLocLists.headerBytes(dwarf),
2557 DebugLocLists.trailer_bytes,
2558 dwarf,
2559 ) == unit);
2560 errdefer dwarf.debug_loclists.section.popUnit(dwarf.gpa);
2561 assert(try dwarf.debug_rnglists.section.addUnit(
2562 DebugRngLists.headerBytes(dwarf),
2563 DebugRngLists.trailer_bytes,
2564 dwarf,
2565 ) == unit);
2566 errdefer dwarf.debug_rnglists.section.popUnit(dwarf.gpa);
2567 }
2568 return unit;
2569}
2570
2571fn getUnitIfExists(dwarf: *const Dwarf, mod: *Module) ?Unit.Index {
2572 return @fromBackingInt(@intCast(dwarf.mods.getIndex(mod) orelse return null));
2573}
2574
2575fn getModInfo(dwarf: *Dwarf, unit: Unit.Index) *ModInfo {
2576 return &dwarf.mods.values()[@backingInt(unit)];
2577}
2578
2579fn getUnitModule(dwarf: *Dwarf, unit: Unit.Index) *Module {
2580 return dwarf.mods.keys()[@backingInt(unit)];
2581}
2582
2583pub fn initWipNav(
2584 dwarf: *Dwarf,
2585 pt: Zcu.PerThread,
2586 nav_index: InternPool.Nav.Index,
2587 sym_index: link.File.SymbolId,
2588) link.Error!WipNav {
2589 return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) {
2590 error.OutOfMemory => error.OutOfMemory,
2591 else => |e| pt.zcu.codegenFail(nav_index, "failed to init dwarf: {s}", .{@errorName(e)}),
2592 };
2593}
2594
2595fn initWipNavInner(
2596 dwarf: *Dwarf,
2597 pt: Zcu.PerThread,
2598 nav_index: InternPool.Nav.Index,
2599 sym_index: link.File.SymbolId,
2600) !WipNav {
2601 const zcu = pt.zcu;
2602 const ip = &zcu.intern_pool;
2603
2604 const nav = ip.getNav(nav_index);
2605 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
2606 const file = zcu.fileByIndex(inst_info.file);
2607 const decl = file.zir.?.getDeclaration(inst_info.inst);
2608 log.debug("initWipNav({s}:{d}:{d} %{d} = {f})", .{
2609 file.sub_file_path,
2610 decl.src_line + 1,
2611 decl.src_column + 1,
2612 @backingInt(inst_info.inst),
2613 nav.fqn.fmt(ip),
2614 });
2615
2616 const mod = file.mod.?;
2617 const unit = try dwarf.getUnit(mod);
2618 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
2619 errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
2620 if (nav_gop.found_existing) {
2621 for ([_]*Section{
2622 &dwarf.debug_aranges.section,
2623 &dwarf.debug_info.section,
2624 &dwarf.debug_line.section,
2625 &dwarf.debug_loclists.section,
2626 &dwarf.debug_rnglists.section,
2627 }) |sec| sec.getUnit(unit).getEntry(nav_gop.value_ptr.*).clear();
2628 } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
2629 var wip_nav: WipNav = .{
2630 .dwarf = dwarf,
2631 .pt = pt,
2632 .unit = unit,
2633 .entry = nav_gop.value_ptr.*,
2634 .any_children = false,
2635 .func = .none,
2636 .func_sym_index = undefined,
2637 .func_high_pc = undefined,
2638 .blocks = undefined,
2639 .cfi = undefined,
2640 .debug_frame = .init(dwarf.gpa),
2641 .debug_info = .init(dwarf.gpa),
2642 .debug_line = .init(dwarf.gpa),
2643 .debug_loclists = .init(dwarf.gpa),
2644 };
2645 errdefer wip_nav.deinit();
2646
2647 const nav_val = zcu.navValue(nav_index);
2648 nav_val: switch (ip.indexToKey(nav_val.toIntern())) {
2649 .@"extern" => |@"extern"| switch (@"extern".source) {
2650 .builtin => {
2651 const maybe_func_type = switch (ip.indexToKey(@"extern".ty)) {
2652 .func_type => |func_type| func_type,
2653 else => null,
2654 };
2655 const diw = &wip_nav.debug_info.writer;
2656 try wip_nav.abbrevCode(if (maybe_func_type) |func_type|
2657 if (func_type.param_types.len > 0 or func_type.is_var_args) .builtin_extern_func else .builtin_extern_nullary_func
2658 else
2659 .builtin_extern_var);
2660 try wip_nav.refType(.fromInterned(zcu.fileRootType(inst_info.file)));
2661 try wip_nav.strp(@"extern".name.toSlice(ip));
2662 try wip_nav.refType(.fromInterned(if (maybe_func_type) |func_type| func_type.return_type else @"extern".ty));
2663 if (maybe_func_type) |func_type| {
2664 try wip_nav.infoAddrSym(sym_index, 0);
2665 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
2666 if (func_type.param_types.len > 0 or func_type.is_var_args) {
2667 for (func_type.param_types.get(ip)) |param_type| {
2668 try wip_nav.abbrevCode(.extern_param);
2669 try wip_nav.refType(.fromInterned(param_type));
2670 }
2671 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
2672 try diw.writeUleb128(@backingInt(AbbrevCode.null));
2673 }
2674 } else try wip_nav.infoExprLoc(.{ .addr_reloc = sym_index });
2675 },
2676 .syntax => switch (ip.isFunctionType(@"extern".ty)) {
2677 false => continue :nav_val .{ .undef = @"extern".ty },
2678 true => {
2679 const func_type = ip.indexToKey(@"extern".ty).func_type;
2680 const diw = &wip_nav.debug_info.writer;
2681 try wip_nav.declCommon(if (func_type.param_types.len > 0 or func_type.is_var_args) .{
2682 .decl = .decl_extern_func,
2683 .decl_specification = .decl_specification_func,
2684 .decl_instance = .decl_instance_extern_func,
2685 } else .{
2686 .decl = .decl_extern_nullary_func,
2687 .decl_specification = .decl_specification_func,
2688 .decl_instance = .decl_instance_extern_nullary_func,
2689 }, &nav, inst_info.file, &decl);
2690 try wip_nav.strp(@"extern".name.toSlice(ip));
2691 try wip_nav.refType(.fromInterned(func_type.return_type));
2692 try wip_nav.infoAddrSym(sym_index, 0);
2693 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
2694 if (func_type.param_types.len > 0 or func_type.is_var_args) {
2695 for (func_type.param_types.get(ip)) |param_type| {
2696 try wip_nav.abbrevCode(.extern_param);
2697 try wip_nav.refType(.fromInterned(param_type));
2698 }
2699 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
2700 try diw.writeUleb128(@backingInt(AbbrevCode.null));
2701 }
2702 },
2703 },
2704 },
2705 .func => |func| if (func.owner_nav != nav_index) {
2706 try wip_nav.declCommon(.{
2707 .decl = .decl_alias,
2708 .decl_specification = .decl_specification_const,
2709 .decl_instance = .decl_instance_alias,
2710 }, &nav, inst_info.file, &decl);
2711 try wip_nav.refNav(func.owner_nav);
2712 } else {
2713 const func_type = ip.indexToKey(func.ty).func_type;
2714 wip_nav.func = nav_val.toIntern();
2715 wip_nav.func_sym_index = sym_index;
2716 wip_nav.blocks = .empty;
2717 if (dwarf.debug_frame.header.format != .none) wip_nav.cfi = .{
2718 .loc = 0,
2719 .cfa = dwarf.debug_frame.header.initial_instructions[0].def_cfa,
2720 };
2721
2722 switch (dwarf.debug_frame.header.format) {
2723 .none => {},
2724 .debug_frame, .eh_frame => |format| {
2725 const entry = dwarf.debug_frame.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry);
2726 const dfw = &wip_nav.debug_frame.writer;
2727 switch (dwarf.format) {
2728 .@"32" => try dfw.writeInt(u32, undefined, dwarf.endian),
2729 .@"64" => {
2730 try dfw.writeInt(u32, std.math.maxInt(u32), dwarf.endian);
2731 try dfw.writeInt(u64, undefined, dwarf.endian);
2732 },
2733 }
2734 switch (format) {
2735 .none => unreachable,
2736 .debug_frame => {
2737 try entry.cross_entry_relocs.append(dwarf.gpa, .{
2738 .source_off = @intCast(dfw.end),
2739 });
2740 try dfw.splatByteAll(0, dwarf.sectionOffsetBytes());
2741 try wip_nav.frameAddrSym(sym_index, 0);
2742 try dfw.splatByteAll(undefined, @backingInt(dwarf.address_size));
2743 },
2744 .eh_frame => {
2745 try dfw.writeInt(u32, undefined, dwarf.endian);
2746 try wip_nav.frameExternalReloc(.{
2747 .source_off = @intCast(dfw.end),
2748 .target_sym = sym_index,
2749 });
2750 try dfw.writeInt(u32, 0, dwarf.endian);
2751 try dfw.writeInt(u32, undefined, dwarf.endian);
2752 try dfw.writeUleb128(0);
2753 },
2754 }
2755 },
2756 }
2757
2758 const diw = &wip_nav.debug_info.writer;
2759 try wip_nav.declCommon(.{
2760 .decl = .decl_func,
2761 .decl_specification = .decl_specification_func,
2762 .decl_instance = .decl_instance_func,
2763 }, &nav, inst_info.file, &decl);
2764 try wip_nav.strp(switch (decl.linkage) {
2765 .normal => nav.fqn,
2766 .@"extern", .@"export" => nav.name,
2767 }.toSlice(ip));
2768 try wip_nav.refType(.fromInterned(func_type.return_type));
2769 try wip_nav.infoAddrSym(sym_index, 0);
2770 wip_nav.func_high_pc = @intCast(diw.end);
2771 try diw.writeInt(u32, 0, dwarf.endian);
2772 const target = &mod.resolved_target.result;
2773 try diw.writeUleb128(switch (nav.resolved.?.@"align") {
2774 .none => target_info.defaultFunctionAlignment(target),
2775 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
2776 }.toByteUnits().?);
2777 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2778 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
2779
2780 const dlw = &wip_nav.debug_line.writer;
2781 try dlw.writeByte(DW.LNS.extended_op);
2782 if (dwarf.incremental()) {
2783 try dlw.writeUleb128(1 + dwarf.sectionOffsetBytes());
2784 try dlw.writeByte(DW.LNE.ZIG_set_decl);
2785 try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{
2786 .source_off = @intCast(dlw.end),
2787 .target_sec = .debug_info,
2788 .target_unit = wip_nav.unit,
2789 .target_entry = wip_nav.entry.toOptional(),
2790 });
2791 try dlw.splatByteAll(0, dwarf.sectionOffsetBytes());
2792
2793 try dlw.writeByte(DW.LNS.set_column);
2794 try dlw.writeUleb128(func.lbrace_column + 1);
2795
2796 try wip_nav.advanceLineAndPc(func.lbrace_line, 0, false);
2797 } else {
2798 try dlw.writeUleb128(1 + @backingInt(dwarf.address_size));
2799 try dlw.writeByte(DW.LNE.set_address);
2800 try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
2801 .source_off = @intCast(dlw.end),
2802 .target_sym = sym_index,
2803 });
2804 try dlw.splatByteAll(0, @backingInt(dwarf.address_size));
2805
2806 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
2807 try dlw.writeByte(DW.LNS.set_file);
2808 try dlw.writeUleb128(file_gop.index);
2809
2810 try dlw.writeByte(DW.LNS.set_column);
2811 try dlw.writeUleb128(func.lbrace_column + 1);
2812
2813 try wip_nav.advanceLineAndPc(decl.src_line + func.lbrace_line, 0, false);
2814 }
2815 },
2816 else => {
2817 const diw = &wip_nav.debug_info.writer;
2818 try wip_nav.declCommon(.{
2819 .decl = .decl_var,
2820 .decl_specification = switch (decl.kind) {
2821 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
2822 .@"const" => .decl_specification_const,
2823 .@"var" => .decl_specification_var,
2824 },
2825 .decl_instance = .decl_instance_var,
2826 }, &nav, inst_info.file, &decl);
2827 try wip_nav.strp(switch (decl.linkage) {
2828 .normal => nav.fqn,
2829 .@"extern", .@"export" => nav.name,
2830 }.toSlice(ip));
2831 const ty: Type = nav_val.typeOf(zcu);
2832 const addr: Loc = .{ .addr_reloc = sym_index };
2833 const loc: Loc = if (decl.is_threadlocal) loc: {
2834 const target = zcu.comp.root_mod.resolved_target.result;
2835 break :loc switch (target.cpu.arch) {
2836 .x86_64 => .{ .form_tls_address = &addr },
2837 else => .empty,
2838 };
2839 } else addr;
2840 switch (decl.kind) {
2841 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
2842 .@"const" => {
2843 const const_ty_reloc_index = try wip_nav.refForward();
2844 try wip_nav.infoExprLoc(loc);
2845 try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse
2846 ty.abiAlignment(zcu).toByteUnits().?);
2847 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2848 wip_nav.finishForward(const_ty_reloc_index);
2849 try wip_nav.abbrevCode(.is_const);
2850 try wip_nav.refType(ty);
2851 },
2852 .@"var" => {
2853 try wip_nav.refType(ty);
2854 try wip_nav.infoExprLoc(loc);
2855 try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse
2856 ty.abiAlignment(zcu).toByteUnits().?);
2857 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2858 },
2859 }
2860 },
2861 }
2862 return wip_nav;
2863}
2864
2865pub fn finishWipNavFunc(
2866 dwarf: *Dwarf,
2867 pt: Zcu.PerThread,
2868 nav_index: InternPool.Nav.Index,
2869 code_size: u64,
2870 wip_nav: *WipNav,
2871) UpdateError!void {
2872 return dwarf.finishWipNavFuncWriterError(pt, nav_index, code_size, wip_nav) catch |err| switch (err) {
2873 error.WriteFailed => error.OutOfMemory,
2874 else => |e| e,
2875 };
2876}
2877fn finishWipNavFuncWriterError(
2878 dwarf: *Dwarf,
2879 pt: Zcu.PerThread,
2880 nav_index: InternPool.Nav.Index,
2881 code_size: u64,
2882 wip_nav: *WipNav,
2883) (UpdateError || Writer.Error)!void {
2884 const zcu = pt.zcu;
2885 const ip = &zcu.intern_pool;
2886 const nav = ip.getNav(nav_index);
2887 assert(wip_nav.func != .none);
2888 log.debug("finishWipNavFunc({f})", .{nav.fqn.fmt(ip)});
2889
2890 {
2891 const external_relocs = &dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
2892 try external_relocs.append(dwarf.gpa, .{ .target_sym = wip_nav.func_sym_index });
2893 var entry: [8 + 8]u8 = undefined;
2894 @memset(entry[0..@backingInt(dwarf.address_size)], 0);
2895 dwarf.writeInt(entry[@backingInt(dwarf.address_size)..][0..@backingInt(dwarf.address_size)], code_size);
2896 try dwarf.debug_aranges.section.replaceEntry(
2897 wip_nav.unit,
2898 wip_nav.entry,
2899 dwarf,
2900 entry[0 .. @backingInt(dwarf.address_size) * 2],
2901 );
2902 }
2903 switch (dwarf.debug_frame.header.format) {
2904 .none => {},
2905 .debug_frame, .eh_frame => |format| {
2906 const dfw = &wip_nav.debug_frame.writer;
2907 try dfw.splatByteAll(
2908 DW.CFA.nop,
2909 @intCast(dwarf.debug_frame.section.alignment.forward(dfw.end) - dfw.end),
2910 );
2911 const contents = wip_nav.debug_frame.written();
2912 try dwarf.debug_frame.section.resizeEntry(wip_nav.unit, wip_nav.entry, dwarf, @intCast(contents.len));
2913 const unit = dwarf.debug_frame.section.getUnit(wip_nav.unit);
2914 const entry = unit.getEntry(wip_nav.entry);
2915 const unit_len = (if (entry.next.unwrap()) |next_entry|
2916 unit.getEntry(next_entry).off - entry.off
2917 else
2918 entry.len) - dwarf.unitLengthBytes();
2919 dwarf.writeInt(contents[dwarf.unitLengthBytes() - dwarf.sectionOffsetBytes() ..][0..dwarf.sectionOffsetBytes()], unit_len);
2920 switch (format) {
2921 .none => unreachable,
2922 .debug_frame => dwarf.writeInt(contents[dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() +
2923 @backingInt(dwarf.address_size) ..][0..@backingInt(dwarf.address_size)], code_size),
2924 .eh_frame => {
2925 std.mem.writeInt(
2926 u32,
2927 contents[dwarf.unitLengthBytes()..][0..4],
2928 unit.header_len + entry.off + dwarf.unitLengthBytes(),
2929 dwarf.endian,
2930 );
2931 std.mem.writeInt(u32, contents[dwarf.unitLengthBytes() + 4 + 4 ..][0..4], @intCast(code_size), dwarf.endian);
2932 },
2933 }
2934 try entry.replace(unit, &dwarf.debug_frame.section, dwarf, contents);
2935 },
2936 }
2937 {
2938 std.mem.writeInt(u32, wip_nav.debug_info.written()[wip_nav.func_high_pc..][0..4], @intCast(code_size), dwarf.endian);
2939 if (wip_nav.any_children) {
2940 const diw = &wip_nav.debug_info.writer;
2941 try diw.writeUleb128(@backingInt(AbbrevCode.null));
2942 } else {
2943 const abbrev_code_buf = wip_nav.debug_info.written()[0..AbbrevCode.decl_bytes];
2944 var abbrev_code_fr: std.Io.Reader = .fixed(abbrev_code_buf);
2945 const abbrev_code: AbbrevCode = @fromBackingInt(@intCast(
2946 abbrev_code_fr.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable,
2947 ));
2948 std.leb.writeUnsignedFixed(
2949 AbbrevCode.decl_bytes,
2950 abbrev_code_buf,
2951 @intCast(try dwarf.refAbbrevCode(switch (abbrev_code) {
2952 else => unreachable,
2953 .decl_func => .decl_nullary_func,
2954 .decl_instance_func => .decl_instance_nullary_func,
2955 })),
2956 );
2957 }
2958 }
2959 {
2960 try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.appendSlice(dwarf.gpa, &.{
2961 .{
2962 .source_off = 1,
2963 .target_sym = wip_nav.func_sym_index,
2964 },
2965 .{
2966 .source_off = 1 + @backingInt(dwarf.address_size),
2967 .target_sym = wip_nav.func_sym_index,
2968 .target_off = code_size,
2969 },
2970 });
2971 try dwarf.debug_rnglists.section.replaceEntry(
2972 wip_nav.unit,
2973 wip_nav.entry,
2974 dwarf,
2975 ([1]u8{DW.RLE.start_end} ++ @as([8 + 8]u8, @splat(0)))[0 .. 1 + @backingInt(dwarf.address_size) + @backingInt(dwarf.address_size)],
2976 );
2977 }
2978
2979 try dwarf.finishWipNav(pt, nav_index, wip_nav);
2980}
2981
2982pub fn finishWipNav(
2983 dwarf: *Dwarf,
2984 pt: Zcu.PerThread,
2985 nav_index: InternPool.Nav.Index,
2986 wip_nav: *WipNav,
2987) UpdateError!void {
2988 return dwarf.finishWipNavWriterError(pt, nav_index, wip_nav) catch |err| switch (err) {
2989 error.WriteFailed => error.OutOfMemory,
2990 else => |e| e,
2991 };
2992}
2993fn finishWipNavWriterError(
2994 dwarf: *Dwarf,
2995 pt: Zcu.PerThread,
2996 nav_index: InternPool.Nav.Index,
2997 wip_nav: *WipNav,
2998) (UpdateError || Writer.Error)!void {
2999 const zcu = pt.zcu;
3000 const ip = &zcu.intern_pool;
3001 const nav = ip.getNav(nav_index);
3002 log.debug("finishWipNav({f})", .{nav.fqn.fmt(ip)});
3003
3004 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
3005 try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.written());
3006 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written());
3007
3008 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
3009}
3010
3011pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void {
3012 return updateComptimeNavInner(dwarf, pt, nav_index) catch |err| switch (err) {
3013 error.OutOfMemory => error.OutOfMemory,
3014 else => |e| pt.zcu.codegenFail(nav_index, "failed to update dwarf: {s}", .{@errorName(e)}),
3015 };
3016}
3017
3018fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
3019 const zcu = pt.zcu;
3020 const ip = &zcu.intern_pool;
3021
3022 const nav = ip.getNav(nav_index);
3023 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
3024 const nav_val: Value = .fromInterned(nav.resolved.?.value);
3025 const file = zcu.fileByIndex(inst_info.file);
3026 const decl = file.zir.?.getDeclaration(inst_info.inst);
3027 log.debug("updateComptimeNav({s}:{d}:{d} %{d} = {f})", .{
3028 file.sub_file_path,
3029 decl.src_line + 1,
3030 decl.src_column + 1,
3031 @backingInt(inst_info.inst),
3032 nav.fqn.fmt(ip),
3033 });
3034
3035 const is_test = switch (decl.kind) {
3036 .unnamed_test, .@"test", .decltest => true,
3037 .@"comptime", .@"const", .@"var" => false,
3038 };
3039 if (is_test) {
3040 // This isn't actually a comptime Nav! It's a test, so it'll definitely never be referenced at comptime.
3041 return;
3042 }
3043
3044 const tag: union(enum) {
3045 alias,
3046 @"var",
3047 @"const",
3048 func: Type,
3049 func_alias: InternPool.Nav.Index,
3050 } = switch (ip.indexToKey(nav_val.toIntern())) {
3051 .int_type,
3052 .ptr_type,
3053 .array_type,
3054 .vector_type,
3055 .opt_type,
3056 .error_union_type,
3057 .anyframe_type,
3058 .simple_type,
3059 .tuple_type,
3060 .func_type,
3061 .error_set_type,
3062 .inferred_error_set_type,
3063 .spirv_type,
3064 => .alias,
3065
3066 .struct_type => tag: {
3067 const loaded_struct = ip.loadStructType(nav_val.toIntern());
3068 if (nav_index.toOptional() == loaded_struct.name_nav) {
3069 // This Nav's entry is populated by the type, not the actual Nav.
3070 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
3071 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
3072 return;
3073 }
3074 break :tag .alias;
3075 },
3076 .enum_type => tag: {
3077 const loaded_enum = ip.loadEnumType(nav_val.toIntern());
3078 if (nav_index.toOptional() == loaded_enum.name_nav) {
3079 // This Nav's entry is populated by the type, not the actual Nav.
3080 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
3081 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
3082 return;
3083 }
3084 break :tag .alias;
3085 },
3086 .union_type => tag: {
3087 const loaded_union = ip.loadUnionType(nav_val.toIntern());
3088 if (nav_index.toOptional() == loaded_union.name_nav) {
3089 // This Nav's entry is populated by the type, not the actual Nav.
3090 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
3091 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
3092 return;
3093 }
3094 break :tag .alias;
3095 },
3096 .opaque_type => tag: {
3097 const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
3098 if (nav_index.toOptional() == loaded_opaque.name_nav) {
3099 // This Nav's entry is populated by the type, not the actual Nav.
3100 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern());
3101 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
3102 return;
3103 }
3104 break :tag .alias;
3105 },
3106
3107 .undef,
3108 .simple_value,
3109 .int,
3110 .err,
3111 .error_union,
3112 .enum_literal,
3113 .enum_tag,
3114 .float,
3115 .ptr,
3116 .slice,
3117 .opt,
3118 .aggregate,
3119 .un,
3120 .bitpack,
3121 => if (nav.resolved.?.@"const") .@"const" else .@"var",
3122
3123 .@"extern" => unreachable,
3124
3125 .func => |func| tag: {
3126 if (func.owner_nav != nav_index) break :tag .{ .func_alias = func.owner_nav };
3127 break :tag .{ .func = .fromInterned(func.ty) };
3128 },
3129
3130 // memoization, not types
3131 .memoized_call => unreachable,
3132 };
3133
3134 const unit = try dwarf.getUnit(file.mod.?);
3135
3136 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
3137 errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
3138
3139 if (nav_gop.found_existing) {
3140 if (tag == .func) switch (try dwarf.debug_info.declAbbrevCode(unit, nav_gop.value_ptr.*)) {
3141 else => unreachable,
3142
3143 .decl_nullary_func,
3144 .decl_func,
3145 .decl_instance_nullary_func,
3146 .decl_instance_func,
3147 => return,
3148
3149 .null,
3150 .decl_nullary_func_generic,
3151 .decl_func_generic,
3152 .decl_instance_nullary_func_generic,
3153 .decl_instance_func_generic,
3154 => {},
3155 };
3156 dwarf.debug_info.section.getUnit(unit).getEntry(nav_gop.value_ptr.*).clear();
3157 } else {
3158 nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
3159 }
3160
3161 var wip_nav: WipNav = .{
3162 .dwarf = dwarf,
3163 .pt = pt,
3164 .unit = unit,
3165 .entry = nav_gop.value_ptr.*,
3166 .any_children = false,
3167 .func = .none,
3168 .func_sym_index = undefined,
3169 .func_high_pc = undefined,
3170 .blocks = undefined,
3171 .cfi = undefined,
3172 .debug_frame = .init(dwarf.gpa),
3173 .debug_info = .init(dwarf.gpa),
3174 .debug_line = .init(dwarf.gpa),
3175 .debug_loclists = .init(dwarf.gpa),
3176 };
3177 defer wip_nav.deinit();
3178 const diw = &wip_nav.debug_info.writer;
3179
3180 switch (tag) {
3181 .alias => {
3182 try wip_nav.declCommon(.{
3183 .decl = .decl_alias,
3184 .decl_specification = .decl_specification_const,
3185 .decl_instance = .decl_instance_alias,
3186 }, &nav, inst_info.file, &decl);
3187 try wip_nav.refType(nav_val.toType());
3188 },
3189 .@"var" => {
3190 try wip_nav.declCommon(.{
3191 .decl = .decl_var,
3192 .decl_specification = .decl_specification_var,
3193 .decl_instance = .decl_instance_var,
3194 }, &nav, inst_info.file, &decl);
3195 try wip_nav.strp(switch (decl.linkage) {
3196 .normal => nav.fqn,
3197 .@"extern", .@"export" => nav.name,
3198 }.toSlice(ip));
3199 const nav_ty = nav_val.typeOf(zcu);
3200 try wip_nav.refType(nav_ty);
3201 try wip_nav.blockValue(nav_val);
3202 try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse
3203 nav_ty.abiAlignment(zcu).toByteUnits().?);
3204 try diw.writeByte(@intFromBool(decl.linkage != .normal));
3205 },
3206 .@"const" => {
3207 const nav_ty = nav_val.typeOf(zcu);
3208 const has_runtime_bits = nav_ty.hasRuntimeBits(zcu);
3209 const has_comptime_state = nav_ty.comptimeOnly(zcu);
3210 try wip_nav.declCommon(if (has_runtime_bits and has_comptime_state) .{
3211 .decl = .decl_const_runtime_bits_comptime_state,
3212 .decl_specification = .decl_specification_const,
3213 .decl_instance = .decl_instance_const_runtime_bits_comptime_state,
3214 } else if (has_comptime_state) .{
3215 .decl = .decl_const_comptime_state,
3216 .decl_specification = .decl_specification_const,
3217 .decl_instance = .decl_instance_const_comptime_state,
3218 } else if (has_runtime_bits) .{
3219 .decl = .decl_const_runtime_bits,
3220 .decl_specification = .decl_specification_const,
3221 .decl_instance = .decl_instance_const_runtime_bits,
3222 } else .{
3223 .decl = .decl_const,
3224 .decl_specification = .decl_specification_const,
3225 .decl_instance = .decl_instance_const,
3226 }, &nav, inst_info.file, &decl);
3227 try wip_nav.strp(switch (decl.linkage) {
3228 .normal => nav.fqn,
3229 .@"extern", .@"export" => nav.name,
3230 }.toSlice(ip));
3231 const nav_ty_reloc_index = try wip_nav.refForward();
3232 try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse
3233 nav_ty.abiAlignment(zcu).toByteUnits().?);
3234 try diw.writeByte(@intFromBool(decl.linkage != .normal));
3235 if (has_runtime_bits) try wip_nav.blockValue(nav_val);
3236 if (has_comptime_state) try wip_nav.refValue(nav_val);
3237 wip_nav.finishForward(nav_ty_reloc_index);
3238 try wip_nav.abbrevCode(.is_const);
3239 try wip_nav.refType(nav_ty);
3240 },
3241 .func => |func_ty| {
3242 const func_type = ip.indexToKey(func_ty.toIntern()).func_type;
3243 const is_nullary = !func_type.is_var_args and for (0..func_type.param_types.len) |param_index| {
3244 if (!func_type.paramIsComptime(std.math.cast(u5, param_index) orelse break false)) break false;
3245 } else true;
3246 try wip_nav.declCommon(if (is_nullary) .{
3247 .decl = .decl_nullary_func_generic,
3248 .decl_specification = .decl_specification_func,
3249 .decl_instance = .decl_instance_nullary_func_generic,
3250 } else .{
3251 .decl = .decl_func_generic,
3252 .decl_specification = .decl_specification_func,
3253 .decl_instance = .decl_instance_func_generic,
3254 }, &nav, inst_info.file, &decl);
3255 try wip_nav.refType(.fromInterned(func_type.return_type));
3256 if (!is_nullary) {
3257 for (0..func_type.param_types.len) |param_index| {
3258 if (std.math.cast(u5, param_index)) |small_param_index|
3259 if (func_type.paramIsComptime(small_param_index)) continue;
3260 try wip_nav.abbrevCode(.func_type_param);
3261 try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
3262 }
3263 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
3264 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3265 }
3266 },
3267 .func_alias => |owner_nav| {
3268 try wip_nav.declCommon(.{
3269 .decl = .decl_alias,
3270 .decl_specification = .decl_specification_const,
3271 .decl_instance = .decl_instance_alias,
3272 }, &nav, inst_info.file, &decl);
3273 try wip_nav.refNav(owner_nav);
3274 },
3275 }
3276 try dwarf.debug_info.section.replaceEntry(unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
3277 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
3278}
3279
3280pub fn updateContainerType(
3281 dwarf: *Dwarf,
3282 pt: Zcu.PerThread,
3283 ty: InternPool.Index,
3284 success: bool,
3285) !void {
3286 try dwarf.const_pool.updateContainerType(pt, dwarf.constPoolUser(), ty, success);
3287}
3288/// Should only be called by the `link.ConstPool` implementation.
3289pub fn addConst(dwarf: *Dwarf, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
3290 addConstInner(dwarf, pt, index, val) catch |err| switch (err) {
3291 error.OutOfMemory => |e| return e,
3292 else => |e| std.debug.panic("DWARF TODO: '{t}' while registering constant\n", .{e}),
3293 };
3294}
3295fn addConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) !void {
3296 const zcu = pt.zcu;
3297 const ip = &zcu.intern_pool;
3298
3299 const unit: Unit.Index, const entry: Entry.Index = switch (ip.indexToKey(val)) {
3300 else => .{ .main, try dwarf.addCommonEntry(.main) },
3301 .func => |func| try dwarf.getNavEntry(func.owner_nav),
3302 .@"extern" => |@"extern"| try dwarf.getNavEntry(@"extern".owner_nav),
3303 .struct_type, .union_type, .enum_type, .opaque_type => |_, tag| entry: {
3304 const name_nav = switch (tag) {
3305 .struct_type => ip.loadStructType(val).name_nav,
3306 .union_type => ip.loadUnionType(val).name_nav,
3307 .enum_type => ip.loadEnumType(val).name_nav,
3308 .opaque_type => ip.loadOpaqueType(val).name_nav,
3309 else => unreachable,
3310 };
3311 if (name_nav.unwrap()) |nav| {
3312 break :entry try dwarf.getNavEntry(nav);
3313 } else {
3314 const zir_index = Type.fromInterned(val).typeDeclInstAllowGeneratedTag(zcu).?;
3315 const unit = try dwarf.getUnit(zcu.fileByIndex(zir_index.resolveFile(ip)).mod.?);
3316 break :entry .{ unit, try dwarf.addCommonEntry(unit) };
3317 }
3318 },
3319 };
3320
3321 assert(@backingInt(index) == dwarf.values.items.len);
3322 try dwarf.values.append(dwarf.gpa, .{ unit, entry });
3323}
3324/// Should only be called by the `link.ConstPool` implementation.
3325///
3326/// Emits a "dummy" DIE for the given comptime-only value (which may be a type). For types, this is
3327/// an opaque type. Otherwise, it is an undefined value of the value's type.
3328pub fn updateConstIncomplete(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) Allocator.Error!void {
3329 updateConstIncompleteInner(dwarf, pt, debug_const_index, value_index) catch |err| switch (err) {
3330 error.OutOfMemory => |e| return e,
3331 else => |e| std.debug.panic("DWARF TODO: '{t}' while updating incomplete constant\n", .{e}),
3332 };
3333}
3334fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) !void {
3335 const zcu = pt.zcu;
3336 const ip = &zcu.intern_pool;
3337
3338 const val: Value = .fromInterned(value_index);
3339
3340 switch (value_index) {
3341 .generic_poison_type => log.debug("updateValueIncomplete(anytype)", .{}),
3342 else => log.debug("updateValueIncomplete(@as({f}, {f}))", .{
3343 val.typeOf(zcu).fmt(pt),
3344 val.fmtValue(pt),
3345 }),
3346 }
3347
3348 const unit, const entry = dwarf.values.items[@backingInt(debug_const_index)];
3349
3350 for ([_]*Section{
3351 &dwarf.debug_aranges.section,
3352 &dwarf.debug_aranges.section,
3353 &dwarf.debug_info.section,
3354 &dwarf.debug_line.section,
3355 &dwarf.debug_loclists.section,
3356 &dwarf.debug_rnglists.section,
3357 }) |sec| sec.getUnit(unit).getEntry(entry).clear();
3358
3359 var wip_nav: WipNav = .{
3360 .dwarf = dwarf,
3361 .pt = pt,
3362 .unit = unit,
3363 .entry = entry,
3364 .any_children = false,
3365 .func = .none,
3366 .func_sym_index = undefined,
3367 .func_high_pc = undefined,
3368 .blocks = undefined,
3369 .cfi = undefined,
3370 .debug_frame = .init(dwarf.gpa),
3371 .debug_info = .init(dwarf.gpa),
3372 .debug_line = .init(dwarf.gpa),
3373 .debug_loclists = .init(dwarf.gpa),
3374 };
3375 defer wip_nav.deinit();
3376
3377 switch (ip.indexToKey(value_index)) {
3378 // Container types still need to be valid namespaces.
3379 .struct_type => {
3380 const loaded_struct = ip.loadStructType(value_index);
3381 const root_of_file: ?Zcu.File.Index = if (loaded_struct.zir_index.resolveFull(ip)) |r| f: {
3382 if (r.inst != .main_struct_inst) break :f null;
3383 break :f r.file;
3384 } else null;
3385 if (root_of_file) |file_index| {
3386 assert(loaded_struct.name_nav == .none);
3387 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file_index);
3388 try wip_nav.abbrevCode(.empty_file);
3389 try wip_nav.debug_info.writer.writeUleb128(file_gop.index);
3390 try wip_nav.strp(loaded_struct.fqn.toSlice(ip));
3391 } else {
3392 try dwarf.emitIncompleteContainerType(
3393 &wip_nav,
3394 loaded_struct.zir_index,
3395 loaded_struct.fqn,
3396 loaded_struct.name_nav,
3397 );
3398 }
3399 },
3400 .union_type => {
3401 const loaded_union = ip.loadUnionType(value_index);
3402 try dwarf.emitIncompleteContainerType(
3403 &wip_nav,
3404 loaded_union.zir_index,
3405 loaded_union.fqn,
3406 loaded_union.name_nav,
3407 );
3408 },
3409 .enum_type => {
3410 const loaded_enum = ip.loadEnumType(value_index);
3411 if (loaded_enum.zir_index.unwrap()) |zir_index| {
3412 try dwarf.emitIncompleteContainerType(
3413 &wip_nav,
3414 zir_index,
3415 loaded_enum.fqn,
3416 loaded_enum.name_nav,
3417 );
3418 } else {
3419 try wip_nav.abbrevCode(.generated_empty_struct_type);
3420 try wip_nav.strp(loaded_enum.fqn.toSlice(ip));
3421 try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
3422 }
3423 },
3424 .opaque_type => {
3425 const loaded_opaque = ip.loadOpaqueType(value_index);
3426 try dwarf.emitIncompleteContainerType(
3427 &wip_nav,
3428 loaded_opaque.zir_index,
3429 loaded_opaque.fqn,
3430 loaded_opaque.name_nav,
3431 );
3432 },
3433 // Not a container type, so just emit a dummy entry. If `val` happens to be a type, we'll
3434 // emit it as if it were an opaque type so that we can name it.
3435 else => |val_key| switch (val_key.typeOf()) {
3436 .type_type => {
3437 try wip_nav.abbrevCode(.generated_empty_struct_type);
3438 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3439 try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
3440 },
3441 else => |ty| {
3442 try wip_nav.abbrevCode(.undefined_comptime_value);
3443 try wip_nav.refType(.fromInterned(ty));
3444 },
3445 },
3446 }
3447 try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written());
3448 try dwarf.debug_loclists.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_loclists.written());
3449}
3450fn emitIncompleteContainerType(
3451 dwarf: *Dwarf,
3452 wip_nav: *WipNav,
3453 zir_index: InternPool.TrackedInst.Index,
3454 fqn: InternPool.NullTerminatedString,
3455 name_nav: InternPool.Nav.Index.Optional,
3456) !void {
3457 const zcu = wip_nav.pt.zcu;
3458 const ip = &zcu.intern_pool;
3459 const file = zir_index.resolveFile(ip);
3460 if (name_nav.unwrap()) |nav_index| {
3461 const nav = ip.getNav(nav_index);
3462 const decl_inst = nav.srcInst(ip).resolve(ip).?;
3463 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
3464 try wip_nav.declCommon(.{
3465 .decl = .decl_namespace_struct,
3466 .decl_specification = .decl_specification_const,
3467 .decl_instance = .decl_instance_namespace_struct,
3468 }, &nav, file, &decl);
3469 try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
3470 } else {
3471 const diw = &wip_nav.debug_info.writer;
3472 const file_gop = try dwarf.getModInfo(wip_nav.unit).files.getOrPut(dwarf.gpa, file);
3473 try wip_nav.abbrevCode(.empty_struct_type);
3474 try diw.writeUleb128(file_gop.index);
3475 try wip_nav.strp(fqn.toSlice(ip));
3476 try diw.writeByte(@intFromBool(true));
3477 }
3478}
3479/// Should only be called by the `link.ConstPool` implementation.
3480///
3481/// Emits a DIE for the given comptime-only value (which may be a type).
3482pub fn updateConst(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) Allocator.Error!void {
3483 updateConstInner(dwarf, pt, debug_const_index, value_index) catch |err| switch (err) {
3484 error.OutOfMemory => |e| return e,
3485 else => |e| std.debug.panic("DWARF TODO: '{t}' while updating constant\n", .{e}),
3486 };
3487}
3488fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) !void {
3489 const zcu = pt.zcu;
3490 const ip = &zcu.intern_pool;
3491
3492 const val: Value = .fromInterned(value_index);
3493
3494 if (val.typeOf(zcu).toIntern() == .type_type and !val.isUndef(zcu)) {
3495 val.toType().assertHasLayout(zcu);
3496 } else {
3497 val.typeOf(zcu).assertHasLayout(zcu);
3498 }
3499
3500 if (value_index == .anyerror_type) return; // handled in `flush` instead
3501
3502 const value_ip_key = ip.indexToKey(value_index);
3503 switch (value_ip_key) {
3504 .func => return, // populated by the Nav instead (`updateComptimeNav` or `initWipNav`)
3505 .@"extern" => return, // populated by the Nav instead (`initWipNav`)
3506 else => {},
3507 }
3508
3509 switch (value_index) {
3510 .generic_poison_type => log.debug("updateValue(anytype)", .{}),
3511 else => log.debug("updateValue(@as({f}, {f}))", .{
3512 val.typeOf(zcu).fmt(pt),
3513 val.fmtValue(pt),
3514 }),
3515 }
3516
3517 const unit, const entry = dwarf.values.items[@backingInt(debug_const_index)];
3518
3519 for ([_]*Section{
3520 &dwarf.debug_aranges.section,
3521 &dwarf.debug_info.section,
3522 &dwarf.debug_line.section,
3523 &dwarf.debug_loclists.section,
3524 &dwarf.debug_rnglists.section,
3525 }) |sec| sec.getUnit(unit).getEntry(entry).clear();
3526
3527 var wip_nav: WipNav = .{
3528 .dwarf = dwarf,
3529 .pt = pt,
3530 .unit = unit,
3531 .entry = entry,
3532 .any_children = false,
3533 .func = .none,
3534 .func_sym_index = undefined,
3535 .func_high_pc = undefined,
3536 .blocks = undefined,
3537 .cfi = undefined,
3538 .debug_frame = .init(dwarf.gpa),
3539 .debug_info = .init(dwarf.gpa),
3540 .debug_line = .init(dwarf.gpa),
3541 .debug_loclists = .init(dwarf.gpa),
3542 };
3543 defer wip_nav.deinit();
3544
3545 const diw = &wip_nav.debug_info.writer;
3546 var big_int_space: Value.BigIntSpace = undefined;
3547 switch (value_ip_key) {
3548 .func => unreachable, // handled above
3549 .@"extern" => unreachable, // handled above
3550 .spirv_type => unreachable,
3551
3552 .int_type => |int_type| {
3553 try wip_nav.abbrevCode(.numeric_type);
3554 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3555 try diw.writeByte(switch (int_type.signedness) {
3556 inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)),
3557 });
3558 try diw.writeUleb128(int_type.bits);
3559 try diw.writeUleb128(val.toType().abiSize(zcu));
3560 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
3561 },
3562 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
3563 .one, .many, .c => {
3564 const ptr_child_type: Type = .fromInterned(ptr_type.child);
3565 try wip_nav.abbrevCode(switch (ptr_type.flags.alignment) {
3566 .none => if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type,
3567 else => if (ptr_type.sentinel == .none) .ptr_aligned_type else .ptr_aligned_sentinel_type,
3568 });
3569 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3570 if (ptr_type.sentinel != .none) try wip_nav.blockValue(.fromInterned(ptr_type.sentinel));
3571 if (ptr_type.flags.alignment.toByteUnits()) |a| try diw.writeUleb128(a);
3572 try diw.writeByte(@backingInt(ptr_type.flags.address_space));
3573 if (ptr_type.flags.is_const or ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
3574 .debug_info,
3575 wip_nav.unit,
3576 wip_nav.entry,
3577 @intCast(diw.end + dwarf.sectionOffsetBytes()),
3578 ) else try wip_nav.refType(ptr_child_type);
3579 if (ptr_type.flags.is_const) {
3580 try wip_nav.abbrevCode(.is_const);
3581 if (ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
3582 .debug_info,
3583 wip_nav.unit,
3584 wip_nav.entry,
3585 @intCast(diw.end + dwarf.sectionOffsetBytes()),
3586 ) else try wip_nav.refType(ptr_child_type);
3587 }
3588 if (ptr_type.flags.is_volatile) {
3589 try wip_nav.abbrevCode(.is_volatile);
3590 try wip_nav.refType(ptr_child_type);
3591 }
3592 },
3593 .slice => {
3594 try wip_nav.abbrevCode(.generated_struct_type);
3595 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3596 try diw.writeUleb128(val.toType().abiSize(zcu));
3597 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
3598 try wip_nav.abbrevCode(.generated_field);
3599 try wip_nav.strp("ptr");
3600 const ptr_field_type = val.toType().slicePtrFieldType(zcu);
3601 try wip_nav.refType(ptr_field_type);
3602 try diw.writeUleb128(0);
3603 try wip_nav.abbrevCode(.generated_field);
3604 try wip_nav.strp("len");
3605 const len_field_type: Type = .usize;
3606 try wip_nav.refType(len_field_type);
3607 try diw.writeUleb128(len_field_type.abiAlignment(zcu).forward(ptr_field_type.abiSize(zcu)));
3608 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3609 },
3610 },
3611 .array_type => |array_type| {
3612 const array_child_type: Type = .fromInterned(array_type.child);
3613 try wip_nav.abbrevCode(if (array_type.sentinel == .none) .array_type else .array_sentinel_type);
3614 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3615 if (array_type.sentinel != .none) try wip_nav.blockValue(.fromInterned(array_type.sentinel));
3616 try wip_nav.refType(array_child_type);
3617 try wip_nav.abbrevCode(.array_len);
3618 try wip_nav.refType(.usize);
3619 try diw.writeUleb128(array_type.len);
3620 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3621 },
3622 .vector_type => |vector_type| {
3623 try wip_nav.abbrevCode(.vector_type);
3624 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3625 try wip_nav.refType(.fromInterned(vector_type.child));
3626 try wip_nav.abbrevCode(.array_len);
3627 try wip_nav.refType(.usize);
3628 try diw.writeUleb128(vector_type.len);
3629 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3630 },
3631 .opt_type => |opt_child_type_index| {
3632 const opt_child_type: Type = .fromInterned(opt_child_type_index);
3633 const opt_repr = optRepr(opt_child_type, zcu);
3634 try wip_nav.abbrevCode(.generated_union_type);
3635 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3636 try diw.writeUleb128(val.toType().abiSize(zcu));
3637 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
3638 switch (opt_repr) {
3639 .opv_null => {
3640 try wip_nav.abbrevCode(.generated_field);
3641 try wip_nav.strp("null");
3642 try wip_nav.refType(.null);
3643 try diw.writeUleb128(0);
3644 },
3645 .unpacked, .error_set, .pointer => {
3646 try wip_nav.abbrevCode(.tagged_union);
3647 try wip_nav.infoSectionOffset(
3648 .debug_info,
3649 wip_nav.unit,
3650 wip_nav.entry,
3651 @intCast(diw.end + dwarf.sectionOffsetBytes()),
3652 );
3653 {
3654 try wip_nav.abbrevCode(.generated_field);
3655 try wip_nav.strp("has_value");
3656 switch (opt_repr) {
3657 .opv_null => unreachable,
3658 .unpacked => {
3659 try wip_nav.refType(.bool);
3660 try diw.writeUleb128(if (opt_child_type.hasRuntimeBits(zcu))
3661 opt_child_type.abiSize(zcu)
3662 else
3663 0);
3664 },
3665 .error_set => {
3666 try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
3667 .signedness = .unsigned,
3668 .bits = zcu.errorSetBits(),
3669 } })));
3670 try diw.writeUleb128(0);
3671 },
3672 .pointer => {
3673 try wip_nav.refType(.usize);
3674 try diw.writeUleb128(0);
3675 },
3676 }
3677
3678 try wip_nav.abbrevCode(.tagged_union_field);
3679 try diw.writeUleb128(DW.FORM.udata);
3680 try diw.writeUleb128(0);
3681 {
3682 try wip_nav.abbrevCode(.generated_field);
3683 try wip_nav.strp("null");
3684 try wip_nav.refType(.null);
3685 try diw.writeUleb128(0);
3686 }
3687 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3688
3689 try wip_nav.abbrevCode(.tagged_union_default_field);
3690 {
3691 try wip_nav.abbrevCode(.generated_field);
3692 try wip_nav.strp("?");
3693 try wip_nav.refType(opt_child_type);
3694 try diw.writeUleb128(0);
3695 }
3696 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3697 }
3698 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3699 },
3700 }
3701 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3702 },
3703 .anyframe_type => unreachable,
3704 .error_union_type => |error_union_type| {
3705 const error_union_error_set_type: Type = .fromInterned(error_union_type.error_set_type);
3706 const error_union_payload_type: Type = .fromInterned(error_union_type.payload_type);
3707 const error_union_error_set_offset, const error_union_payload_offset = switch (error_union_type.payload_type) {
3708 .generic_poison_type => .{ 0, 0 },
3709 else => .{
3710 codegen.errUnionErrorOffset(error_union_payload_type, zcu),
3711 codegen.errUnionPayloadOffset(error_union_payload_type, zcu),
3712 },
3713 };
3714
3715 try wip_nav.abbrevCode(.generated_union_type);
3716 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3717 if (error_union_type.error_set_type != .generic_poison_type and
3718 error_union_type.payload_type != .generic_poison_type)
3719 {
3720 try diw.writeUleb128(val.toType().abiSize(zcu));
3721 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
3722 } else {
3723 try diw.writeUleb128(0);
3724 try diw.writeUleb128(1);
3725 }
3726 {
3727 try wip_nav.abbrevCode(.tagged_union);
3728 try wip_nav.infoSectionOffset(
3729 .debug_info,
3730 wip_nav.unit,
3731 wip_nav.entry,
3732 @intCast(diw.end + dwarf.sectionOffsetBytes()),
3733 );
3734 {
3735 try wip_nav.abbrevCode(.generated_field);
3736 try wip_nav.strp("is_error");
3737 try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
3738 .signedness = .unsigned,
3739 .bits = zcu.errorSetBits(),
3740 } })));
3741 try diw.writeUleb128(error_union_error_set_offset);
3742
3743 try wip_nav.abbrevCode(.tagged_union_field);
3744 try diw.writeUleb128(DW.FORM.udata);
3745 try diw.writeUleb128(0);
3746 {
3747 try wip_nav.abbrevCode(.generated_field);
3748 try wip_nav.strp("value");
3749 try wip_nav.refType(error_union_payload_type);
3750 try diw.writeUleb128(error_union_payload_offset);
3751 }
3752 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3753
3754 try wip_nav.abbrevCode(.tagged_union_default_field);
3755 {
3756 try wip_nav.abbrevCode(.generated_field);
3757 try wip_nav.strp("error");
3758 try wip_nav.refType(error_union_error_set_type);
3759 try diw.writeUleb128(error_union_error_set_offset);
3760 }
3761 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3762 }
3763 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3764 }
3765 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3766 },
3767 .simple_type => |simple_type| switch (simple_type) {
3768 .f16,
3769 .f32,
3770 .f64,
3771 .f80,
3772 .f128,
3773 .usize,
3774 .isize,
3775 .c_char,
3776 .c_short,
3777 .c_ushort,
3778 .c_int,
3779 .c_uint,
3780 .c_long,
3781 .c_ulong,
3782 .c_longlong,
3783 .c_ulonglong,
3784 .c_longdouble,
3785 .bool,
3786 => {
3787 try wip_nav.abbrevCode(.numeric_type);
3788 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3789 try diw.writeByte(if (value_index == .bool_type)
3790 DW.ATE.boolean
3791 else if (val.toType().isRuntimeFloat())
3792 DW.ATE.float
3793 else if (val.toType().isSignedInt(zcu))
3794 DW.ATE.signed
3795 else if (val.toType().isUnsignedInt(zcu))
3796 DW.ATE.unsigned
3797 else
3798 unreachable);
3799 try diw.writeUleb128(val.toType().bitSize(zcu));
3800 try diw.writeUleb128(val.toType().abiSize(zcu));
3801 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
3802 },
3803 .generic_poison => {
3804 try wip_nav.abbrevCode(.void_type);
3805 try wip_nav.strp("anytype");
3806 },
3807 .anyopaque,
3808 .void,
3809 .type,
3810 .comptime_int,
3811 .comptime_float,
3812 .noreturn,
3813 .null,
3814 .undefined,
3815 .enum_literal,
3816 => {
3817 try wip_nav.abbrevCode(.void_type);
3818 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3819 },
3820 .anyerror => unreachable, // already did early return above
3821 .adhoc_inferred_error_set => unreachable,
3822 },
3823 .tuple_type => |tuple_type| if (tuple_type.types.len == 0) {
3824 try wip_nav.abbrevCode(.generated_empty_struct_type);
3825 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3826 try diw.writeByte(@intFromBool(false));
3827 } else {
3828 try wip_nav.abbrevCode(.generated_struct_type);
3829 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
3830 try diw.writeUleb128(val.toType().abiSize(zcu));
3831 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
3832 var field_byte_offset: u64 = 0;
3833 for (0..tuple_type.types.len) |field_index| {
3834 const comptime_value = tuple_type.values.get(ip)[field_index];
3835 const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);
3836 const has_runtime_bits, const has_comptime_state = switch (comptime_value) {
3837 .none => .{ false, false },
3838 else => .{ field_type.hasRuntimeBits(zcu), field_type.comptimeOnly(zcu) },
3839 };
3840 try wip_nav.abbrevCode(if (has_comptime_state)
3841 .field_comptime_comptime_state
3842 else if (has_runtime_bits)
3843 .field_comptime_runtime_bits
3844 else if (comptime_value != .none)
3845 .field_comptime
3846 else
3847 .field);
3848 {
3849 var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined;
3850 const field_name = std.mem.print(&field_name_buf, "{d}", .{field_index}) catch unreachable;
3851 try wip_nav.strp(field_name);
3852 }
3853 try wip_nav.refType(field_type);
3854 if (comptime_value == .none) {
3855 const field_align = field_type.abiAlignment(zcu);
3856 field_byte_offset = field_align.forward(field_byte_offset);
3857 try diw.writeUleb128(field_byte_offset);
3858 try diw.writeUleb128(field_type.abiAlignment(zcu).toByteUnits().?);
3859 field_byte_offset += field_type.abiSize(zcu);
3860 }
3861 if (has_comptime_state)
3862 try wip_nav.refValue(.fromInterned(comptime_value))
3863 else if (has_runtime_bits)
3864 try wip_nav.blockValue(.fromInterned(comptime_value));
3865 }
3866 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3867 },
3868 .struct_type => {
3869 const loaded_struct = ip.loadStructType(value_index);
3870 const ty = val.toType();
3871 const file = loaded_struct.zir_index.resolveFile(ip);
3872 switch (loaded_struct.layout) {
3873 .auto, .@"extern" => {
3874 const struct_is_file: bool = if (loaded_struct.zir_index.resolve(ip)) |inst| f: {
3875 break :f inst == .main_struct_inst;
3876 } else false;
3877 if (loaded_struct.name_nav.unwrap()) |nav_index| {
3878 assert(!struct_is_file);
3879 const nav = ip.getNav(nav_index);
3880 const decl_inst = nav.srcInst(ip).resolve(ip).?;
3881 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
3882 try wip_nav.declCommon(if (loaded_struct.field_types.len == 0) .{
3883 .decl = .decl_namespace_struct,
3884 .decl_specification = .decl_specification_const,
3885 .decl_instance = .decl_instance_namespace_struct,
3886 } else .{
3887 .decl = .decl_struct,
3888 .decl_specification = .decl_specification_const,
3889 .decl_instance = .decl_instance_struct,
3890 }, &nav, file, &decl);
3891 } else {
3892 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
3893 try wip_nav.abbrevCode(switch (loaded_struct.field_types.len) {
3894 0 => if (struct_is_file) .empty_file else .empty_struct_type,
3895 else => if (struct_is_file) .file else .struct_type,
3896 });
3897 try diw.writeUleb128(file_gop.index);
3898 try wip_nav.strp(loaded_struct.fqn.toSlice(ip));
3899 }
3900 if (loaded_struct.field_types.len == 0) {
3901 if (!struct_is_file) try diw.writeByte(@intFromBool(false));
3902 } else {
3903 try diw.writeUleb128(ty.abiSize(zcu));
3904 try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
3905 for (0..loaded_struct.field_types.len) |field_index| {
3906 const is_comptime = loaded_struct.field_is_comptime_bits.get(ip, field_index);
3907 // TODO: we currently don't emit information about default values for
3908 // non-`comptime` fields, because these default values are resolved at a
3909 // separate time in the compiler frontend. To emit this information, the
3910 // frontend needs to tell us when the default values are available: like
3911 // how `Zcu.PerThread.ensureTypeLayoutUpToDate` enqueues a link task to
3912 // indicate completion of the type's layout, a task should be enqueued
3913 // by `Zcu.PerThread.ensureStructDefaultsUpToDate`, and upon receiving
3914 // it we should patch the correct default field values in.
3915 const field_init: InternPool.Index = if (is_comptime) loaded_struct.field_defaults.getOrNone(ip, field_index) else .none;
3916 assert(!(is_comptime and field_init == .none));
3917 const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
3918 const has_runtime_bits, const has_comptime_state = switch (field_init) {
3919 .none => .{ false, false },
3920 else => .{
3921 field_type.hasRuntimeBits(zcu),
3922 field_type.comptimeOnly(zcu),
3923 },
3924 };
3925 try wip_nav.abbrevCode(if (is_comptime)
3926 if (has_comptime_state)
3927 .field_comptime_comptime_state
3928 else if (has_runtime_bits)
3929 .field_comptime_runtime_bits
3930 else
3931 .field_comptime
3932 else if (field_init != .none)
3933 if (has_comptime_state)
3934 .field_default_comptime_state
3935 else if (has_runtime_bits)
3936 .field_default_runtime_bits
3937 else
3938 .field
3939 else
3940 .field);
3941 try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
3942 try wip_nav.refType(field_type);
3943 if (!is_comptime) {
3944 try diw.writeUleb128(loaded_struct.field_offsets.get(ip)[field_index]);
3945 try diw.writeUleb128(loaded_struct.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
3946 field_type.abiAlignment(zcu).toByteUnits().?);
3947 }
3948 if (has_comptime_state)
3949 try wip_nav.refValue(.fromInterned(field_init))
3950 else if (has_runtime_bits)
3951 try wip_nav.blockValue(.fromInterned(field_init));
3952 }
3953 try diw.writeUleb128(@backingInt(AbbrevCode.null));
3954 }
3955 },
3956 .@"packed" => {
3957 const need_terminator: bool = if (loaded_struct.name_nav.unwrap()) |nav_index| t: {
3958 const nav = ip.getNav(nav_index);
3959 const decl_inst = nav.srcInst(ip).resolve(ip).?;
3960 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
3961 try wip_nav.declCommon(.{
3962 .decl = .decl_packed_struct,
3963 .decl_specification = .decl_specification_const,
3964 .decl_instance = .decl_instance_packed_struct,
3965 }, &nav, file, &decl);
3966 break :t true;
3967 } else t: {
3968 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
3969 try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type);
3970 try diw.writeUleb128(file_gop.index);
3971 try wip_nav.strp(loaded_struct.fqn.toSlice(ip));
3972 break :t loaded_struct.field_types.len > 0;
3973 };
3974 try wip_nav.refType(.fromInterned(loaded_struct.packed_backing_int_type));
3975 var field_bit_offset: u16 = 0;
3976 for (0..loaded_struct.field_types.len) |field_index| {
3977 try wip_nav.abbrevCode(.packed_field);
3978 try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
3979 const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
3980 try wip_nav.refType(field_type);
3981 try diw.writeUleb128(field_bit_offset);
3982 field_bit_offset += @intCast(field_type.bitSize(zcu));
3983 }
3984 if (need_terminator) try diw.writeUleb128(@backingInt(AbbrevCode.null));
3985 },
3986 }
3987 },
3988 .union_type => {
3989 const loaded_union = ip.loadUnionType(value_index);
3990 const file = loaded_union.zir_index.resolveFile(ip);
3991 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
3992 switch (loaded_union.layout) {
3993 .auto, .@"extern" => {
3994 const need_terminator: bool = if (loaded_union.name_nav.unwrap()) |nav_index| t: {
3995 const nav = ip.getNav(nav_index);
3996 const decl_inst = nav.srcInst(ip).resolve(ip).?;
3997 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
3998 try wip_nav.declCommon(.{
3999 .decl = .decl_union,
4000 .decl_specification = .decl_specification_const,
4001 .decl_instance = .decl_instance_union,
4002 }, &nav, file, &decl);
4003 break :t true;
4004 } else t: {
4005 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
4006 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);
4007 try diw.writeUleb128(file_gop.index);
4008 try wip_nav.strp(loaded_union.fqn.toSlice(ip));
4009 break :t loaded_union.field_types.len > 0;
4010 };
4011 const union_layout = Type.getUnionLayout(loaded_union, zcu);
4012 try diw.writeUleb128(union_layout.abi_size);
4013 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
4014 if (loaded_union.has_runtime_tag) {
4015 try wip_nav.abbrevCode(.tagged_union);
4016 try wip_nav.infoSectionOffset(
4017 .debug_info,
4018 wip_nav.unit,
4019 wip_nav.entry,
4020 @intCast(diw.end + dwarf.sectionOffsetBytes()),
4021 );
4022 {
4023 try wip_nav.abbrevCode(.generated_field);
4024 try wip_nav.strp("tag");
4025 try wip_nav.refType(.fromInterned(loaded_union.enum_tag_type));
4026 try diw.writeUleb128(union_layout.tagOffset());
4027
4028 for (0..loaded_union.field_types.len) |field_index| {
4029 try wip_nav.abbrevCode(.tagged_union_field);
4030 try wip_nav.enumConstValue(loaded_tag, field_index);
4031 {
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(union_layout.payloadOffset());
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 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4041 }
4042 }
4043 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4044 } else for (0..loaded_union.field_types.len) |field_index| {
4045 try wip_nav.abbrevCode(.field);
4046 try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
4047 const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
4048 try wip_nav.refType(field_type);
4049 try diw.writeUleb128(0);
4050 try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
4051 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
4052 }
4053 if (need_terminator) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4054 },
4055 .@"packed" => {
4056 const need_terminator: bool = if (loaded_union.name_nav.unwrap()) |nav_index| t: {
4057 const nav = ip.getNav(nav_index);
4058 const decl_inst = nav.srcInst(ip).resolve(ip).?;
4059 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
4060 try wip_nav.declCommon(.{
4061 .decl = .decl_packed_union,
4062 .decl_specification = .decl_specification_const,
4063 .decl_instance = .decl_instance_packed_union,
4064 }, &nav, file, &decl);
4065 break :t true;
4066 } else t: {
4067 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
4068 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .packed_union_type else .empty_packed_union_type);
4069 try diw.writeUleb128(file_gop.index);
4070 try wip_nav.strp(loaded_union.fqn.toSlice(ip));
4071 break :t loaded_union.field_types.len > 0;
4072 };
4073 try wip_nav.refType(.fromInterned(loaded_union.packed_backing_int_type));
4074 for (0..loaded_union.field_types.len) |field_index| {
4075 try wip_nav.abbrevCode(.packed_field);
4076 try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
4077 try wip_nav.refType(.fromInterned(loaded_union.field_types.get(ip)[field_index]));
4078 try diw.writeUleb128(0);
4079 }
4080 if (need_terminator) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4081 },
4082 }
4083 },
4084 .enum_type => {
4085 const loaded_enum = ip.loadEnumType(value_index);
4086 if (loaded_enum.zir_index.unwrap()) |zir_index| {
4087 assert(loaded_enum.owner_union == .none);
4088 const file = zir_index.resolveFile(ip);
4089 if (loaded_enum.name_nav.unwrap()) |nav_index| {
4090 const nav = ip.getNav(nav_index);
4091 const decl_inst = nav.srcInst(ip).resolve(ip).?;
4092 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
4093 try wip_nav.declCommon(if (loaded_enum.field_names.len > 0) .{
4094 .decl = .decl_enum,
4095 .decl_specification = .decl_specification_const,
4096 .decl_instance = .decl_instance_enum,
4097 } else .{
4098 .decl = .decl_empty_enum,
4099 .decl_specification = .decl_specification_const,
4100 .decl_instance = .decl_instance_empty_enum,
4101 }, &nav, file, &decl);
4102 } else {
4103 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
4104 try wip_nav.abbrevCode(if (loaded_enum.field_names.len > 0) .enum_type else .empty_enum_type);
4105 try diw.writeUleb128(file_gop.index);
4106 try wip_nav.strp(loaded_enum.fqn.toSlice(ip));
4107 }
4108 try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
4109 for (0..loaded_enum.field_names.len) |field_index| {
4110 try wip_nav.abbrevCode(.enum_field);
4111 try wip_nav.enumConstValue(loaded_enum, field_index);
4112 try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
4113 }
4114 if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4115 } else {
4116 assert(loaded_enum.owner_union != .none);
4117 try wip_nav.abbrevCode(if (loaded_enum.field_names.len == 0) .generated_empty_enum_type else .generated_enum_type);
4118 try wip_nav.strp(loaded_enum.fqn.toSlice(ip));
4119 try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
4120 for (0..loaded_enum.field_names.len) |field_index| {
4121 try wip_nav.abbrevCode(.enum_field);
4122 try wip_nav.enumConstValue(loaded_enum, field_index);
4123 try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
4124 }
4125 if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4126 }
4127 },
4128 .opaque_type => {
4129 const loaded_opaque = ip.loadOpaqueType(value_index);
4130 const file = loaded_opaque.zir_index.resolveFile(ip);
4131 if (loaded_opaque.name_nav.unwrap()) |nav_index| {
4132 const nav = ip.getNav(nav_index);
4133 const decl_inst = nav.srcInst(ip).resolve(ip).?;
4134 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
4135 try wip_nav.declCommon(.{
4136 .decl = .decl_namespace_struct,
4137 .decl_specification = .decl_specification_const,
4138 .decl_instance = .decl_instance_namespace_struct,
4139 }, &nav, file, &decl);
4140 } else {
4141 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
4142 try wip_nav.abbrevCode(.empty_struct_type);
4143 try diw.writeUleb128(file_gop.index);
4144 try wip_nav.strp(loaded_opaque.fqn.toSlice(ip));
4145 }
4146 try diw.writeByte(@intFromBool(true));
4147 },
4148 .func_type => |func_type| {
4149 const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
4150 try wip_nav.abbrevCode(if (is_nullary) .nullary_func_type else .func_type);
4151 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
4152 const cc: DW.CC = cc: {
4153 if (zcu.getTarget().cCallingConvention()) |cc| {
4154 if (@as(std.lang.CallingConvention.Tag, cc) == func_type.cc) {
4155 break :cc .normal;
4156 }
4157 }
4158 // For better or worse, we try to match what Clang emits.
4159 break :cc switch (func_type.cc) {
4160 .@"inline" => .nocall,
4161 .async, .auto, .naked => .normal,
4162 .x86_64_sysv => .LLVM_X86_64SysV,
4163 .x86_64_win => .LLVM_Win64,
4164 .x86_64_regcall_v3_sysv => .LLVM_X86RegCall,
4165 .x86_64_regcall_v4_win => .LLVM_X86RegCall,
4166 .x86_64_vectorcall => .LLVM_vectorcall,
4167 .x86_sysv, .x86_win, .x86_mingw => .normal,
4168 .x86_64_preserve_none => .LLVM_PreserveNone,
4169 .x86_stdcall => .BORLAND_stdcall,
4170 .x86_fastcall => .BORLAND_msfastcall,
4171 .x86_thiscall => .BORLAND_thiscall,
4172 .x86_thiscall_mingw => .BORLAND_thiscall,
4173 .x86_regcall_v3 => .LLVM_X86RegCall,
4174 .x86_regcall_v4_win => .LLVM_X86RegCall,
4175 .x86_vectorcall => .LLVM_vectorcall,
4176
4177 .aarch64_aapcs => .normal,
4178 .aarch64_aapcs_darwin => .normal,
4179 .aarch64_aapcs_win => .normal,
4180 .aarch64_vfabi => .LLVM_AAPCS,
4181 .aarch64_vfabi_sve => .LLVM_AAPCS,
4182 .aarch64_preserve_none => .LLVM_PreserveNone,
4183
4184 .arm_aapcs => .LLVM_AAPCS,
4185 .arm_aapcs_vfp => .LLVM_AAPCS_VFP,
4186
4187 .riscv64_lp64_v,
4188 .riscv32_ilp32_v,
4189 => .LLVM_RISCVVectorCall,
4190
4191 .m68k_rtd => .LLVM_M68kRTD,
4192
4193 .sh_renesas => .GNU_renesas_sh,
4194
4195 .amdgcn_kernel => .LLVM_OpenCLKernel,
4196 .nvptx_kernel,
4197 .spirv_kernel,
4198 => .nocall,
4199
4200 .x86_64_interrupt,
4201 .x86_interrupt,
4202 .arm_interrupt,
4203 .mips64_interrupt,
4204 .mips_interrupt,
4205 .riscv64_interrupt,
4206 .riscv32_interrupt,
4207 .sh_interrupt,
4208 .arc_interrupt,
4209 .avr_builtin,
4210 .avr_signal,
4211 .avr_interrupt,
4212 .csky_interrupt,
4213 .m68k_interrupt,
4214 .microblaze_interrupt,
4215 .msp430_interrupt,
4216 => .normal,
4217
4218 else => .nocall,
4219 };
4220 };
4221 try diw.writeByte(@backingInt(cc));
4222 try wip_nav.refType(.fromInterned(func_type.return_type));
4223 if (!is_nullary) {
4224 for (0..func_type.param_types.len) |param_index| {
4225 try wip_nav.abbrevCode(.func_type_param);
4226 try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
4227 }
4228 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
4229 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4230 }
4231 },
4232 .error_set_type => |error_set_type| {
4233 try wip_nav.abbrevCode(if (error_set_type.names.len == 0) .generated_empty_enum_type else .generated_enum_type);
4234 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
4235 try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
4236 .signedness = .unsigned,
4237 .bits = zcu.errorSetBits(),
4238 } })));
4239 for (0..error_set_type.names.len) |field_index| {
4240 const field_name = error_set_type.names.get(ip)[field_index];
4241 try wip_nav.abbrevCode(.enum_field);
4242 try diw.writeUleb128(DW.FORM.udata);
4243 try diw.writeUleb128(ip.getErrorValueIfExists(field_name).?);
4244 try wip_nav.strp(field_name.toSlice(ip));
4245 }
4246 if (error_set_type.names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4247 },
4248 .inferred_error_set_type => |func| {
4249 try wip_nav.abbrevCode(.inferred_error_set_type);
4250 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
4251 try wip_nav.refType(.fromInterned(switch (ip.funcIesResolvedUnordered(func)) {
4252 .none => .anyerror_type,
4253 else => |ies| ies,
4254 }));
4255 },
4256
4257 .undef => |ty| {
4258 try wip_nav.abbrevCode(.undefined_comptime_value);
4259 try wip_nav.refType(.fromInterned(ty));
4260 },
4261 .simple_value => |simple_value| switch (simple_value) {
4262 .void => unreachable, // opv state
4263 .true, .false => unreachable, // runtime bits
4264 .@"unreachable" => unreachable, // not a value
4265 .null => {
4266 // TODO: proper representation for this
4267 try wip_nav.abbrevCode(.undefined_comptime_value);
4268 try wip_nav.refType(.null);
4269 },
4270 },
4271 .int => |int| {
4272 try wip_nav.abbrevCode(.comptime_value);
4273 try wip_nav.refType(.fromInterned(int.ty));
4274 try wip_nav.bigIntConstValue(.fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu));
4275 },
4276 .bitpack => |bitpack| {
4277 const backing_int_val: Value = .fromInterned(bitpack.backing_int_val);
4278 try wip_nav.abbrevCode(.comptime_value);
4279 try wip_nav.refType(.fromInterned(bitpack.ty));
4280 try wip_nav.bigIntConstValue(backing_int_val.typeOf(zcu), backing_int_val.toBigInt(&big_int_space, zcu));
4281 },
4282 .err => |err| {
4283 try wip_nav.abbrevCode(.comptime_value);
4284 try wip_nav.refType(.fromInterned(err.ty));
4285 try diw.writeUleb128(DW.FORM.udata);
4286 try diw.writeUleb128(try pt.getErrorValue(err.name));
4287 },
4288 .error_union => |error_union| {
4289 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value);
4290 try wip_nav.refType(.fromInterned(error_union.ty));
4291 var err_buf: [4]u8 = undefined;
4292 const err_bytes = err_buf[0..@divCeil(zcu.errorSetBits(), 8)];
4293 dwarf.writeInt(err_bytes, switch (error_union.val) {
4294 .err_name => |err_name| try pt.getErrorValue(err_name),
4295 .payload => 0,
4296 });
4297 {
4298 try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
4299 try wip_nav.strp("is_error");
4300 try diw.writeUleb128(err_bytes.len);
4301 try diw.writeAll(err_bytes);
4302 }
4303 payload_field: switch (error_union.val) {
4304 .err_name => {},
4305 .payload => |payload_val| {
4306 const payload_type: Type = .fromInterned(ip.typeOf(payload_val));
4307 const has_runtime_bits = payload_type.hasRuntimeBits(zcu);
4308 const has_comptime_state = payload_type.comptimeOnly(zcu);
4309 try wip_nav.abbrevCode(if (has_comptime_state)
4310 .comptime_value_field_comptime_state
4311 else if (has_runtime_bits)
4312 .comptime_value_field_runtime_bits
4313 else
4314 break :payload_field);
4315 try wip_nav.strp("value");
4316 if (has_comptime_state)
4317 try wip_nav.refValue(.fromInterned(payload_val))
4318 else
4319 try wip_nav.blockValue(.fromInterned(payload_val));
4320 },
4321 }
4322 {
4323 try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
4324 try wip_nav.strp("error");
4325 try diw.writeUleb128(err_bytes.len);
4326 try diw.writeAll(err_bytes);
4327 }
4328 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4329 },
4330 .enum_literal => |enum_literal| {
4331 try wip_nav.abbrevCode(.comptime_value);
4332 try wip_nav.refType(.enum_literal);
4333 try diw.writeUleb128(DW.FORM.strp);
4334 try wip_nav.strp(enum_literal.toSlice(ip));
4335 },
4336 .enum_tag => |enum_tag| {
4337 const int = ip.indexToKey(enum_tag.int).int;
4338 try wip_nav.abbrevCode(.comptime_value);
4339 try wip_nav.refType(.fromInterned(enum_tag.ty));
4340 try wip_nav.bigIntConstValue(.fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu));
4341 },
4342 .float => |float| {
4343 try wip_nav.abbrevCode(.comptime_value);
4344 try wip_nav.refType(.fromInterned(float.ty));
4345 switch (float.storage) {
4346 .f16 => |f16_val| {
4347 try diw.writeUleb128(DW.FORM.data2);
4348 try diw.writeInt(u16, @bitCast(f16_val), dwarf.endian);
4349 },
4350 .f32 => |f32_val| {
4351 try diw.writeUleb128(DW.FORM.data4);
4352 try diw.writeInt(u32, @bitCast(f32_val), dwarf.endian);
4353 },
4354 .f64 => |f64_val| {
4355 try diw.writeUleb128(DW.FORM.data8);
4356 try diw.writeInt(u64, @bitCast(f64_val), dwarf.endian);
4357 },
4358 .f80 => |f80_val| {
4359 try diw.writeUleb128(DW.FORM.block);
4360 try diw.writeUleb128(@divExact(80, 8));
4361 try diw.writeInt(u80, @bitCast(f80_val), dwarf.endian);
4362 },
4363 .f128 => |f128_val| {
4364 try diw.writeUleb128(DW.FORM.data16);
4365 try diw.writeInt(u128, @bitCast(f128_val), dwarf.endian);
4366 },
4367 }
4368 },
4369 .ptr => |ptr| {
4370 const Access = union(enum) {
4371 index: u64,
4372 field: InternPool.NullTerminatedString,
4373 synthetic_field: []const u8,
4374 tuple_index: u32,
4375 };
4376 var zero_bit_accesses: std.ArrayList(Access) = .empty;
4377 defer zero_bit_accesses.deinit(dwarf.gpa);
4378 location: {
4379 var base_addr = ptr.base_addr;
4380 var byte_offset = ptr.byte_offset;
4381 const base_unit, const base_entry = while (true) {
4382 const base_ptr, const access: Access = base_ptr_access: switch (base_addr) {
4383 .nav => |nav_index| break try dwarf.getNavEntry(nav_index),
4384 .comptime_alloc, .comptime_field => unreachable,
4385 .uav => |uav| {
4386 const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));
4387 if (uav_ty.classify(zcu) == .one_possible_value) {
4388 try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)
4389 .aggregate_comptime_value
4390 else
4391 .comptime_value);
4392 try wip_nav.refType(.fromInterned(ptr.ty));
4393 try diw.writeUleb128(DW.FORM.udata);
4394 try diw.writeUleb128(ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment.toByteUnits() orelse
4395 uav_ty.abiAlignment(zcu).toByteUnits().?);
4396 break :location;
4397 } else break try wip_nav.getValueEntry(.fromInterned(uav.val));
4398 },
4399 .int => {
4400 try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)
4401 .aggregate_comptime_value
4402 else
4403 .comptime_value);
4404 try wip_nav.refType(.fromInterned(ptr.ty));
4405 try diw.writeUleb128(DW.FORM.udata);
4406 try diw.writeUleb128(byte_offset);
4407 break :location;
4408 },
4409 .eu_payload => |eu_ptr| {
4410 const base_ptr = ip.indexToKey(eu_ptr).ptr;
4411 byte_offset += codegen.errUnionPayloadOffset(.fromInterned(ip.indexToKey(
4412 ip.indexToKey(base_ptr.ty).ptr_type.child,
4413 ).error_union_type.payload_type), zcu);
4414 break :base_ptr_access .{ base_ptr, .{ .synthetic_field = "value" } };
4415 },
4416 .opt_payload => |opt_ptr| .{ ip.indexToKey(opt_ptr).ptr, .{ .synthetic_field = "?" } },
4417 .field => |field| {
4418 const base_ptr = ip.indexToKey(field.base).ptr;
4419 const agg_ty: Type = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child);
4420 break :base_ptr_access .{
4421 base_ptr,
4422 if (agg_ty.isSlice(zcu)) .{ .synthetic_field = switch (field.index) {
4423 Value.slice_ptr_index => "ptr",
4424 Value.slice_len_index => "len",
4425 else => unreachable,
4426 } } else if (agg_ty.structFieldName(@intCast(field.index), zcu).unwrap()) |field_name|
4427 .{ .field = field_name }
4428 else
4429 .{ .tuple_index = @intCast(field.index) },
4430 };
4431 },
4432 .arr_elem => |arr_elem| .{
4433 ip.indexToKey(arr_elem.base).ptr,
4434 .{ .index = arr_elem.index },
4435 },
4436 };
4437 base_addr = base_ptr.base_addr;
4438 byte_offset += base_ptr.byte_offset;
4439 if (Type.fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child).hasRuntimeBits(zcu))
4440 assert(access != .index)
4441 else
4442 try zero_bit_accesses.append(dwarf.gpa, access);
4443 };
4444 try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)
4445 .aggregate_location_comptime_value
4446 else
4447 .location_comptime_value);
4448 try wip_nav.refType(.fromInterned(ptr.ty));
4449 try wip_nav.infoExprLoc(.{ .implicit_pointer = .{
4450 .unit = base_unit,
4451 .entry = base_entry,
4452 .offset = byte_offset,
4453 } });
4454 }
4455 if (zero_bit_accesses.items.len > 0) {
4456 for (zero_bit_accesses.items) |access| switch (access) {
4457 .index => |index| {
4458 try wip_nav.abbrevCode(.array_index);
4459 try diw.writeUleb128(index);
4460 },
4461 .field => |field| {
4462 try wip_nav.abbrevCode(.access);
4463 try wip_nav.strp(field.toSlice(ip));
4464 },
4465 .synthetic_field => |field| {
4466 try wip_nav.abbrevCode(.access);
4467 try wip_nav.strp(field);
4468 },
4469 .tuple_index => |index| {
4470 try wip_nav.abbrevCode(.access);
4471 var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined;
4472 const field_name = std.mem.print(&field_name_buf, "{d}", .{index}) catch unreachable;
4473 try wip_nav.strp(field_name);
4474 },
4475 };
4476 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4477 }
4478 },
4479 .slice => |slice| {
4480 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value);
4481 try wip_nav.refType(.fromInterned(slice.ty));
4482 {
4483 try wip_nav.abbrevCode(.comptime_value_field_comptime_state);
4484 try wip_nav.strp("ptr");
4485 try wip_nav.refValue(.fromInterned(slice.ptr));
4486 }
4487 {
4488 try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
4489 try wip_nav.strp("len");
4490 try wip_nav.blockValue(.fromInterned(slice.len));
4491 }
4492 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4493 },
4494 .opt => |opt| {
4495 const opt_child_type: Type = .fromInterned(ip.indexToKey(opt.ty).opt_type);
4496 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value);
4497 try wip_nav.refType(.fromInterned(opt.ty));
4498 {
4499 try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
4500 try wip_nav.strp("has_value");
4501 switch (optRepr(opt_child_type, zcu)) {
4502 .opv_null => try diw.writeUleb128(0),
4503 .unpacked => try wip_nav.blockValue(.makeBool(opt.val != .none)),
4504 .error_set, .pointer => try wip_nav.blockValue(.fromInterned(value_index)),
4505 }
4506 }
4507 if (opt.val != .none) child_field: {
4508 const has_runtime_bits = opt_child_type.hasRuntimeBits(zcu);
4509 const has_comptime_state = opt_child_type.comptimeOnly(zcu);
4510 try wip_nav.abbrevCode(if (has_comptime_state)
4511 .comptime_value_field_comptime_state
4512 else if (has_runtime_bits)
4513 .comptime_value_field_runtime_bits
4514 else
4515 break :child_field);
4516 try wip_nav.strp("?");
4517 if (has_comptime_state)
4518 try wip_nav.refValue(.fromInterned(opt.val))
4519 else
4520 try wip_nav.blockValue(.fromInterned(opt.val));
4521 }
4522 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4523 },
4524 .aggregate => |aggregate| {
4525 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value);
4526 try wip_nav.refType(.fromInterned(aggregate.ty));
4527 switch (ip.indexToKey(aggregate.ty)) {
4528 .struct_type => {
4529 const loaded_struct_type = ip.loadStructType(aggregate.ty);
4530 assert(loaded_struct_type.layout == .auto);
4531 for (0..loaded_struct_type.field_types.len) |field_index| {
4532 if (loaded_struct_type.field_is_comptime_bits.get(ip, field_index)) continue;
4533 const field_type: Type = .fromInterned(loaded_struct_type.field_types.get(ip)[field_index]);
4534 const has_runtime_bits = field_type.hasRuntimeBits(zcu);
4535 const has_comptime_state = field_type.comptimeOnly(zcu);
4536 try wip_nav.abbrevCode(if (has_comptime_state)
4537 .comptime_value_field_comptime_state
4538 else if (has_runtime_bits)
4539 .comptime_value_field_runtime_bits
4540 else
4541 continue);
4542 try wip_nav.strp(loaded_struct_type.field_names.get(ip)[field_index].toSlice(ip));
4543 const field_value: Value = .fromInterned(switch (aggregate.storage) {
4544 .bytes => unreachable,
4545 .elems => |elems| elems[field_index],
4546 .repeated_elem => |repeated_elem| repeated_elem,
4547 });
4548 if (has_comptime_state)
4549 try wip_nav.refValue(field_value)
4550 else
4551 try wip_nav.blockValue(field_value);
4552 }
4553 },
4554 .tuple_type => |tuple_type| for (0..tuple_type.types.len) |field_index| {
4555 if (tuple_type.values.get(ip)[field_index] != .none) continue;
4556 const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);
4557 const has_runtime_bits = field_type.hasRuntimeBits(zcu);
4558 const has_comptime_state = field_type.comptimeOnly(zcu);
4559 try wip_nav.abbrevCode(if (has_comptime_state)
4560 .comptime_value_field_comptime_state
4561 else if (has_runtime_bits)
4562 .comptime_value_field_runtime_bits
4563 else
4564 continue);
4565 {
4566 var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined;
4567 const field_name = std.mem.print(&field_name_buf, "{d}", .{field_index}) catch unreachable;
4568 try wip_nav.strp(field_name);
4569 }
4570 const field_value: Value = .fromInterned(switch (aggregate.storage) {
4571 .bytes => unreachable,
4572 .elems => |elems| elems[field_index],
4573 .repeated_elem => |repeated_elem| repeated_elem,
4574 });
4575 if (has_comptime_state)
4576 try wip_nav.refValue(field_value)
4577 else
4578 try wip_nav.blockValue(field_value);
4579 },
4580 inline .array_type, .vector_type => |sequence_type| {
4581 const child_type: Type = .fromInterned(sequence_type.child);
4582 const has_runtime_bits = child_type.hasRuntimeBits(zcu);
4583 const has_comptime_state = child_type.comptimeOnly(zcu);
4584 for (switch (aggregate.storage) {
4585 .bytes => unreachable,
4586 .elems => |elems| elems,
4587 .repeated_elem => |*repeated_elem| repeated_elem[0..1],
4588 }) |elem| {
4589 try wip_nav.abbrevCode(if (has_comptime_state)
4590 .comptime_value_elem_comptime_state
4591 else if (has_runtime_bits)
4592 .comptime_value_elem_runtime_bits
4593 else
4594 break);
4595 if (has_comptime_state)
4596 try wip_nav.refValue(.fromInterned(elem))
4597 else
4598 try wip_nav.blockValue(.fromInterned(elem));
4599 }
4600 },
4601 else => unreachable,
4602 }
4603 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4604 },
4605 .un => |un| {
4606 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value);
4607 try wip_nav.refType(.fromInterned(un.ty));
4608 {
4609 const loaded_union_type = ip.loadUnionType(un.ty);
4610 assert(loaded_union_type.layout == .auto);
4611 const field_index = zcu.unionTagFieldIndex(loaded_union_type, Value.fromInterned(un.tag)).?;
4612 const field_ty: Type = .fromInterned(loaded_union_type.field_types.get(ip)[field_index]);
4613 const field_name = ip.loadEnumType(loaded_union_type.enum_tag_type).field_names.get(ip)[field_index];
4614 const has_runtime_bits = field_ty.hasRuntimeBits(zcu);
4615 const has_comptime_state = field_ty.comptimeOnly(zcu);
4616 try wip_nav.abbrevCode(if (has_comptime_state)
4617 .comptime_value_field_comptime_state
4618 else if (has_runtime_bits)
4619 .comptime_value_field_runtime_bits
4620 else
4621 .access);
4622 try wip_nav.strp(field_name.toSlice(ip));
4623 if (has_comptime_state)
4624 try wip_nav.refValue(.fromInterned(un.val))
4625 else if (has_runtime_bits)
4626 try wip_nav.blockValue(.fromInterned(un.val));
4627 }
4628 try diw.writeUleb128(@backingInt(AbbrevCode.null));
4629 },
4630
4631 .memoized_call => unreachable, // not a value
4632 }
4633 try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written());
4634 try dwarf.debug_loclists.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_loclists.written());
4635}
4636
4637fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { unpacked, opv_null, error_set, pointer } {
4638 if (opt_child_type.isNoReturn(zcu)) return .opv_null;
4639 return switch (opt_child_type.toIntern()) {
4640 .anyerror_type => .error_set,
4641 else => switch (zcu.intern_pool.indexToKey(opt_child_type.toIntern())) {
4642 else => .unpacked,
4643 .error_set_type, .inferred_error_set_type => .error_set,
4644 .ptr_type => |ptr_type| if (ptr_type.flags.is_allowzero) .unpacked else .pointer,
4645 },
4646 };
4647}
4648
4649pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedInst.Index, line: u32) UpdateError!void {
4650 const comp = dwarf.bin_file.comp;
4651 const io = comp.io;
4652 const ip = &zcu.intern_pool;
4653
4654 const inst_info = zir_index.resolveFull(ip).?;
4655 if (inst_info.inst == .main_struct_inst) return;
4656 const file = zcu.fileByIndex(inst_info.file);
4657
4658 var line_buf: [4]u8 = undefined;
4659 std.mem.writeInt(u32, &line_buf, line + 1, dwarf.endian);
4660
4661 const unit = dwarf.debug_info.section.getUnit(dwarf.getUnitIfExists(file.mod.?) orelse return);
4662 const entry = unit.getEntry(dwarf.decls.get(zir_index) orelse return);
4663 try dwarf.getFile().?.writePositionalAll(io, &line_buf, dwarf.debug_info.section.off(dwarf) + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf));
4664}
4665
4666pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void {
4667 _ = dwarf;
4668 _ = nav_index;
4669}
4670
4671fn refAbbrevCode(
4672 dwarf: *Dwarf,
4673 abbrev_code: AbbrevCode,
4674) (UpdateError || Writer.Error)!@typeInfo(AbbrevCode).@"enum".tag_type {
4675 assert(abbrev_code != .null);
4676 const entry: Entry.Index = @fromBackingInt(@intCast(@backingInt(abbrev_code)));
4677 if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @backingInt(abbrev_code);
4678 var debug_abbrev_aw: Writer.Allocating = .init(dwarf.gpa);
4679 defer debug_abbrev_aw.deinit();
4680 const daw = &debug_abbrev_aw.writer;
4681 const abbrev = AbbrevCode.abbrevs.get(abbrev_code);
4682 try daw.writeUleb128(@backingInt(abbrev_code));
4683 try daw.writeUleb128(@backingInt(abbrev.tag));
4684 try daw.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no);
4685 for (abbrev.attrs) |*attr| inline for (attr) |info| try daw.writeUleb128(@backingInt(info));
4686 for (0..2) |_| try daw.writeUleb128(0);
4687 try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, entry, dwarf, debug_abbrev_aw.written());
4688 return @backingInt(abbrev_code);
4689}
4690
4691pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) UpdateError!void {
4692 return dwarf.flushWriterError(pt) catch |err| switch (err) {
4693 error.WriteFailed => error.OutOfMemory,
4694 else => |e| e,
4695 };
4696}
4697fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Error)!void {
4698 const zcu = pt.zcu;
4699 const ip = &zcu.intern_pool;
4700 const comp = dwarf.bin_file.comp;
4701 const io = comp.io;
4702
4703 // Update `anyerror` based on the finished global error set.
4704 {
4705 const index = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), .anyerror_type);
4706 const unit, const entry = dwarf.values.items[@backingInt(index)];
4707 var wip_nav: WipNav = .{
4708 .dwarf = dwarf,
4709 .pt = pt,
4710 .unit = unit,
4711 .entry = entry,
4712 .any_children = false,
4713 .func = .none,
4714 .func_sym_index = undefined,
4715 .func_high_pc = undefined,
4716 .blocks = undefined,
4717 .cfi = undefined,
4718 .debug_frame = .init(dwarf.gpa),
4719 .debug_info = .init(dwarf.gpa),
4720 .debug_line = .init(dwarf.gpa),
4721 .debug_loclists = .init(dwarf.gpa),
4722 };
4723 defer wip_nav.deinit();
4724 const diw = &wip_nav.debug_info.writer;
4725 const global_error_set_names = ip.global_error_set.getNamesFromMainThread();
4726 try wip_nav.abbrevCode(if (global_error_set_names.len == 0) .generated_empty_enum_type else .generated_enum_type);
4727 try wip_nav.strp("anyerror");
4728 try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
4729 .signedness = .unsigned,
4730 .bits = zcu.errorSetBits(),
4731 } })));
4732 for (global_error_set_names, 1..) |name, value| {
4733 try wip_nav.abbrevCode(.enum_field);
4734 try diw.writeUleb128(DW.FORM.udata);
4735 try diw.writeUleb128(value);
4736 try wip_nav.strp(name.toSlice(ip));
4737 }
4738 if (global_error_set_names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null));
4739 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
4740 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser());
4741 }
4742
4743 for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {
4744 const root_dir_path = try mod.root.toAbsolute(&zcu.comp.dirs, dwarf.gpa);
4745 defer dwarf.gpa.free(root_dir_path);
4746 mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);
4747 }
4748
4749 var header_aw: Writer.Allocating = .init(dwarf.gpa);
4750 defer header_aw.deinit();
4751 const hw = &header_aw.writer;
4752 if (dwarf.debug_aranges.section.dirty) {
4753 for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| {
4754 const unit: Unit.Index = @fromBackingInt(@intCast(unit_index));
4755 unit_ptr.clear();
4756 try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 1);
4757 header_aw.clearRetainingCapacity();
4758 try header_aw.ensureTotalCapacity(unit_ptr.header_len);
4759 const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
4760 dwarf.debug_aranges.section.getUnit(next_unit).off
4761 else
4762 dwarf.debug_aranges.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
4763 switch (dwarf.format) {
4764 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
4765 .@"64" => {
4766 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
4767 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
4768 },
4769 }
4770 hw.writeInt(u16, 2, dwarf.endian) catch unreachable;
4771 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4772 .source_off = @intCast(hw.end),
4773 .target_sec = .debug_info,
4774 .target_unit = unit,
4775 });
4776 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4777 hw.writeByte(@backingInt(dwarf.address_size)) catch unreachable;
4778 hw.writeByte(0) catch unreachable;
4779 hw.splatByteAll(0, unit_ptr.header_len - hw.end) catch unreachable;
4780 try unit_ptr.replaceHeader(&dwarf.debug_aranges.section, dwarf, header_aw.written());
4781 try unit_ptr.writeTrailer(&dwarf.debug_aranges.section, dwarf);
4782 }
4783 dwarf.debug_aranges.section.dirty = false;
4784 }
4785 if (dwarf.debug_frame.section.dirty) {
4786 const target = &dwarf.bin_file.comp.root_mod.resolved_target.result;
4787 switch (dwarf.debug_frame.header.format) {
4788 .none => {},
4789 .debug_frame => unreachable,
4790 .eh_frame => switch (target.cpu.arch) {
4791 .x86_64 => {
4792 dev.checkAny(&.{ .llvm_backend, .x86_64_backend });
4793 const Register = @import("../codegen/x86_64/bits.zig").Register;
4794 for (dwarf.debug_frame.section.units.items) |*unit| {
4795 header_aw.clearRetainingCapacity();
4796 try header_aw.ensureTotalCapacity(unit.header_len);
4797 const unit_len = unit.header_len - dwarf.unitLengthBytes();
4798 switch (dwarf.format) {
4799 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
4800 .@"64" => {
4801 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
4802 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
4803 },
4804 }
4805 hw.splatByteAll(0, 4) catch unreachable;
4806 hw.writeByte(1) catch unreachable;
4807 hw.writeAll("zR\x00") catch unreachable;
4808 hw.writeUleb128(dwarf.debug_frame.header.code_alignment_factor) catch unreachable;
4809 hw.writeSleb128(dwarf.debug_frame.header.data_alignment_factor) catch unreachable;
4810 hw.writeUleb128(dwarf.debug_frame.header.return_address_register) catch unreachable;
4811 hw.writeUleb128(1) catch unreachable;
4812 hw.writeByte(@bitCast(@as(DW.EH.PE, .{ .type = .sdata4, .rel = .pcrel }))) catch unreachable;
4813 hw.writeByte(DW.CFA.def_cfa_sf) catch unreachable;
4814 hw.writeUleb128(Register.rsp.dwarfNum()) catch unreachable;
4815 hw.writeSleb128(-1) catch unreachable;
4816 hw.writeByte(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum()) catch unreachable;
4817 hw.writeUleb128(1) catch unreachable;
4818 hw.splatByteAll(DW.CFA.nop, unit.header_len - hw.end) catch unreachable;
4819 try unit.replaceHeader(&dwarf.debug_frame.section, dwarf, header_aw.written());
4820 try unit.writeTrailer(&dwarf.debug_frame.section, dwarf);
4821 }
4822 },
4823 else => unreachable,
4824 },
4825 }
4826 dwarf.debug_frame.section.dirty = false;
4827 }
4828 if (dwarf.debug_info.section.dirty) {
4829 for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| {
4830 const unit: Unit.Index = @fromBackingInt(@intCast(unit_index));
4831 unit_ptr.clear();
4832 try unit_ptr.cross_unit_relocs.ensureTotalCapacity(dwarf.gpa, 1);
4833 try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 7);
4834 header_aw.clearRetainingCapacity();
4835 try header_aw.ensureTotalCapacity(unit_ptr.header_len);
4836 const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
4837 dwarf.debug_info.section.getUnit(next_unit).off
4838 else
4839 dwarf.debug_info.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
4840 switch (dwarf.format) {
4841 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
4842 .@"64" => {
4843 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
4844 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
4845 },
4846 }
4847 hw.writeInt(u16, 5, dwarf.endian) catch unreachable;
4848 hw.writeByte(DW.UT.compile) catch unreachable;
4849 hw.writeByte(@backingInt(dwarf.address_size)) catch unreachable;
4850 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4851 .source_off = @intCast(hw.end),
4852 .target_sec = .debug_abbrev,
4853 .target_unit = DebugAbbrev.unit,
4854 });
4855 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4856 const compile_unit_off: u32 = @intCast(hw.end);
4857 hw.writeUleb128(try dwarf.refAbbrevCode(.compile_unit)) catch unreachable;
4858 hw.writeByte(DW.LANG.Zig) catch unreachable;
4859 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4860 .source_off = @intCast(hw.end),
4861 .target_sec = .debug_line_str,
4862 .target_unit = StringSection.unit,
4863 .target_entry = (try dwarf.debug_line_str.addString(dwarf, "zig " ++ @import("build_options").version)).toOptional(),
4864 });
4865 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4866 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4867 .source_off = @intCast(hw.end),
4868 .target_sec = .debug_line_str,
4869 .target_unit = StringSection.unit,
4870 .target_entry = mod_info.root_dir_path.toOptional(),
4871 });
4872 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4873 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4874 .source_off = @intCast(hw.end),
4875 .target_sec = .debug_line_str,
4876 .target_unit = StringSection.unit,
4877 .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod.root_src_path)).toOptional(),
4878 });
4879 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4880 unit_ptr.cross_unit_relocs.appendAssumeCapacity(.{
4881 .source_off = @intCast(hw.end),
4882 .target_unit = .main,
4883 .target_off = compile_unit_off,
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_line,
4889 .target_unit = unit,
4890 });
4891 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4892 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4893 .source_off = @intCast(hw.end),
4894 .target_sec = .debug_rnglists,
4895 .target_unit = unit,
4896 .target_off = DebugRngLists.baseOffset(dwarf),
4897 });
4898 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4899 hw.writeUleb128(0) catch unreachable;
4900 hw.writeUleb128(try dwarf.refAbbrevCode(.module)) catch unreachable;
4901 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
4902 .source_off = @intCast(hw.end),
4903 .target_sec = .debug_str,
4904 .target_unit = StringSection.unit,
4905 .target_entry = (try dwarf.debug_str.addString(dwarf, mod.fully_qualified_name)).toOptional(),
4906 });
4907 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4908 hw.writeUleb128(0) catch unreachable;
4909 try unit_ptr.replaceHeader(&dwarf.debug_info.section, dwarf, header_aw.written());
4910 try unit_ptr.writeTrailer(&dwarf.debug_info.section, dwarf);
4911 }
4912 dwarf.debug_info.section.dirty = false;
4913 }
4914 if (dwarf.debug_abbrev.section.dirty) {
4915 assert(!dwarf.debug_info.section.dirty);
4916 try dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).writeTrailer(&dwarf.debug_abbrev.section, dwarf);
4917 dwarf.debug_abbrev.section.dirty = false;
4918 }
4919 if (dwarf.debug_str.section.dirty) {
4920 const contents = dwarf.debug_str.contents.items;
4921 try dwarf.debug_str.section.resize(dwarf, contents.len);
4922 try dwarf.getFile().?.writePositionalAll(io, contents, dwarf.debug_str.section.off(dwarf));
4923 dwarf.debug_str.section.dirty = false;
4924 }
4925 if (dwarf.debug_line.section.dirty) {
4926 for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| try unit.resizeHeader(
4927 &dwarf.debug_line.section,
4928 dwarf,
4929 DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count())),
4930 );
4931 for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| {
4932 unit.clear();
4933 try unit.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, mod_info.dirs.count() + 2 * (mod_info.files.count()));
4934 header_aw.clearRetainingCapacity();
4935 try header_aw.ensureTotalCapacity(unit.header_len);
4936 const unit_len = (if (unit.next.unwrap()) |next_unit|
4937 dwarf.debug_line.section.getUnit(next_unit).off
4938 else
4939 dwarf.debug_line.section.len) - unit.off - dwarf.unitLengthBytes();
4940 switch (dwarf.format) {
4941 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
4942 .@"64" => {
4943 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
4944 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
4945 },
4946 }
4947 hw.writeInt(u16, 5, dwarf.endian) catch unreachable;
4948 hw.writeByte(@backingInt(dwarf.address_size)) catch unreachable;
4949 hw.writeByte(0) catch unreachable;
4950 switch (dwarf.format) {
4951 .@"32" => hw.writeInt(u32, @intCast(unit.header_len - hw.end - 4), dwarf.endian) catch unreachable,
4952 .@"64" => hw.writeInt(u64, @intCast(unit.header_len - hw.end - 8), dwarf.endian) catch unreachable,
4953 }
4954 const StandardOpcode = DeclValEnum(DW.LNS);
4955 hw.writeAll(&.{
4956 dwarf.debug_line.header.minimum_instruction_length,
4957 dwarf.debug_line.header.maximum_operations_per_instruction,
4958 @intFromBool(dwarf.debug_line.header.default_is_stmt),
4959 @bitCast(dwarf.debug_line.header.line_base),
4960 dwarf.debug_line.header.line_range,
4961 dwarf.debug_line.header.opcode_base,
4962 }) catch unreachable;
4963 hw.writeAll(std.enums.EnumArray(StandardOpcode, u8).init(.{
4964 .extended_op = undefined,
4965 .copy = 0,
4966 .advance_pc = 1,
4967 .advance_line = 1,
4968 .set_file = 1,
4969 .set_column = 1,
4970 .negate_stmt = 0,
4971 .set_basic_block = 0,
4972 .const_add_pc = 0,
4973 .fixed_advance_pc = 1,
4974 .set_prologue_end = 0,
4975 .set_epilogue_begin = 0,
4976 .set_isa = 1,
4977 }).values[1..dwarf.debug_line.header.opcode_base]) catch unreachable;
4978 hw.writeByte(1) catch unreachable;
4979 hw.writeUleb128(DW.LNCT.path) catch unreachable;
4980 hw.writeUleb128(DW.FORM.line_strp) catch unreachable;
4981 hw.writeUleb128(mod_info.dirs.count()) catch unreachable;
4982 for (mod_info.dirs.keys()) |dir_unit| {
4983 unit.cross_section_relocs.appendAssumeCapacity(.{
4984 .source_off = @intCast(hw.end),
4985 .target_sec = .debug_line_str,
4986 .target_unit = StringSection.unit,
4987 .target_entry = dwarf.getModInfo(dir_unit).root_dir_path.toOptional(),
4988 });
4989 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
4990 }
4991 const dir_index_info = DebugLine.dirIndexInfo(@intCast(mod_info.dirs.count()));
4992 hw.writeByte(3) catch unreachable;
4993 hw.writeUleb128(DW.LNCT.path) catch unreachable;
4994 hw.writeUleb128(DW.FORM.line_strp) catch unreachable;
4995 hw.writeUleb128(DW.LNCT.directory_index) catch unreachable;
4996 hw.writeUleb128(@backingInt(dir_index_info.form)) catch unreachable;
4997 hw.writeUleb128(DW.LNCT.LLVM_source) catch unreachable;
4998 hw.writeUleb128(DW.FORM.line_strp) catch unreachable;
4999 hw.writeUleb128(mod_info.files.count()) catch unreachable;
5000 for (mod_info.files.keys()) |file_index| {
5001 const file = zcu.fileByIndex(file_index);
5002 unit.cross_section_relocs.appendAssumeCapacity(.{
5003 .source_off = @intCast(hw.end),
5004 .target_sec = .debug_line_str,
5005 .target_unit = StringSection.unit,
5006 .target_entry = (try dwarf.debug_line_str.addString(dwarf, file.sub_file_path)).toOptional(),
5007 });
5008 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
5009 const dir_index = mod_info.dirs.getIndex(dwarf.getUnitIfExists(file.mod.?).?) orelse 0;
5010 switch (dir_index_info.bytes) {
5011 else => unreachable,
5012 1 => hw.writeByte(@intCast(dir_index)) catch unreachable,
5013 2 => hw.writeInt(u16, @intCast(dir_index), dwarf.endian) catch unreachable,
5014 }
5015 unit.cross_section_relocs.appendAssumeCapacity(.{
5016 .source_off = @intCast(hw.end),
5017 .target_sec = .debug_line_str,
5018 .target_unit = StringSection.unit,
5019 .target_entry = (try dwarf.debug_line_str.addString(
5020 dwarf,
5021 if (file.is_builtin) file.source.? else "",
5022 )).toOptional(),
5023 });
5024 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable;
5025 }
5026 try unit.replaceHeader(&dwarf.debug_line.section, dwarf, header_aw.written());
5027 try unit.writeTrailer(&dwarf.debug_line.section, dwarf);
5028 }
5029 dwarf.debug_line.section.dirty = false;
5030 }
5031 if (dwarf.debug_line_str.section.dirty) {
5032 const contents = dwarf.debug_line_str.contents.items;
5033 try dwarf.debug_line_str.section.resize(dwarf, contents.len);
5034 try dwarf.getFile().?.writePositionalAll(io, contents, dwarf.debug_line_str.section.off(dwarf));
5035 dwarf.debug_line_str.section.dirty = false;
5036 }
5037 if (dwarf.debug_loclists.section.dirty) {
5038 dwarf.debug_loclists.section.dirty = false;
5039 }
5040 if (dwarf.debug_rnglists.section.dirty) {
5041 for (dwarf.debug_rnglists.section.units.items) |*unit| {
5042 header_aw.clearRetainingCapacity();
5043 try header_aw.ensureTotalCapacity(unit.header_len);
5044 const unit_len = (if (unit.next.unwrap()) |next_unit|
5045 dwarf.debug_rnglists.section.getUnit(next_unit).off
5046 else
5047 dwarf.debug_rnglists.section.len) - unit.off - dwarf.unitLengthBytes();
5048 switch (dwarf.format) {
5049 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable,
5050 .@"64" => {
5051 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable;
5052 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable;
5053 },
5054 }
5055 hw.writeInt(u16, 5, dwarf.endian) catch unreachable;
5056 hw.writeByte(@backingInt(dwarf.address_size)) catch unreachable;
5057 hw.writeByte(0) catch unreachable;
5058 hw.writeInt(u32, 1, dwarf.endian) catch unreachable;
5059 switch (dwarf.format) {
5060 .@"32" => hw.writeInt(u32, dwarf.sectionOffsetBytes() * 1, dwarf.endian) catch unreachable,
5061 .@"64" => hw.writeInt(u64, dwarf.sectionOffsetBytes() * 1, dwarf.endian) catch unreachable,
5062 }
5063 try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header_aw.written());
5064 try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf);
5065 }
5066 dwarf.debug_rnglists.section.dirty = false;
5067 }
5068 assert(!dwarf.debug_abbrev.section.dirty);
5069 assert(!dwarf.debug_aranges.section.dirty);
5070 assert(!dwarf.debug_frame.section.dirty);
5071 assert(!dwarf.debug_info.section.dirty);
5072 assert(!dwarf.debug_line.section.dirty);
5073 assert(!dwarf.debug_line_str.section.dirty);
5074 assert(!dwarf.debug_loclists.section.dirty);
5075 assert(!dwarf.debug_rnglists.section.dirty);
5076 assert(!dwarf.debug_str.section.dirty);
5077}
5078
5079pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void {
5080 for ([_]*Section{
5081 &dwarf.debug_abbrev.section,
5082 &dwarf.debug_aranges.section,
5083 &dwarf.debug_frame.section,
5084 &dwarf.debug_info.section,
5085 &dwarf.debug_line.section,
5086 &dwarf.debug_line_str.section,
5087 &dwarf.debug_loclists.section,
5088 &dwarf.debug_rnglists.section,
5089 &dwarf.debug_str.section,
5090 }) |sec| try sec.resolveRelocs(dwarf);
5091}
5092
5093fn DeclValEnum(comptime T: type) type {
5094 const decl_names = @typeInfo(T).@"struct".decl_names;
5095 @setEvalBranchQuota(10 * decl_names.len);
5096 var field_names: [decl_names.len][]const u8 = undefined;
5097 var fields_len = 0;
5098 var min_value: ?comptime_int = null;
5099 var max_value: ?comptime_int = null;
5100 for (decl_names) |decl_name| {
5101 if (std.mem.startsWith(u8, decl_name, "HP_") or std.mem.endsWith(u8, decl_name, "_user")) continue;
5102 const value = @field(T, decl_name);
5103 field_names[fields_len] = decl_name;
5104 fields_len += 1;
5105 if (min_value == null or min_value.? > value) min_value = value;
5106 if (max_value == null or max_value.? < value) max_value = value;
5107 }
5108 if (fields_len == 0) return enum {};
5109 const TagInt = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0);
5110 var field_vals: [fields_len]TagInt = undefined;
5111 for (field_names[0..fields_len], &field_vals) |name, *val| val.* = @field(T, name);
5112 return @Enum(TagInt, .exhaustive, field_names[0..fields_len], &field_vals);
5113}
5114
5115const AbbrevCode = enum {
5116 null,
5117 // padding codes must be one byte uleb128 values to function
5118 pad_1,
5119 pad_n,
5120 // decl, generic decl, and instance codes are assumed to all have the same uleb128 length
5121 decl_alias,
5122 decl_empty_enum,
5123 decl_enum,
5124 decl_namespace_struct,
5125 decl_struct,
5126 decl_packed_struct,
5127 decl_union,
5128 decl_packed_union,
5129 decl_var,
5130 decl_const,
5131 decl_const_runtime_bits,
5132 decl_const_comptime_state,
5133 decl_const_runtime_bits_comptime_state,
5134 decl_nullary_func,
5135 decl_func,
5136 decl_nullary_func_generic,
5137 decl_func_generic,
5138 decl_extern_nullary_func,
5139 decl_extern_func,
5140 decl_specification_var,
5141 decl_specification_const,
5142 decl_specification_func,
5143 decl_instance_alias,
5144 decl_instance_empty_enum,
5145 decl_instance_enum,
5146 decl_instance_namespace_struct,
5147 decl_instance_struct,
5148 decl_instance_packed_struct,
5149 decl_instance_union,
5150 decl_instance_packed_union,
5151 decl_instance_var,
5152 decl_instance_const,
5153 decl_instance_const_runtime_bits,
5154 decl_instance_const_comptime_state,
5155 decl_instance_const_runtime_bits_comptime_state,
5156 decl_instance_nullary_func,
5157 decl_instance_func,
5158 decl_instance_nullary_func_generic,
5159 decl_instance_func_generic,
5160 decl_instance_extern_nullary_func,
5161 decl_instance_extern_func,
5162 // the rest are unrestricted other than empty variants must not be longer
5163 // than the non-empty variant, and so should appear first
5164 compile_unit,
5165 module,
5166 empty_file,
5167 file,
5168 access,
5169 enum_field,
5170 generated_field,
5171 field,
5172 field_default_runtime_bits,
5173 field_default_comptime_state,
5174 field_comptime,
5175 field_comptime_runtime_bits,
5176 field_comptime_comptime_state,
5177 packed_field,
5178 tagged_union,
5179 tagged_union_field,
5180 tagged_union_default_field,
5181 void_type,
5182 numeric_type,
5183 inferred_error_set_type,
5184 ptr_type,
5185 ptr_sentinel_type,
5186 ptr_aligned_type,
5187 ptr_aligned_sentinel_type,
5188 is_const,
5189 is_volatile,
5190 array_type,
5191 array_sentinel_type,
5192 vector_type,
5193 array_index,
5194 array_len,
5195 nullary_func_type,
5196 func_type,
5197 func_type_param,
5198 is_var_args,
5199 generated_empty_enum_type,
5200 generated_enum_type,
5201 generated_empty_struct_type,
5202 generated_struct_type,
5203 generated_union_type,
5204 empty_enum_type,
5205 enum_type,
5206 empty_struct_type,
5207 struct_type,
5208 empty_packed_struct_type,
5209 packed_struct_type,
5210 empty_union_type,
5211 union_type,
5212 empty_packed_union_type,
5213 packed_union_type,
5214 builtin_extern_nullary_func,
5215 builtin_extern_func,
5216 builtin_extern_var,
5217 empty_block,
5218 block,
5219 empty_inlined_func,
5220 inlined_func,
5221 arg,
5222 unnamed_arg,
5223 comptime_arg,
5224 unnamed_comptime_arg,
5225 comptime_arg_runtime_bits,
5226 unnamed_comptime_arg_runtime_bits,
5227 comptime_arg_comptime_state,
5228 unnamed_comptime_arg_comptime_state,
5229 comptime_arg_runtime_bits_comptime_state,
5230 unnamed_comptime_arg_runtime_bits_comptime_state,
5231 extern_param,
5232 local_var,
5233 local_const,
5234 local_const_runtime_bits,
5235 local_const_comptime_state,
5236 local_const_runtime_bits_comptime_state,
5237 undefined_comptime_value,
5238 comptime_value,
5239 location_comptime_value,
5240 aggregate_undefined_comptime_value,
5241 aggregate_comptime_value,
5242 aggregate_location_comptime_value,
5243 comptime_value_field_runtime_bits,
5244 comptime_value_field_comptime_state,
5245 comptime_value_elem_runtime_bits,
5246 comptime_value_elem_comptime_state,
5247
5248 const decl_bytes = uleb128Bytes(@backingInt(AbbrevCode.decl_instance_extern_func));
5249 comptime {
5250 assert(uleb128Bytes(@backingInt(AbbrevCode.pad_1)) == 1);
5251 assert(uleb128Bytes(@backingInt(AbbrevCode.pad_n)) == 1);
5252 assert(uleb128Bytes(@backingInt(AbbrevCode.decl_alias)) == decl_bytes);
5253 }
5254
5255 const Attr = struct {
5256 DeclValEnum(DW.AT),
5257 DeclValEnum(DW.FORM),
5258 };
5259 const decl_abbrev_common_attrs = &[_]Attr{
5260 .{ .ZIG_parent, .ref_addr },
5261 .{ .decl_line, .data4 },
5262 .{ .decl_column, .udata },
5263 .{ .accessibility, .data1 },
5264 .{ .name, .strp },
5265 };
5266 const decl_specification_abbrev_common_attrs = decl_abbrev_common_attrs ++ &[_]Attr{
5267 .{ .declaration, .flag_present },
5268 };
5269 const decl_instance_abbrev_common_attrs = &[_]Attr{
5270 .{ .ZIG_parent, .ref_addr },
5271 .{ .abstract_origin, .ref_addr },
5272 };
5273 const abbrevs = std.EnumArray(AbbrevCode, struct {
5274 tag: DeclValEnum(DW.TAG),
5275 children: bool = false,
5276 attrs: []const Attr = &.{},
5277 }).init(.{
5278 .pad_1 = .{
5279 .tag = .ZIG_padding,
5280 },
5281 .pad_n = .{
5282 .tag = .ZIG_padding,
5283 .attrs = &.{
5284 .{ .ZIG_padding, .block },
5285 },
5286 },
5287 .decl_alias = .{
5288 .tag = .imported_declaration,
5289 .attrs = decl_abbrev_common_attrs ++ .{
5290 .{ .import, .ref_addr },
5291 },
5292 },
5293 .decl_empty_enum = .{
5294 .tag = .enumeration_type,
5295 .attrs = decl_abbrev_common_attrs ++ .{
5296 .{ .type, .ref_addr },
5297 },
5298 },
5299 .decl_enum = .{
5300 .tag = .enumeration_type,
5301 .children = true,
5302 .attrs = decl_abbrev_common_attrs ++ .{
5303 .{ .type, .ref_addr },
5304 },
5305 },
5306 .decl_namespace_struct = .{
5307 .tag = .structure_type,
5308 .attrs = decl_abbrev_common_attrs ++ .{
5309 .{ .declaration, .flag },
5310 },
5311 },
5312 .decl_struct = .{
5313 .tag = .structure_type,
5314 .children = true,
5315 .attrs = decl_abbrev_common_attrs ++ .{
5316 .{ .byte_size, .udata },
5317 .{ .alignment, .udata },
5318 },
5319 },
5320 .decl_packed_struct = .{
5321 .tag = .structure_type,
5322 .children = true,
5323 .attrs = decl_abbrev_common_attrs ++ .{
5324 .{ .type, .ref_addr },
5325 },
5326 },
5327 .decl_union = .{
5328 .tag = .union_type,
5329 .children = true,
5330 .attrs = decl_abbrev_common_attrs ++ .{
5331 .{ .byte_size, .udata },
5332 .{ .alignment, .udata },
5333 },
5334 },
5335 .decl_packed_union = .{
5336 .tag = .union_type,
5337 .children = true,
5338 .attrs = decl_abbrev_common_attrs ++ .{
5339 .{ .type, .ref_addr },
5340 },
5341 },
5342 .decl_var = .{
5343 .tag = .variable,
5344 .attrs = decl_abbrev_common_attrs ++ .{
5345 .{ .linkage_name, .strp },
5346 .{ .type, .ref_addr },
5347 .{ .location, .exprloc },
5348 .{ .alignment, .udata },
5349 .{ .external, .flag },
5350 },
5351 },
5352 .decl_const = .{
5353 .tag = .constant,
5354 .attrs = decl_abbrev_common_attrs ++ .{
5355 .{ .linkage_name, .strp },
5356 .{ .type, .ref_addr },
5357 .{ .alignment, .udata },
5358 .{ .external, .flag },
5359 },
5360 },
5361 .decl_const_runtime_bits = .{
5362 .tag = .constant,
5363 .attrs = decl_abbrev_common_attrs ++ .{
5364 .{ .linkage_name, .strp },
5365 .{ .type, .ref_addr },
5366 .{ .alignment, .udata },
5367 .{ .external, .flag },
5368 .{ .const_value, .block },
5369 },
5370 },
5371 .decl_const_comptime_state = .{
5372 .tag = .constant,
5373 .attrs = decl_abbrev_common_attrs ++ .{
5374 .{ .linkage_name, .strp },
5375 .{ .type, .ref_addr },
5376 .{ .alignment, .udata },
5377 .{ .external, .flag },
5378 .{ .ZIG_comptime_value, .ref_addr },
5379 },
5380 },
5381 .decl_const_runtime_bits_comptime_state = .{
5382 .tag = .constant,
5383 .attrs = decl_abbrev_common_attrs ++ .{
5384 .{ .linkage_name, .strp },
5385 .{ .type, .ref_addr },
5386 .{ .alignment, .udata },
5387 .{ .external, .flag },
5388 .{ .const_value, .block },
5389 .{ .ZIG_comptime_value, .ref_addr },
5390 },
5391 },
5392 .decl_nullary_func = .{
5393 .tag = .subprogram,
5394 .attrs = decl_abbrev_common_attrs ++ .{
5395 .{ .linkage_name, .strp },
5396 .{ .type, .ref_addr },
5397 .{ .low_pc, .addr },
5398 .{ .high_pc, .data4 },
5399 .{ .alignment, .udata },
5400 .{ .external, .flag },
5401 .{ .noreturn, .flag },
5402 },
5403 },
5404 .decl_func = .{
5405 .tag = .subprogram,
5406 .children = true,
5407 .attrs = decl_abbrev_common_attrs ++ .{
5408 .{ .linkage_name, .strp },
5409 .{ .type, .ref_addr },
5410 .{ .low_pc, .addr },
5411 .{ .high_pc, .data4 },
5412 .{ .alignment, .udata },
5413 .{ .external, .flag },
5414 .{ .noreturn, .flag },
5415 },
5416 },
5417 .decl_nullary_func_generic = .{
5418 .tag = .subprogram,
5419 .attrs = decl_abbrev_common_attrs ++ .{
5420 .{ .type, .ref_addr },
5421 },
5422 },
5423 .decl_func_generic = .{
5424 .tag = .subprogram,
5425 .children = true,
5426 .attrs = decl_abbrev_common_attrs ++ .{
5427 .{ .type, .ref_addr },
5428 },
5429 },
5430 .decl_extern_nullary_func = .{
5431 .tag = .subprogram,
5432 .attrs = decl_abbrev_common_attrs ++ .{
5433 .{ .linkage_name, .strp },
5434 .{ .type, .ref_addr },
5435 .{ .low_pc, .addr },
5436 .{ .external, .flag_present },
5437 .{ .noreturn, .flag },
5438 },
5439 },
5440 .decl_extern_func = .{
5441 .tag = .subprogram,
5442 .children = true,
5443 .attrs = decl_abbrev_common_attrs ++ .{
5444 .{ .linkage_name, .strp },
5445 .{ .type, .ref_addr },
5446 .{ .low_pc, .addr },
5447 .{ .external, .flag_present },
5448 .{ .noreturn, .flag },
5449 },
5450 },
5451 .decl_specification_var = .{
5452 .tag = .variable,
5453 .attrs = decl_specification_abbrev_common_attrs,
5454 },
5455 .decl_specification_const = .{
5456 .tag = .constant,
5457 .attrs = decl_specification_abbrev_common_attrs,
5458 },
5459 .decl_specification_func = .{
5460 .tag = .subprogram,
5461 .attrs = decl_specification_abbrev_common_attrs,
5462 },
5463 .decl_instance_alias = .{
5464 .tag = .imported_declaration,
5465 .attrs = decl_instance_abbrev_common_attrs ++ .{
5466 .{ .import, .ref_addr },
5467 },
5468 },
5469 .decl_instance_empty_enum = .{
5470 .tag = .enumeration_type,
5471 .attrs = decl_instance_abbrev_common_attrs ++ .{
5472 .{ .type, .ref_addr },
5473 },
5474 },
5475 .decl_instance_enum = .{
5476 .tag = .enumeration_type,
5477 .children = true,
5478 .attrs = decl_instance_abbrev_common_attrs ++ .{
5479 .{ .type, .ref_addr },
5480 },
5481 },
5482 .decl_instance_namespace_struct = .{
5483 .tag = .structure_type,
5484 .attrs = decl_instance_abbrev_common_attrs ++ .{
5485 .{ .declaration, .flag },
5486 },
5487 },
5488 .decl_instance_struct = .{
5489 .tag = .structure_type,
5490 .children = true,
5491 .attrs = decl_instance_abbrev_common_attrs ++ .{
5492 .{ .byte_size, .udata },
5493 .{ .alignment, .udata },
5494 },
5495 },
5496 .decl_instance_packed_struct = .{
5497 .tag = .structure_type,
5498 .children = true,
5499 .attrs = decl_instance_abbrev_common_attrs ++ .{
5500 .{ .type, .ref_addr },
5501 },
5502 },
5503 .decl_instance_union = .{
5504 .tag = .union_type,
5505 .children = true,
5506 .attrs = decl_instance_abbrev_common_attrs ++ .{
5507 .{ .byte_size, .udata },
5508 .{ .alignment, .udata },
5509 },
5510 },
5511 .decl_instance_packed_union = .{
5512 .tag = .union_type,
5513 .children = true,
5514 .attrs = decl_instance_abbrev_common_attrs ++ .{
5515 .{ .type, .ref_addr },
5516 },
5517 },
5518 .decl_instance_var = .{
5519 .tag = .variable,
5520 .attrs = decl_instance_abbrev_common_attrs ++ .{
5521 .{ .linkage_name, .strp },
5522 .{ .type, .ref_addr },
5523 .{ .location, .exprloc },
5524 .{ .alignment, .udata },
5525 .{ .external, .flag },
5526 },
5527 },
5528 .decl_instance_const = .{
5529 .tag = .constant,
5530 .attrs = decl_instance_abbrev_common_attrs ++ .{
5531 .{ .linkage_name, .strp },
5532 .{ .type, .ref_addr },
5533 .{ .alignment, .udata },
5534 .{ .external, .flag },
5535 },
5536 },
5537 .decl_instance_const_runtime_bits = .{
5538 .tag = .constant,
5539 .attrs = decl_instance_abbrev_common_attrs ++ .{
5540 .{ .linkage_name, .strp },
5541 .{ .type, .ref_addr },
5542 .{ .alignment, .udata },
5543 .{ .external, .flag },
5544 .{ .const_value, .block },
5545 },
5546 },
5547 .decl_instance_const_comptime_state = .{
5548 .tag = .constant,
5549 .attrs = decl_instance_abbrev_common_attrs ++ .{
5550 .{ .linkage_name, .strp },
5551 .{ .type, .ref_addr },
5552 .{ .alignment, .udata },
5553 .{ .external, .flag },
5554 .{ .ZIG_comptime_value, .ref_addr },
5555 },
5556 },
5557 .decl_instance_const_runtime_bits_comptime_state = .{
5558 .tag = .constant,
5559 .attrs = decl_instance_abbrev_common_attrs ++ .{
5560 .{ .linkage_name, .strp },
5561 .{ .type, .ref_addr },
5562 .{ .alignment, .udata },
5563 .{ .external, .flag },
5564 .{ .const_value, .block },
5565 .{ .ZIG_comptime_value, .ref_addr },
5566 },
5567 },
5568 .decl_instance_nullary_func = .{
5569 .tag = .subprogram,
5570 .attrs = decl_instance_abbrev_common_attrs ++ .{
5571 .{ .linkage_name, .strp },
5572 .{ .type, .ref_addr },
5573 .{ .low_pc, .addr },
5574 .{ .high_pc, .data4 },
5575 .{ .alignment, .udata },
5576 .{ .external, .flag },
5577 .{ .noreturn, .flag },
5578 },
5579 },
5580 .decl_instance_func = .{
5581 .tag = .subprogram,
5582 .children = true,
5583 .attrs = decl_instance_abbrev_common_attrs ++ .{
5584 .{ .linkage_name, .strp },
5585 .{ .type, .ref_addr },
5586 .{ .low_pc, .addr },
5587 .{ .high_pc, .data4 },
5588 .{ .alignment, .udata },
5589 .{ .external, .flag },
5590 .{ .noreturn, .flag },
5591 },
5592 },
5593 .decl_instance_nullary_func_generic = .{
5594 .tag = .subprogram,
5595 .attrs = decl_instance_abbrev_common_attrs ++ .{
5596 .{ .type, .ref_addr },
5597 },
5598 },
5599 .decl_instance_func_generic = .{
5600 .tag = .subprogram,
5601 .children = true,
5602 .attrs = decl_instance_abbrev_common_attrs ++ .{
5603 .{ .type, .ref_addr },
5604 },
5605 },
5606 .decl_instance_extern_nullary_func = .{
5607 .tag = .subprogram,
5608 .attrs = decl_instance_abbrev_common_attrs ++ .{
5609 .{ .linkage_name, .strp },
5610 .{ .type, .ref_addr },
5611 .{ .low_pc, .addr },
5612 .{ .external, .flag_present },
5613 .{ .noreturn, .flag },
5614 },
5615 },
5616 .decl_instance_extern_func = .{
5617 .tag = .subprogram,
5618 .children = true,
5619 .attrs = decl_instance_abbrev_common_attrs ++ .{
5620 .{ .linkage_name, .strp },
5621 .{ .type, .ref_addr },
5622 .{ .low_pc, .addr },
5623 .{ .external, .flag_present },
5624 .{ .noreturn, .flag },
5625 },
5626 },
5627 .compile_unit = .{
5628 .tag = .compile_unit,
5629 .children = true,
5630 .attrs = &.{
5631 .{ .language, .data1 },
5632 .{ .producer, .line_strp },
5633 .{ .comp_dir, .line_strp },
5634 .{ .name, .line_strp },
5635 .{ .base_types, .ref_addr },
5636 .{ .stmt_list, .sec_offset },
5637 .{ .rnglists_base, .sec_offset },
5638 .{ .ranges, .rnglistx },
5639 },
5640 },
5641 .module = .{
5642 .tag = .module,
5643 .children = true,
5644 .attrs = &.{
5645 .{ .name, .strp },
5646 .{ .ranges, .rnglistx },
5647 },
5648 },
5649 .empty_file = .{
5650 .tag = .structure_type,
5651 .attrs = &.{
5652 .{ .decl_file, .udata },
5653 .{ .name, .strp },
5654 },
5655 },
5656 .file = .{
5657 .tag = .structure_type,
5658 .children = true,
5659 .attrs = &.{
5660 .{ .decl_file, .udata },
5661 .{ .name, .strp },
5662 .{ .byte_size, .udata },
5663 .{ .alignment, .udata },
5664 },
5665 },
5666 .access = .{
5667 .tag = .member,
5668 .attrs = &.{
5669 .{ .name, .strp },
5670 },
5671 },
5672 .enum_field = .{
5673 .tag = .enumerator,
5674 .attrs = &.{
5675 .{ .const_value, .indirect },
5676 .{ .name, .strp },
5677 },
5678 },
5679 .generated_field = .{
5680 .tag = .member,
5681 .attrs = &.{
5682 .{ .name, .strp },
5683 .{ .type, .ref_addr },
5684 .{ .data_member_location, .udata },
5685 .{ .artificial, .flag_present },
5686 },
5687 },
5688 .field = .{
5689 .tag = .member,
5690 .attrs = &.{
5691 .{ .name, .strp },
5692 .{ .type, .ref_addr },
5693 .{ .data_member_location, .udata },
5694 .{ .alignment, .udata },
5695 },
5696 },
5697 .field_default_runtime_bits = .{
5698 .tag = .member,
5699 .attrs = &.{
5700 .{ .name, .strp },
5701 .{ .type, .ref_addr },
5702 .{ .data_member_location, .udata },
5703 .{ .alignment, .udata },
5704 .{ .default_value, .block },
5705 },
5706 },
5707 .field_default_comptime_state = .{
5708 .tag = .member,
5709 .attrs = &.{
5710 .{ .name, .strp },
5711 .{ .type, .ref_addr },
5712 .{ .data_member_location, .udata },
5713 .{ .alignment, .udata },
5714 .{ .ZIG_comptime_value, .ref_addr },
5715 },
5716 },
5717 .field_comptime = .{
5718 .tag = .member,
5719 .attrs = &.{
5720 .{ .const_expr, .flag_present },
5721 .{ .name, .strp },
5722 .{ .type, .ref_addr },
5723 },
5724 },
5725 .field_comptime_runtime_bits = .{
5726 .tag = .member,
5727 .attrs = &.{
5728 .{ .const_expr, .flag_present },
5729 .{ .name, .strp },
5730 .{ .type, .ref_addr },
5731 .{ .const_value, .block },
5732 },
5733 },
5734 .field_comptime_comptime_state = .{
5735 .tag = .member,
5736 .attrs = &.{
5737 .{ .const_expr, .flag_present },
5738 .{ .name, .strp },
5739 .{ .type, .ref_addr },
5740 .{ .ZIG_comptime_value, .ref_addr },
5741 },
5742 },
5743 .packed_field = .{
5744 .tag = .member,
5745 .attrs = &.{
5746 .{ .name, .strp },
5747 .{ .type, .ref_addr },
5748 .{ .data_bit_offset, .udata },
5749 },
5750 },
5751 .tagged_union = .{
5752 .tag = .variant_part,
5753 .children = true,
5754 .attrs = &.{
5755 .{ .discr, .ref_addr },
5756 },
5757 },
5758 .tagged_union_field = .{
5759 .tag = .variant,
5760 .children = true,
5761 .attrs = &.{
5762 .{ .discr_value, .indirect },
5763 },
5764 },
5765 .tagged_union_default_field = .{
5766 .tag = .variant,
5767 .children = true,
5768 .attrs = &.{},
5769 },
5770 .void_type = .{
5771 .tag = .unspecified_type,
5772 .attrs = &.{
5773 .{ .name, .strp },
5774 },
5775 },
5776 .numeric_type = .{
5777 .tag = .base_type,
5778 .attrs = &.{
5779 .{ .name, .strp },
5780 .{ .encoding, .data1 },
5781 .{ .bit_size, .udata },
5782 .{ .byte_size, .udata },
5783 .{ .alignment, .udata },
5784 },
5785 },
5786 .inferred_error_set_type = .{
5787 .tag = .typedef,
5788 .attrs = &.{
5789 .{ .name, .strp },
5790 .{ .type, .ref_addr },
5791 },
5792 },
5793 .ptr_type = .{
5794 .tag = .pointer_type,
5795 .attrs = &.{
5796 .{ .name, .strp },
5797 .{ .address_class, .data1 },
5798 .{ .type, .ref_addr },
5799 },
5800 },
5801 .ptr_sentinel_type = .{
5802 .tag = .pointer_type,
5803 .attrs = &.{
5804 .{ .name, .strp },
5805 .{ .ZIG_sentinel, .block },
5806 .{ .address_class, .data1 },
5807 .{ .type, .ref_addr },
5808 },
5809 },
5810 .ptr_aligned_type = .{
5811 .tag = .pointer_type,
5812 .attrs = &.{
5813 .{ .name, .strp },
5814 .{ .alignment, .udata },
5815 .{ .address_class, .data1 },
5816 .{ .type, .ref_addr },
5817 },
5818 },
5819 .ptr_aligned_sentinel_type = .{
5820 .tag = .pointer_type,
5821 .attrs = &.{
5822 .{ .name, .strp },
5823 .{ .ZIG_sentinel, .block },
5824 .{ .alignment, .udata },
5825 .{ .address_class, .data1 },
5826 .{ .type, .ref_addr },
5827 },
5828 },
5829 .is_const = .{
5830 .tag = .const_type,
5831 .attrs = &.{
5832 .{ .type, .ref_addr },
5833 },
5834 },
5835 .is_volatile = .{
5836 .tag = .volatile_type,
5837 .attrs = &.{
5838 .{ .type, .ref_addr },
5839 },
5840 },
5841 .array_type = .{
5842 .tag = .array_type,
5843 .children = true,
5844 .attrs = &.{
5845 .{ .name, .strp },
5846 .{ .type, .ref_addr },
5847 },
5848 },
5849 .array_sentinel_type = .{
5850 .tag = .array_type,
5851 .children = true,
5852 .attrs = &.{
5853 .{ .name, .strp },
5854 .{ .ZIG_sentinel, .block },
5855 .{ .type, .ref_addr },
5856 },
5857 },
5858 .vector_type = .{
5859 .tag = .array_type,
5860 .children = true,
5861 .attrs = &.{
5862 .{ .name, .strp },
5863 .{ .type, .ref_addr },
5864 .{ .GNU_vector, .flag_present },
5865 },
5866 },
5867 .array_index = .{
5868 .tag = .subrange_type,
5869 .attrs = &.{
5870 .{ .lower_bound, .udata },
5871 },
5872 },
5873 .array_len = .{
5874 .tag = .subrange_type,
5875 .attrs = &.{
5876 .{ .type, .ref_addr },
5877 .{ .count, .udata },
5878 },
5879 },
5880 .nullary_func_type = .{
5881 .tag = .subroutine_type,
5882 .attrs = &.{
5883 .{ .name, .strp },
5884 .{ .calling_convention, .data1 },
5885 .{ .type, .ref_addr },
5886 },
5887 },
5888 .func_type = .{
5889 .tag = .subroutine_type,
5890 .children = true,
5891 .attrs = &.{
5892 .{ .name, .strp },
5893 .{ .calling_convention, .data1 },
5894 .{ .type, .ref_addr },
5895 },
5896 },
5897 .func_type_param = .{
5898 .tag = .formal_parameter,
5899 .attrs = &.{
5900 .{ .type, .ref_addr },
5901 },
5902 },
5903 .is_var_args = .{
5904 .tag = .unspecified_parameters,
5905 },
5906 .generated_empty_enum_type = .{
5907 .tag = .enumeration_type,
5908 .attrs = &.{
5909 .{ .name, .strp },
5910 .{ .type, .ref_addr },
5911 },
5912 },
5913 .generated_enum_type = .{
5914 .tag = .enumeration_type,
5915 .children = true,
5916 .attrs = &.{
5917 .{ .name, .strp },
5918 .{ .type, .ref_addr },
5919 },
5920 },
5921 .generated_empty_struct_type = .{
5922 .tag = .structure_type,
5923 .attrs = &.{
5924 .{ .name, .strp },
5925 .{ .declaration, .flag },
5926 },
5927 },
5928 .generated_struct_type = .{
5929 .tag = .structure_type,
5930 .children = true,
5931 .attrs = &.{
5932 .{ .name, .strp },
5933 .{ .byte_size, .udata },
5934 .{ .alignment, .udata },
5935 },
5936 },
5937 .generated_union_type = .{
5938 .tag = .union_type,
5939 .children = true,
5940 .attrs = &.{
5941 .{ .name, .strp },
5942 .{ .byte_size, .udata },
5943 .{ .alignment, .udata },
5944 },
5945 },
5946 .empty_enum_type = .{
5947 .tag = .enumeration_type,
5948 .attrs = &.{
5949 .{ .decl_file, .udata },
5950 .{ .name, .strp },
5951 .{ .type, .ref_addr },
5952 },
5953 },
5954 .enum_type = .{
5955 .tag = .enumeration_type,
5956 .children = true,
5957 .attrs = &.{
5958 .{ .decl_file, .udata },
5959 .{ .name, .strp },
5960 .{ .type, .ref_addr },
5961 },
5962 },
5963 .empty_struct_type = .{
5964 .tag = .structure_type,
5965 .attrs = &.{
5966 .{ .decl_file, .udata },
5967 .{ .name, .strp },
5968 .{ .declaration, .flag },
5969 },
5970 },
5971 .struct_type = .{
5972 .tag = .structure_type,
5973 .children = true,
5974 .attrs = &.{
5975 .{ .decl_file, .udata },
5976 .{ .name, .strp },
5977 .{ .byte_size, .udata },
5978 .{ .alignment, .udata },
5979 },
5980 },
5981 .empty_packed_struct_type = .{
5982 .tag = .structure_type,
5983 .attrs = &.{
5984 .{ .decl_file, .udata },
5985 .{ .name, .strp },
5986 .{ .type, .ref_addr },
5987 },
5988 },
5989 .packed_struct_type = .{
5990 .tag = .structure_type,
5991 .children = true,
5992 .attrs = &.{
5993 .{ .decl_file, .udata },
5994 .{ .name, .strp },
5995 .{ .type, .ref_addr },
5996 },
5997 },
5998 .empty_union_type = .{
5999 .tag = .union_type,
6000 .attrs = &.{
6001 .{ .decl_file, .udata },
6002 .{ .name, .strp },
6003 .{ .byte_size, .udata },
6004 .{ .alignment, .udata },
6005 },
6006 },
6007 .union_type = .{
6008 .tag = .union_type,
6009 .children = true,
6010 .attrs = &.{
6011 .{ .decl_file, .udata },
6012 .{ .name, .strp },
6013 .{ .byte_size, .udata },
6014 .{ .alignment, .udata },
6015 },
6016 },
6017 .empty_packed_union_type = .{
6018 .tag = .union_type,
6019 .attrs = &.{
6020 .{ .decl_file, .udata },
6021 .{ .name, .strp },
6022 .{ .type, .ref_addr },
6023 },
6024 },
6025 .packed_union_type = .{
6026 .tag = .union_type,
6027 .children = true,
6028 .attrs = &.{
6029 .{ .decl_file, .udata },
6030 .{ .name, .strp },
6031 .{ .type, .ref_addr },
6032 },
6033 },
6034 .builtin_extern_nullary_func = .{
6035 .tag = .subprogram,
6036 .attrs = &.{
6037 .{ .ZIG_parent, .ref_addr },
6038 .{ .linkage_name, .strp },
6039 .{ .type, .ref_addr },
6040 .{ .low_pc, .addr },
6041 .{ .external, .flag_present },
6042 .{ .noreturn, .flag },
6043 },
6044 },
6045 .builtin_extern_func = .{
6046 .tag = .subprogram,
6047 .children = true,
6048 .attrs = &.{
6049 .{ .ZIG_parent, .ref_addr },
6050 .{ .linkage_name, .strp },
6051 .{ .type, .ref_addr },
6052 .{ .low_pc, .addr },
6053 .{ .external, .flag_present },
6054 .{ .noreturn, .flag },
6055 },
6056 },
6057 .builtin_extern_var = .{
6058 .tag = .variable,
6059 .attrs = &.{
6060 .{ .ZIG_parent, .ref_addr },
6061 .{ .linkage_name, .strp },
6062 .{ .type, .ref_addr },
6063 .{ .location, .exprloc },
6064 .{ .external, .flag_present },
6065 },
6066 },
6067 .empty_block = .{
6068 .tag = .lexical_block,
6069 .attrs = &.{
6070 .{ .low_pc, .addr },
6071 .{ .high_pc, .data4 },
6072 },
6073 },
6074 .block = .{
6075 .tag = .lexical_block,
6076 .children = true,
6077 .attrs = &.{
6078 .{ .low_pc, .addr },
6079 .{ .high_pc, .data4 },
6080 },
6081 },
6082 .empty_inlined_func = .{
6083 .tag = .inlined_subroutine,
6084 .attrs = &.{
6085 .{ .abstract_origin, .ref_addr },
6086 .{ .call_line, .udata },
6087 .{ .call_column, .udata },
6088 .{ .low_pc, .addr },
6089 .{ .high_pc, .data4 },
6090 },
6091 },
6092 .inlined_func = .{
6093 .tag = .inlined_subroutine,
6094 .children = true,
6095 .attrs = &.{
6096 .{ .abstract_origin, .ref_addr },
6097 .{ .call_line, .udata },
6098 .{ .call_column, .udata },
6099 .{ .low_pc, .addr },
6100 .{ .high_pc, .data4 },
6101 },
6102 },
6103 .arg = .{
6104 .tag = .formal_parameter,
6105 .attrs = &.{
6106 .{ .name, .strp },
6107 .{ .type, .ref_addr },
6108 .{ .location, .exprloc },
6109 },
6110 },
6111 .unnamed_arg = .{
6112 .tag = .formal_parameter,
6113 .attrs = &.{
6114 .{ .type, .ref_addr },
6115 .{ .location, .exprloc },
6116 },
6117 },
6118 .comptime_arg = .{
6119 .tag = .formal_parameter,
6120 .attrs = &.{
6121 .{ .const_expr, .flag_present },
6122 .{ .name, .strp },
6123 .{ .type, .ref_addr },
6124 },
6125 },
6126 .unnamed_comptime_arg = .{
6127 .tag = .formal_parameter,
6128 .attrs = &.{
6129 .{ .const_expr, .flag_present },
6130 .{ .type, .ref_addr },
6131 },
6132 },
6133 .comptime_arg_runtime_bits = .{
6134 .tag = .formal_parameter,
6135 .attrs = &.{
6136 .{ .const_expr, .flag_present },
6137 .{ .name, .strp },
6138 .{ .type, .ref_addr },
6139 .{ .const_value, .block },
6140 },
6141 },
6142 .unnamed_comptime_arg_runtime_bits = .{
6143 .tag = .formal_parameter,
6144 .attrs = &.{
6145 .{ .const_expr, .flag_present },
6146 .{ .type, .ref_addr },
6147 .{ .const_value, .block },
6148 },
6149 },
6150 .comptime_arg_comptime_state = .{
6151 .tag = .formal_parameter,
6152 .attrs = &.{
6153 .{ .const_expr, .flag_present },
6154 .{ .name, .strp },
6155 .{ .type, .ref_addr },
6156 .{ .ZIG_comptime_value, .ref_addr },
6157 },
6158 },
6159 .unnamed_comptime_arg_comptime_state = .{
6160 .tag = .formal_parameter,
6161 .attrs = &.{
6162 .{ .const_expr, .flag_present },
6163 .{ .type, .ref_addr },
6164 .{ .ZIG_comptime_value, .ref_addr },
6165 },
6166 },
6167 .comptime_arg_runtime_bits_comptime_state = .{
6168 .tag = .formal_parameter,
6169 .attrs = &.{
6170 .{ .const_expr, .flag_present },
6171 .{ .name, .strp },
6172 .{ .type, .ref_addr },
6173 .{ .const_value, .block },
6174 .{ .ZIG_comptime_value, .ref_addr },
6175 },
6176 },
6177 .unnamed_comptime_arg_runtime_bits_comptime_state = .{
6178 .tag = .formal_parameter,
6179 .attrs = &.{
6180 .{ .const_expr, .flag_present },
6181 .{ .type, .ref_addr },
6182 .{ .const_value, .block },
6183 .{ .ZIG_comptime_value, .ref_addr },
6184 },
6185 },
6186 .extern_param = .{
6187 .tag = .formal_parameter,
6188 .attrs = &.{
6189 .{ .type, .ref_addr },
6190 },
6191 },
6192 .local_var = .{
6193 .tag = .variable,
6194 .attrs = &.{
6195 .{ .name, .strp },
6196 .{ .type, .ref_addr },
6197 .{ .location, .exprloc },
6198 },
6199 },
6200 .local_const = .{
6201 .tag = .constant,
6202 .attrs = &.{
6203 .{ .name, .strp },
6204 .{ .type, .ref_addr },
6205 },
6206 },
6207 .local_const_runtime_bits = .{
6208 .tag = .constant,
6209 .attrs = &.{
6210 .{ .name, .strp },
6211 .{ .type, .ref_addr },
6212 .{ .const_value, .block },
6213 },
6214 },
6215 .local_const_comptime_state = .{
6216 .tag = .constant,
6217 .attrs = &.{
6218 .{ .name, .strp },
6219 .{ .type, .ref_addr },
6220 .{ .ZIG_comptime_value, .ref_addr },
6221 },
6222 },
6223 .local_const_runtime_bits_comptime_state = .{
6224 .tag = .constant,
6225 .attrs = &.{
6226 .{ .name, .strp },
6227 .{ .type, .ref_addr },
6228 .{ .const_value, .block },
6229 .{ .ZIG_comptime_value, .ref_addr },
6230 },
6231 },
6232 .undefined_comptime_value = .{
6233 .tag = .ZIG_comptime_value,
6234 .attrs = &.{
6235 .{ .type, .ref_addr },
6236 },
6237 },
6238 .aggregate_undefined_comptime_value = .{
6239 .tag = .ZIG_comptime_value,
6240 .children = true,
6241 .attrs = &.{
6242 .{ .type, .ref_addr },
6243 },
6244 },
6245 .comptime_value = .{
6246 .tag = .ZIG_comptime_value,
6247 .attrs = &.{
6248 .{ .type, .ref_addr },
6249 .{ .const_value, .indirect },
6250 },
6251 },
6252 .aggregate_comptime_value = .{
6253 .tag = .ZIG_comptime_value,
6254 .children = true,
6255 .attrs = &.{
6256 .{ .type, .ref_addr },
6257 .{ .const_value, .indirect },
6258 },
6259 },
6260 .location_comptime_value = .{
6261 .tag = .ZIG_comptime_value,
6262 .attrs = &.{
6263 .{ .type, .ref_addr },
6264 .{ .location, .exprloc },
6265 },
6266 },
6267 .aggregate_location_comptime_value = .{
6268 .tag = .ZIG_comptime_value,
6269 .children = true,
6270 .attrs = &.{
6271 .{ .type, .ref_addr },
6272 .{ .location, .exprloc },
6273 },
6274 },
6275 .comptime_value_field_runtime_bits = .{
6276 .tag = .member,
6277 .attrs = &.{
6278 .{ .name, .strp },
6279 .{ .const_value, .block },
6280 },
6281 },
6282 .comptime_value_field_comptime_state = .{
6283 .tag = .member,
6284 .attrs = &.{
6285 .{ .name, .strp },
6286 .{ .ZIG_comptime_value, .ref_addr },
6287 },
6288 },
6289 .comptime_value_elem_runtime_bits = .{
6290 .tag = .member,
6291 .attrs = &.{
6292 .{ .const_value, .block },
6293 },
6294 },
6295 .comptime_value_elem_comptime_state = .{
6296 .tag = .member,
6297 .attrs = &.{
6298 .{ .ZIG_comptime_value, .ref_addr },
6299 },
6300 },
6301 .null = undefined,
6302 });
6303};
6304
6305fn getFile(dwarf: *Dwarf) ?Io.File {
6306 if (dwarf.bin_file.cast(.macho)) |macho_file| if (macho_file.d_sym) |*d_sym| return d_sym.file;
6307 return dwarf.bin_file.file;
6308}
6309
6310fn constPoolUser(dwarf: *Dwarf) link.ConstPool.User {
6311 return switch (dwarf.bin_file.tag) {
6312 else => unreachable,
6313 .elf => .{ .elf = dwarf },
6314 .macho => .{ .macho = dwarf },
6315 };
6316}
6317
6318fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {
6319 const entry = try dwarf.debug_aranges.section.getUnit(unit).addEntry(dwarf.gpa);
6320 assert(try dwarf.debug_frame.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6321 assert(try dwarf.debug_info.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6322 assert(try dwarf.debug_line.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6323 assert(try dwarf.debug_loclists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6324 assert(try dwarf.debug_rnglists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
6325 return entry;
6326}
6327
6328fn freeCommonEntry(
6329 dwarf: *Dwarf,
6330 unit: Unit.Index,
6331 entry: Entry.Index,
6332) (UpdateError || Writer.Error)!void {
6333 try dwarf.debug_aranges.section.freeEntry(unit, entry, dwarf);
6334 try dwarf.debug_frame.section.freeEntry(unit, entry, dwarf);
6335 try dwarf.debug_info.section.freeEntry(unit, entry, dwarf);
6336 try dwarf.debug_line.section.freeEntry(unit, entry, dwarf);
6337 try dwarf.debug_loclists.section.freeEntry(unit, entry, dwarf);
6338 try dwarf.debug_rnglists.section.freeEntry(unit, entry, dwarf);
6339}
6340
6341fn writeInt(dwarf: *Dwarf, buf: []u8, int: u64) void {
6342 switch (buf.len) {
6343 inline 0...8 => |len| std.mem.writeInt(
6344 @Int(.unsigned, len * 8),
6345 buf[0..len],
6346 @intCast(int),
6347 dwarf.endian,
6348 ),
6349 else => unreachable,
6350 }
6351}
6352
6353fn resolveReloc(dwarf: *Dwarf, source: u64, target: u64, size: u32) RelocError!void {
6354 const comp = dwarf.bin_file.comp;
6355 const io = comp.io;
6356 var buf: [8]u8 = undefined;
6357 dwarf.writeInt(buf[0..size], target);
6358 try dwarf.getFile().?.writePositionalAll(io, buf[0..size], source);
6359}
6360
6361fn unitLengthBytes(dwarf: *Dwarf) u32 {
6362 return switch (dwarf.format) {
6363 .@"32" => 4,
6364 .@"64" => 4 + 8,
6365 };
6366}
6367
6368fn sectionOffsetBytes(dwarf: *Dwarf) u32 {
6369 return switch (dwarf.format) {
6370 .@"32" => 4,
6371 .@"64" => 8,
6372 };
6373}
6374
6375fn uleb128Bytes(value: anytype) u32 {
6376 var buf: [64]u8 = undefined;
6377 var dw: Writer.Discarding = .init(&buf);
6378 dw.writer.writeUleb128(value) catch unreachable;
6379 return @intCast(dw.fullCount());
6380}
6381
6382fn sleb128Bytes(value: anytype) u32 {
6383 var buf: [64]u8 = undefined;
6384 var dw: Writer.Discarding = .init(&buf);
6385 dw.writer.writeSleb128(value) catch unreachable;
6386 return @intCast(dw.fullCount());
6387}
6388
6389/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
6390const force_incremental = false;
6391inline fn incremental(dwarf: Dwarf) bool {
6392 return force_incremental or dwarf.bin_file.comp.config.incremental;
6393}