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