authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-09 14:11:28+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-12-09 14:11:28+01:00
logd88eb75a69d27ef50635f9aa1caf2a7177d99ead
tree85d25fdddfda28dd2b65b49ac0d91284e043cfca
parent71c82393ebba8b40266551781d4b2c09b1fca1dc
parent9735953ae2ed04117181cf2cb6cde5cbfb8ca76a
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13820 from ziglang/dwarf-multiple-files

dwarf: add support for multiple source files

5 files changed, 554 insertions(+), 442 deletions(-)

src/link/Dwarf.zig+354-289
......@@ -22,7 +22,7 @@ const Value = @import("../value.zig").Value;
2222const Type = @import("../type.zig").Type;
2323
2424allocator: Allocator,
25tag: File.Tag,
25bin_file: *File,
2626ptr_width: PtrWidth,
2727target: std.Target,
2828
......@@ -44,6 +44,12 @@ abbrev_table_offset: ?u64 = null,
4444/// Table of debug symbol names.
4545strtab: std.ArrayListUnmanaged(u8) = .{},
4646
47/// Quick lookup array of all defined source files referenced by at least one Decl.
48/// They will end up in the DWARF debug_line header as two lists:
49/// * []include_directory
50/// * []file_names
51di_files: std.AutoArrayHashMapUnmanaged(*const Module.File, void) = .{},
52
4753/// List of atoms that are owned directly by the DWARF module.
4854/// TODO convert links in DebugInfoAtom into indices and make
4955/// sure every atom is owned by this module.
......@@ -887,7 +893,7 @@ const min_nop_size = 2;
887893/// actual_capacity + (actual_capacity / ideal_factor)
888894const ideal_factor = 3;
889895
890pub fn init(allocator: Allocator, tag: File.Tag, target: std.Target) Dwarf {
896pub fn init(allocator: Allocator, bin_file: *File, target: std.Target) Dwarf {
891897 const ptr_width: PtrWidth = switch (target.cpu.arch.ptrBitWidth()) {
892898 0...32 => .p32,
893899 33...64 => .p64,
......@@ -895,7 +901,7 @@ pub fn init(allocator: Allocator, tag: File.Tag, target: std.Target) Dwarf {
895901 };
896902 return Dwarf{
897903 .allocator = allocator,
898 .tag = tag,
904 .bin_file = bin_file,
899905 .ptr_width = ptr_width,
900906 .target = target,
901907 };
......@@ -906,6 +912,7 @@ pub fn deinit(self: *Dwarf) void {
906912 self.dbg_line_fn_free_list.deinit(gpa);
907913 self.atom_free_list.deinit(gpa);
908914 self.strtab.deinit(gpa);
915 self.di_files.deinit(gpa);
909916 self.global_abbrev_relocs.deinit(gpa);
910917
911918 for (self.managed_atoms.items) |atom| {
......@@ -968,7 +975,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
968975 assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len);
969976 // Once we support more than one source file, this will have the ability to be more
970977 // than one possible value.
971 const file_index = 1;
978 const file_index = try self.addDIFile(mod, decl_index);
972979 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);
973980
974981 // Emit a line for the begin curly with prologue_end=false. The codegen will
......@@ -995,7 +1002,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
9951002 dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4
9961003 //
9971004 if (fn_ret_has_bits) {
998 const atom = getDbgInfoAtom(self.tag, mod, decl_index);
1005 const atom = getDbgInfoAtom(self.bin_file.tag, mod, decl_index);
9991006 try decl_state.addTypeRelocGlobal(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len));
10001007 dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4
10011008 }
......@@ -1013,7 +1020,6 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
10131020
10141021pub fn commitDeclState(
10151022 self: *Dwarf,
1016 file: *File,
10171023 module: *Module,
10181024 decl_index: Module.Decl.Index,
10191025 sym_addr: u64,
......@@ -1069,7 +1075,7 @@ pub fn commitDeclState(
10691075 // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for
10701076 // `TextBlock` and the .debug_info. If you are editing this logic, you
10711077 // probably need to edit that logic too.
1072 const src_fn = switch (self.tag) {
1078 const src_fn = switch (self.bin_file.tag) {
10731079 .elf => &decl.fn_link.elf,
10741080 .macho => &decl.fn_link.macho,
10751081 .wasm => &decl.fn_link.wasm.src_fn,
......@@ -1090,22 +1096,21 @@ pub fn commitDeclState(
10901096 next.prev = src_fn.prev;
10911097 src_fn.next = null;
10921098 // Populate where it used to be with NOPs.
1093 switch (self.tag) {
1099 switch (self.bin_file.tag) {
10941100 .elf => {
1095 const elf_file = file.cast(File.Elf).?;
1101 const elf_file = self.bin_file.cast(File.Elf).?;
10961102 const debug_line_sect = &elf_file.sections.items[elf_file.debug_line_section_index.?];
10971103 const file_pos = debug_line_sect.sh_offset + src_fn.off;
10981104 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
10991105 },
11001106 .macho => {
1101 const macho_file = file.cast(File.MachO).?;
1102 const d_sym = &macho_file.d_sym.?;
1103 const debug_line_sect = &d_sym.sections.items[d_sym.debug_line_section_index.?];
1107 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1108 const debug_line_sect = d_sym.getSectionPtr(d_sym.debug_line_section_index.?);
11041109 const file_pos = debug_line_sect.offset + src_fn.off;
11051110 try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len);
11061111 },
11071112 .wasm => {
1108 const wasm_file = file.cast(File.Wasm).?;
1113 const wasm_file = self.bin_file.cast(File.Wasm).?;
11091114 const debug_line = wasm_file.debug_line_atom.?.code;
11101115 writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len);
11111116 },
......@@ -1132,7 +1137,7 @@ pub fn commitDeclState(
11321137 self.dbg_line_fn_first = src_fn;
11331138 self.dbg_line_fn_last = src_fn;
11341139
1135 src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(module));
1140 src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{}));
11361141 }
11371142
11381143 const last_src_fn = self.dbg_line_fn_last.?;
......@@ -1142,32 +1147,12 @@ pub fn commitDeclState(
11421147
11431148 // We only have support for one compilation unit so far, so the offsets are directly
11441149 // from the .debug_line section.
1145 switch (self.tag) {
1150 switch (self.bin_file.tag) {
11461151 .elf => {
1147 const elf_file = file.cast(File.Elf).?;
1148 const debug_line_sect = &elf_file.sections.items[elf_file.debug_line_section_index.?];
1149 if (needed_size != debug_line_sect.sh_size) {
1150 if (needed_size > elf_file.allocatedSize(debug_line_sect.sh_offset)) {
1151 const new_offset = elf_file.findFreeSpace(needed_size, 1);
1152 const existing_size = last_src_fn.off;
1153 log.debug("moving .debug_line section: {d} bytes from 0x{x} to 0x{x}", .{
1154 existing_size,
1155 debug_line_sect.sh_offset,
1156 new_offset,
1157 });
1158 const amt = try elf_file.base.file.?.copyRangeAll(
1159 debug_line_sect.sh_offset,
1160 elf_file.base.file.?,
1161 new_offset,
1162 existing_size,
1163 );
1164 if (amt != existing_size) return error.InputOutput;
1165 debug_line_sect.sh_offset = new_offset;
1166 }
1167 debug_line_sect.sh_size = needed_size;
1168 elf_file.shdr_table_dirty = true; // TODO look into making only the one section dirty
1169 elf_file.debug_line_header_dirty = true;
1170 }
1152 const elf_file = self.bin_file.cast(File.Elf).?;
1153 const shdr_index = elf_file.debug_line_section_index.?;
1154 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
1155 const debug_line_sect = elf_file.sections.items[shdr_index];
11711156 const file_pos = debug_line_sect.sh_offset + src_fn.off;
11721157 try pwriteDbgLineNops(
11731158 elf_file.base.file.?,
......@@ -1179,31 +1164,11 @@ pub fn commitDeclState(
11791164 },
11801165
11811166 .macho => {
1182 const macho_file = file.cast(File.MachO).?;
1183 const d_sym = &macho_file.d_sym.?;
1184 const debug_line_sect = &d_sym.sections.items[d_sym.debug_line_section_index.?];
1185 if (needed_size != debug_line_sect.size) {
1186 if (needed_size > d_sym.allocatedSize(debug_line_sect.offset)) {
1187 const new_offset = d_sym.findFreeSpace(needed_size, 1);
1188 const existing_size = last_src_fn.off;
1189 std.log.scoped(.dsym).debug("moving __debug_line section: {} bytes from 0x{x} to 0x{x}", .{
1190 existing_size,
1191 debug_line_sect.offset,
1192 new_offset,
1193 });
1194 const amt = try d_sym.file.copyRangeAll(
1195 debug_line_sect.offset,
1196 d_sym.file,
1197 new_offset,
1198 existing_size,
1199 );
1200 if (amt != existing_size) return error.InputOutput;
1201 debug_line_sect.offset = @intCast(u32, new_offset);
1202 }
1203 debug_line_sect.size = needed_size;
1204 d_sym.debug_line_header_dirty = true;
1205 }
1206 const file_pos = debug_line_sect.offset + src_fn.off;
1167 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1168 const sect_index = d_sym.debug_line_section_index.?;
1169 try d_sym.growSection(sect_index, needed_size, true);
1170 const sect = d_sym.getSection(sect_index);
1171 const file_pos = sect.offset + src_fn.off;
12071172 try pwriteDbgLineNops(
12081173 d_sym.file,
12091174 file_pos,
......@@ -1214,7 +1179,7 @@ pub fn commitDeclState(
12141179 },
12151180
12161181 .wasm => {
1217 const wasm_file = file.cast(File.Wasm).?;
1182 const wasm_file = self.bin_file.cast(File.Wasm).?;
12181183 const atom = wasm_file.debug_line_atom.?;
12191184 const debug_line = &atom.code;
12201185 const segment_size = debug_line.items.len;
......@@ -1247,7 +1212,7 @@ pub fn commitDeclState(
12471212 if (dbg_info_buffer.items.len == 0)
12481213 return;
12491214
1250 const atom = getDbgInfoAtom(self.tag, module, decl_index);
1215 const atom = getDbgInfoAtom(self.bin_file.tag, module, decl_index);
12511216 if (decl_state.abbrev_table.items.len > 0) {
12521217 // Now we emit the .debug_info types of the Decl. These will count towards the size of
12531218 // the buffer, so we have to do it before computing the offset, and we can't perform the actual
......@@ -1274,7 +1239,7 @@ pub fn commitDeclState(
12741239 }
12751240
12761241 log.debug("updateDeclDebugInfoAllocation for '{s}'", .{decl.name});
1277 try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));
1242 try self.updateDeclDebugInfoAllocation(atom, @intCast(u32, dbg_info_buffer.items.len));
12781243
12791244 while (decl_state.abbrev_relocs.popOrNull()) |reloc| {
12801245 if (reloc.target) |target| {
......@@ -1319,10 +1284,9 @@ pub fn commitDeclState(
13191284 }
13201285
13211286 while (decl_state.exprloc_relocs.popOrNull()) |reloc| {
1322 switch (self.tag) {
1287 switch (self.bin_file.tag) {
13231288 .macho => {
1324 const macho_file = file.cast(File.MachO).?;
1325 const d_sym = &macho_file.d_sym.?;
1289 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
13261290 try d_sym.relocs.append(d_sym.allocator, .{
13271291 .type = switch (reloc.type) {
13281292 .direct_load => .direct_load,
......@@ -1339,10 +1303,10 @@ pub fn commitDeclState(
13391303 }
13401304
13411305 log.debug("writeDeclDebugInfo for '{s}", .{decl.name});
1342 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
1306 try self.writeDeclDebugInfo(atom, dbg_info_buffer.items);
13431307}
13441308
1345fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u32) !void {
1309fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {
13461310 const tracy = trace(@src());
13471311 defer tracy.end();
13481312
......@@ -1365,22 +1329,21 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3
13651329 next.prev = atom.prev;
13661330 atom.next = null;
13671331 // Populate where it used to be with NOPs.
1368 switch (self.tag) {
1332 switch (self.bin_file.tag) {
13691333 .elf => {
1370 const elf_file = file.cast(File.Elf).?;
1334 const elf_file = self.bin_file.cast(File.Elf).?;
13711335 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];
13721336 const file_pos = debug_info_sect.sh_offset + atom.off;
13731337 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
13741338 },
13751339 .macho => {
1376 const macho_file = file.cast(File.MachO).?;
1377 const d_sym = &macho_file.d_sym.?;
1378 const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?];
1340 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1341 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
13791342 const file_pos = debug_info_sect.offset + atom.off;
13801343 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false);
13811344 },
13821345 .wasm => {
1383 const wasm_file = file.cast(File.Wasm).?;
1346 const wasm_file = self.bin_file.cast(File.Wasm).?;
13841347 const debug_info = &wasm_file.debug_info_atom.?.code;
13851348 try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false);
13861349 },
......@@ -1411,7 +1374,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3
14111374 }
14121375}
14131376
1414fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []const u8) !void {
1377fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void {
14151378 const tracy = trace(@src());
14161379 defer tracy.end();
14171380
......@@ -1431,32 +1394,12 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
14311394
14321395 // We only have support for one compilation unit so far, so the offsets are directly
14331396 // from the .debug_info section.
1434 switch (self.tag) {
1397 switch (self.bin_file.tag) {
14351398 .elf => {
1436 const elf_file = file.cast(File.Elf).?;
1437 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];
1438 if (needed_size != debug_info_sect.sh_size) {
1439 if (needed_size > elf_file.allocatedSize(debug_info_sect.sh_offset)) {
1440 const new_offset = elf_file.findFreeSpace(needed_size, 1);
1441 const existing_size = last_decl.off;
1442 log.debug("moving .debug_info section: {d} bytes from 0x{x} to 0x{x}", .{
1443 existing_size,
1444 debug_info_sect.sh_offset,
1445 new_offset,
1446 });
1447 const amt = try elf_file.base.file.?.copyRangeAll(
1448 debug_info_sect.sh_offset,
1449 elf_file.base.file.?,
1450 new_offset,
1451 existing_size,
1452 );
1453 if (amt != existing_size) return error.InputOutput;
1454 debug_info_sect.sh_offset = new_offset;
1455 }
1456 debug_info_sect.sh_size = needed_size;
1457 elf_file.shdr_table_dirty = true; // TODO look into making only the one section dirty
1458 elf_file.debug_info_header_dirty = true;
1459 }
1399 const elf_file = self.bin_file.cast(File.Elf).?;
1400 const shdr_index = elf_file.debug_info_section_index.?;
1401 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
1402 const debug_info_sect = elf_file.sections.items[shdr_index];
14601403 const file_pos = debug_info_sect.sh_offset + atom.off;
14611404 try pwriteDbgInfoNops(
14621405 elf_file.base.file.?,
......@@ -1469,31 +1412,11 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
14691412 },
14701413
14711414 .macho => {
1472 const macho_file = file.cast(File.MachO).?;
1473 const d_sym = &macho_file.d_sym.?;
1474 const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?];
1475 if (needed_size != debug_info_sect.size) {
1476 if (needed_size > d_sym.allocatedSize(debug_info_sect.offset)) {
1477 const new_offset = d_sym.findFreeSpace(needed_size, 1);
1478 const existing_size = last_decl.off;
1479 std.log.scoped(.dsym).debug("moving __debug_info section: {} bytes from 0x{x} to 0x{x}", .{
1480 existing_size,
1481 debug_info_sect.offset,
1482 new_offset,
1483 });
1484 const amt = try d_sym.file.copyRangeAll(
1485 debug_info_sect.offset,
1486 d_sym.file,
1487 new_offset,
1488 existing_size,
1489 );
1490 if (amt != existing_size) return error.InputOutput;
1491 debug_info_sect.offset = @intCast(u32, new_offset);
1492 }
1493 debug_info_sect.size = needed_size;
1494 d_sym.debug_info_header_dirty = true;
1495 }
1496 const file_pos = debug_info_sect.offset + atom.off;
1415 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1416 const sect_index = d_sym.debug_info_section_index.?;
1417 try d_sym.growSection(sect_index, needed_size, true);
1418 const sect = d_sym.getSection(sect_index);
1419 const file_pos = sect.offset + atom.off;
14971420 try pwriteDbgInfoNops(
14981421 d_sym.file,
14991422 file_pos,
......@@ -1505,7 +1428,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
15051428 },
15061429
15071430 .wasm => {
1508 const wasm_file = file.cast(File.Wasm).?;
1431 const wasm_file = self.bin_file.cast(File.Wasm).?;
15091432 const info_atom = wasm_file.debug_info_atom.?;
15101433 const debug_info = &info_atom.code;
15111434 const segment_size = debug_info.items.len;
......@@ -1535,7 +1458,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
15351458 }
15361459}
15371460
1538pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl) !void {
1461pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void {
15391462 const tracy = trace(@src());
15401463 defer tracy.end();
15411464
......@@ -1549,22 +1472,21 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl)
15491472 var data: [4]u8 = undefined;
15501473 leb128.writeUnsignedFixed(4, &data, line);
15511474
1552 switch (self.tag) {
1475 switch (self.bin_file.tag) {
15531476 .elf => {
1554 const elf_file = file.cast(File.Elf).?;
1477 const elf_file = self.bin_file.cast(File.Elf).?;
15551478 const shdr = elf_file.sections.items[elf_file.debug_line_section_index.?];
15561479 const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff();
15571480 try elf_file.base.file.?.pwriteAll(&data, file_pos);
15581481 },
15591482 .macho => {
1560 const macho_file = file.cast(File.MachO).?;
1561 const d_sym = macho_file.d_sym.?;
1562 const sect = d_sym.sections.items[d_sym.debug_line_section_index.?];
1483 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1484 const sect = d_sym.getSection(d_sym.debug_line_section_index.?);
15631485 const file_pos = sect.offset + decl.fn_link.macho.off + self.getRelocDbgLineOff();
15641486 try d_sym.file.pwriteAll(&data, file_pos);
15651487 },
15661488 .wasm => {
1567 const wasm_file = file.cast(File.Wasm).?;
1489 const wasm_file = self.bin_file.cast(File.Wasm).?;
15681490 const offset = decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff();
15691491 const atom = wasm_file.debug_line_atom.?;
15701492 mem.copy(u8, atom.code.items[offset..], &data);
......@@ -1601,7 +1523,7 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void {
16011523 // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing
16021524 // is desired for both.
16031525 const gpa = self.allocator;
1604 const fn_link = switch (self.tag) {
1526 const fn_link = switch (self.bin_file.tag) {
16051527 .elf => &decl.fn_link.elf,
16061528 .macho => &decl.fn_link.macho,
16071529 .wasm => &decl.fn_link.wasm.src_fn,
......@@ -1629,7 +1551,7 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void {
16291551 }
16301552}
16311553
1632pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
1554pub fn writeDbgAbbrev(self: *Dwarf) !void {
16331555 // These are LEB encoded but since the values are all less than 127
16341556 // we can simply append these bytes.
16351557 const abbrev_buf = [_]u8{
......@@ -1763,46 +1685,25 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
17631685 self.abbrev_table_offset = abbrev_offset;
17641686
17651687 const needed_size = abbrev_buf.len;
1766 switch (self.tag) {
1688 switch (self.bin_file.tag) {
17671689 .elf => {
1768 const elf_file = file.cast(File.Elf).?;
1769 const debug_abbrev_sect = &elf_file.sections.items[elf_file.debug_abbrev_section_index.?];
1770 const allocated_size = elf_file.allocatedSize(debug_abbrev_sect.sh_offset);
1771 if (needed_size > allocated_size) {
1772 debug_abbrev_sect.sh_size = 0; // free the space
1773 debug_abbrev_sect.sh_offset = elf_file.findFreeSpace(needed_size, 1);
1774 }
1775 debug_abbrev_sect.sh_size = needed_size;
1776 log.debug(".debug_abbrev start=0x{x} end=0x{x}", .{
1777 debug_abbrev_sect.sh_offset,
1778 debug_abbrev_sect.sh_offset + needed_size,
1779 });
1780
1690 const elf_file = self.bin_file.cast(File.Elf).?;
1691 const shdr_index = elf_file.debug_abbrev_section_index.?;
1692 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, false);
1693 const debug_abbrev_sect = elf_file.sections.items[shdr_index];
17811694 const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset;
17821695 try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
17831696 },
17841697 .macho => {
1785 const macho_file = file.cast(File.MachO).?;
1786 const d_sym = &macho_file.d_sym.?;
1787 const dwarf_segment = d_sym.segments.items[d_sym.dwarf_segment_cmd_index.?];
1788 const debug_abbrev_sect = &d_sym.sections.items[d_sym.debug_abbrev_section_index.?];
1789 const allocated_size = d_sym.allocatedSize(debug_abbrev_sect.offset);
1790 if (needed_size > allocated_size) {
1791 debug_abbrev_sect.size = 0; // free the space
1792 const offset = d_sym.findFreeSpace(needed_size, 1);
1793 debug_abbrev_sect.offset = @intCast(u32, offset);
1794 debug_abbrev_sect.addr = dwarf_segment.vmaddr + offset - dwarf_segment.fileoff;
1795 }
1796 debug_abbrev_sect.size = needed_size;
1797 log.debug("__debug_abbrev start=0x{x} end=0x{x}", .{
1798 debug_abbrev_sect.offset,
1799 debug_abbrev_sect.offset + needed_size,
1800 });
1801 const file_pos = debug_abbrev_sect.offset + abbrev_offset;
1698 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1699 const sect_index = d_sym.debug_abbrev_section_index.?;
1700 try d_sym.growSection(sect_index, needed_size, false);
1701 const sect = d_sym.getSection(sect_index);
1702 const file_pos = sect.offset + abbrev_offset;
18021703 try d_sym.file.pwriteAll(&abbrev_buf, file_pos);
18031704 },
18041705 .wasm => {
1805 const wasm_file = file.cast(File.Wasm).?;
1706 const wasm_file = self.bin_file.cast(File.Wasm).?;
18061707 const debug_abbrev = &wasm_file.debug_abbrev_atom.?.code;
18071708 try debug_abbrev.resize(wasm_file.base.allocator, needed_size);
18081709 mem.copy(u8, debug_abbrev.items, &abbrev_buf);
......@@ -1816,7 +1717,7 @@ fn dbgInfoHeaderBytes(self: *Dwarf) usize {
18161717 return 120;
18171718}
18181719
1819pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u64, high_pc: u64) !void {
1720pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u64) !void {
18201721 // If this value is null it means there is an error in the module;
18211722 // leave debug_info_header_dirty=true.
18221723 const first_dbg_info_off = self.getDebugInfoOff() orelse return;
......@@ -1828,7 +1729,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
18281729 defer di_buf.deinit();
18291730
18301731 const target_endian = self.target.cpu.arch.endian();
1831 const init_len_size: usize = if (self.tag == .macho)
1732 const init_len_size: usize = if (self.bin_file.tag == .macho)
18321733 4
18331734 else switch (self.ptr_width) {
18341735 .p32 => @as(usize, 4),
......@@ -1842,7 +1743,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
18421743 // +1 for the final 0 that ends the compilation unit children.
18431744 const dbg_info_end = self.getDebugInfoEnd().? + 1;
18441745 const init_len = dbg_info_end - after_init_len;
1845 if (self.tag == .macho) {
1746 if (self.bin_file.tag == .macho) {
18461747 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len));
18471748 } else switch (self.ptr_width) {
18481749 .p32 => {
......@@ -1855,7 +1756,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
18551756 }
18561757 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version
18571758 const abbrev_offset = self.abbrev_table_offset.?;
1858 if (self.tag == .macho) {
1759 if (self.bin_file.tag == .macho) {
18591760 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, abbrev_offset));
18601761 di_buf.appendAssumeCapacity(8); // address size
18611762 } else switch (self.ptr_width) {
......@@ -1870,11 +1771,12 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
18701771 }
18711772 // Write the form for the compile unit, which must match the abbrev table above.
18721773 const name_strp = try self.makeString(module.root_pkg.root_src_path);
1873 const comp_dir_strp = try self.makeString(module.root_pkg.root_src_directory.path orelse ".");
1774 const compile_unit_dir = self.getCompDir(module);
1775 const comp_dir_strp = try self.makeString(compile_unit_dir);
18741776 const producer_strp = try self.makeString(link.producer_string);
18751777
18761778 di_buf.appendAssumeCapacity(@enumToInt(AbbrevKind.compile_unit));
1877 if (self.tag == .macho) {
1779 if (self.bin_file.tag == .macho) {
18781780 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // DW.AT.stmt_list, DW.FORM.sec_offset
18791781 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), low_pc);
18801782 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), high_pc);
......@@ -1899,22 +1801,21 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
18991801 @panic("TODO: handle .debug_info header exceeding its padding");
19001802 }
19011803 const jmp_amt = first_dbg_info_off - di_buf.items.len;
1902 switch (self.tag) {
1804 switch (self.bin_file.tag) {
19031805 .elf => {
1904 const elf_file = file.cast(File.Elf).?;
1806 const elf_file = self.bin_file.cast(File.Elf).?;
19051807 const debug_info_sect = elf_file.sections.items[elf_file.debug_info_section_index.?];
19061808 const file_pos = debug_info_sect.sh_offset;
19071809 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
19081810 },
19091811 .macho => {
1910 const macho_file = file.cast(File.MachO).?;
1911 const d_sym = &macho_file.d_sym.?;
1912 const debug_info_sect = d_sym.sections.items[d_sym.debug_info_section_index.?];
1812 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1813 const debug_info_sect = d_sym.getSection(d_sym.debug_info_section_index.?);
19131814 const file_pos = debug_info_sect.offset;
19141815 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false);
19151816 },
19161817 .wasm => {
1917 const wasm_file = file.cast(File.Wasm).?;
1818 const wasm_file = self.bin_file.cast(File.Wasm).?;
19181819 const debug_info = &wasm_file.debug_info_atom.?.code;
19191820 try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);
19201821 },
......@@ -1922,6 +1823,21 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
19221823 }
19231824}
19241825
1826fn getCompDir(self: Dwarf, module: *Module) []const u8 {
1827 // For macOS stack traces, we want to avoid having to parse the compilation unit debug
1828 // info. As long as each debug info file has a path independent of the compilation unit
1829 // directory (DW_AT_comp_dir), then we never have to look at the compilation unit debug
1830 // info. If we provide an absolute path to LLVM here for the compilation unit debug
1831 // info, LLVM will emit DWARF info that depends on DW_AT_comp_dir. To avoid this, we
1832 // pass "." for the compilation unit directory. This forces each debug file to have a
1833 // directory rather than be relative to DW_AT_comp_dir. According to DWARF 5, debug
1834 // files will no longer reference DW_AT_comp_dir, for the purpose of being able to
1835 // support the common practice of stripping all but the line number sections from an
1836 // executable.
1837 if (self.bin_file.tag == .macho) return ".";
1838 return module.root_pkg.root_src_directory.path orelse ".";
1839}
1840
19251841fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) void {
19261842 const target_endian = self.target.cpu.arch.endian();
19271843 switch (self.ptr_width) {
......@@ -2144,9 +2060,9 @@ fn writeDbgInfoNopsToArrayList(
21442060 }
21452061}
21462062
2147pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {
2063pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
21482064 const target_endian = self.target.cpu.arch.endian();
2149 const init_len_size: usize = if (self.tag == .macho)
2065 const init_len_size: usize = if (self.bin_file.tag == .macho)
21502066 4
21512067 else switch (self.ptr_width) {
21522068 .p32 => @as(usize, 4),
......@@ -2168,7 +2084,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {
21682084 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version
21692085 // When more than one compilation unit is supported, this will be the offset to it.
21702086 // For now it is always at offset 0 in .debug_info.
2171 if (self.tag == .macho) {
2087 if (self.bin_file.tag == .macho) {
21722088 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // __debug_info offset
21732089 } else {
21742090 self.writeAddrAssumeCapacity(&di_buf, 0); // .debug_info offset
......@@ -2191,7 +2107,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {
21912107
21922108 // Go back and populate the initial length.
21932109 const init_len = di_buf.items.len - after_init_len;
2194 if (self.tag == .macho) {
2110 if (self.bin_file.tag == .macho) {
21952111 mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len));
21962112 } else switch (self.ptr_width) {
21972113 .p32 => {
......@@ -2205,46 +2121,26 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {
22052121 },
22062122 }
22072123
2208 const needed_size = di_buf.items.len;
2209 switch (self.tag) {
2124 const needed_size = @intCast(u32, di_buf.items.len);
2125 switch (self.bin_file.tag) {
22102126 .elf => {
2211 const elf_file = file.cast(File.Elf).?;
2212 const debug_aranges_sect = &elf_file.sections.items[elf_file.debug_aranges_section_index.?];
2213 const allocated_size = elf_file.allocatedSize(debug_aranges_sect.sh_offset);
2214 if (needed_size > allocated_size) {
2215 debug_aranges_sect.sh_size = 0; // free the space
2216 debug_aranges_sect.sh_offset = elf_file.findFreeSpace(needed_size, 16);
2217 }
2218 debug_aranges_sect.sh_size = needed_size;
2219 log.debug(".debug_aranges start=0x{x} end=0x{x}", .{
2220 debug_aranges_sect.sh_offset,
2221 debug_aranges_sect.sh_offset + needed_size,
2222 });
2127 const elf_file = self.bin_file.cast(File.Elf).?;
2128 const shdr_index = elf_file.debug_aranges_section_index.?;
2129 try elf_file.growNonAllocSection(shdr_index, needed_size, 16, false);
2130 const debug_aranges_sect = elf_file.sections.items[shdr_index];
22232131 const file_pos = debug_aranges_sect.sh_offset;
22242132 try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);
22252133 },
22262134 .macho => {
2227 const macho_file = file.cast(File.MachO).?;
2228 const d_sym = &macho_file.d_sym.?;
2229 const dwarf_seg = d_sym.segments.items[d_sym.dwarf_segment_cmd_index.?];
2230 const debug_aranges_sect = &d_sym.sections.items[d_sym.debug_aranges_section_index.?];
2231 const allocated_size = d_sym.allocatedSize(debug_aranges_sect.offset);
2232 if (needed_size > allocated_size) {
2233 debug_aranges_sect.size = 0; // free the space
2234 const new_offset = d_sym.findFreeSpace(needed_size, 16);
2235 debug_aranges_sect.addr = dwarf_seg.vmaddr + new_offset - dwarf_seg.fileoff;
2236 debug_aranges_sect.offset = @intCast(u32, new_offset);
2237 }
2238 debug_aranges_sect.size = needed_size;
2239 log.debug("__debug_aranges start=0x{x} end=0x{x}", .{
2240 debug_aranges_sect.offset,
2241 debug_aranges_sect.offset + needed_size,
2242 });
2243 const file_pos = debug_aranges_sect.offset;
2135 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
2136 const sect_index = d_sym.debug_aranges_section_index.?;
2137 try d_sym.growSection(sect_index, needed_size, false);
2138 const sect = d_sym.getSection(sect_index);
2139 const file_pos = sect.offset;
22442140 try d_sym.file.pwriteAll(di_buf.items, file_pos);
22452141 },
22462142 .wasm => {
2247 const wasm_file = file.cast(File.Wasm).?;
2143 const wasm_file = self.bin_file.cast(File.Wasm).?;
22482144 const debug_ranges = &wasm_file.debug_ranges_atom.?.code;
22492145 try debug_ranges.resize(wasm_file.base.allocator, needed_size);
22502146 mem.copy(u8, debug_ranges.items, di_buf.items);
......@@ -2253,10 +2149,12 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {
22532149 }
22542150}
22552151
2256pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {
2152pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {
2153 const gpa = self.allocator;
2154
22572155 const ptr_width_bytes: u8 = self.ptrWidthBytes();
22582156 const target_endian = self.target.cpu.arch.endian();
2259 const init_len_size: usize = if (self.tag == .macho)
2157 const init_len_size: usize = if (self.bin_file.tag == .macho)
22602158 4
22612159 else switch (self.ptr_width) {
22622160 .p32 => @as(usize, 4),
......@@ -2264,29 +2162,37 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {
22642162 };
22652163
22662164 const dbg_line_prg_off = self.getDebugLineProgramOff() orelse return;
2267 const dbg_line_prg_end = self.getDebugLineProgramEnd().?;
2268 assert(dbg_line_prg_end != 0);
2165 assert(self.getDebugLineProgramEnd().? != 0);
2166
2167 // Convert all input DI files into a set of include dirs and file names.
2168 var arena = std.heap.ArenaAllocator.init(gpa);
2169 defer arena.deinit();
2170 const paths = try self.genIncludeDirsAndFileNames(arena.allocator(), module);
22692171
22702172 // The size of this header is variable, depending on the number of directories,
22712173 // files, and padding. We have a function to compute the upper bound size, however,
22722174 // because it's needed for determining where to put the offset of the first `SrcFn`.
2273 const needed_bytes = self.dbgLineNeededHeaderBytes(module);
2274 var di_buf = try std.ArrayList(u8).initCapacity(self.allocator, needed_bytes);
2175 const needed_bytes = self.dbgLineNeededHeaderBytes(paths.dirs, paths.files);
2176 var di_buf = try std.ArrayList(u8).initCapacity(gpa, needed_bytes);
22752177 defer di_buf.deinit();
22762178
22772179 // initial length - length of the .debug_line contribution for this compilation unit,
22782180 // not including the initial length itself.
2279 const after_init_len = di_buf.items.len + init_len_size;
2280 const init_len = dbg_line_prg_end - after_init_len;
2281 if (self.tag == .macho) {
2282 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len));
2283 } else switch (self.ptr_width) {
2284 .p32 => {
2285 mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian);
2181 // We will backpatch this value later so just remember where we need to write it.
2182 const before_init_len = di_buf.items.len;
2183
2184 switch (self.bin_file.tag) {
2185 .macho => {
2186 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, 0));
22862187 },
2287 .p64 => {
2288 di_buf.appendNTimesAssumeCapacity(0xff, 4);
2289 mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian);
2188 else => switch (self.ptr_width) {
2189 .p32 => {
2190 mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, 0), target_endian);
2191 },
2192 .p64 => {
2193 di_buf.appendNTimesAssumeCapacity(0xff, 4);
2194 mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), @as(u64, 0), target_endian);
2195 },
22902196 },
22912197 }
22922198
......@@ -2297,7 +2203,12 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {
22972203 // Therefore we rely on the NOP jump at the beginning of the Line Number Program for
22982204 // padding rather than this field.
22992205 const before_header_len = di_buf.items.len;
2300 di_buf.items.len += if (self.tag == .macho) @sizeOf(u32) else ptr_width_bytes; // We will come back and write this.
2206
2207 di_buf.items.len += switch (self.bin_file.tag) { // We will come back and write this.
2208 .macho => @sizeOf(u32),
2209 else => ptr_width_bytes,
2210 };
2211
23012212 const after_header_len = di_buf.items.len;
23022213
23032214 const opcode_base = DW.LNS.set_isa + 1;
......@@ -2323,52 +2234,133 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {
23232234 0, // `DW.LNS.set_prologue_end`
23242235 0, // `DW.LNS.set_epilogue_begin`
23252236 1, // `DW.LNS.set_isa`
2326 0, // include_directories (none except the compilation unit cwd)
2327 });
2328 // file_names[0]
2329 di_buf.appendSliceAssumeCapacity(module.root_pkg.root_src_path); // relative path name
2330 di_buf.appendSliceAssumeCapacity(&[_]u8{
2331 0, // null byte for the relative path name
2332 0, // directory_index
2333 0, // mtime (TODO supply this)
2334 0, // file size bytes (TODO supply this)
2335 0, // file_names sentinel
23362237 });
23372238
2239 for (paths.dirs) |dir, i| {
2240 log.debug("adding new include dir at {d} of '{s}'", .{ i + 1, dir });
2241 di_buf.appendSliceAssumeCapacity(dir);
2242 di_buf.appendAssumeCapacity(0);
2243 }
2244 di_buf.appendAssumeCapacity(0); // include directories sentinel
2245
2246 for (paths.files) |file, i| {
2247 const dir_index = paths.files_dirs_indexes[i];
2248 log.debug("adding new file name at {d} of '{s}' referencing directory {d}", .{ i + 1, file, dir_index + 1 });
2249 di_buf.appendSliceAssumeCapacity(file);
2250 di_buf.appendSliceAssumeCapacity(&[_]u8{
2251 0, // null byte for the relative path name
2252 @intCast(u8, dir_index), // directory_index
2253 0, // mtime (TODO supply this)
2254 0, // file size bytes (TODO supply this)
2255 });
2256 }
2257 di_buf.appendAssumeCapacity(0); // file names sentinel
2258
23382259 const header_len = di_buf.items.len - after_header_len;
2339 if (self.tag == .macho) {
2340 mem.writeIntLittle(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len));
2341 } else switch (self.ptr_width) {
2342 .p32 => {
2343 mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len), target_endian);
2260
2261 switch (self.bin_file.tag) {
2262 .macho => {
2263 mem.writeIntLittle(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len));
23442264 },
2345 .p64 => {
2346 mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian);
2265 else => switch (self.ptr_width) {
2266 .p32 => {
2267 mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len), target_endian);
2268 },
2269 .p64 => {
2270 mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian);
2271 },
23472272 },
23482273 }
23492274
2350 // We use NOPs because consumers empirically do not respect the header length field.
2275 assert(needed_bytes == di_buf.items.len);
2276
23512277 if (di_buf.items.len > dbg_line_prg_off) {
2352 // Move the first N files to the end to make more padding for the header.
2353 @panic("TODO: handle .debug_line header exceeding its padding");
2278 const needed_with_padding = padToIdeal(needed_bytes);
2279 const delta = needed_with_padding - dbg_line_prg_off;
2280
2281 var src_fn = self.dbg_line_fn_first.?;
2282 const last_fn = self.dbg_line_fn_last.?;
2283
2284 var buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - src_fn.off);
2285 defer gpa.free(buffer);
2286
2287 switch (self.bin_file.tag) {
2288 .elf => {
2289 const elf_file = self.bin_file.cast(File.Elf).?;
2290 const shdr_index = elf_file.debug_line_section_index.?;
2291 const needed_size = elf_file.sections.items[shdr_index].sh_size + delta;
2292 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
2293 const file_pos = elf_file.sections.items[shdr_index].sh_offset + src_fn.off;
2294
2295 const amt = try elf_file.base.file.?.preadAll(buffer, file_pos);
2296 if (amt != buffer.len) return error.InputOutput;
2297
2298 try elf_file.base.file.?.pwriteAll(buffer, file_pos + delta);
2299 },
2300 .macho => {
2301 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
2302 const sect_index = d_sym.debug_line_section_index.?;
2303 const needed_size = @intCast(u32, d_sym.getSection(sect_index).size + delta);
2304 try d_sym.growSection(sect_index, needed_size, true);
2305 const file_pos = d_sym.getSection(sect_index).offset + src_fn.off;
2306
2307 const amt = try d_sym.file.preadAll(buffer, file_pos);
2308 if (amt != buffer.len) return error.InputOutput;
2309
2310 try d_sym.file.pwriteAll(buffer, file_pos + delta);
2311 },
2312 .wasm => {
2313 const wasm_file = self.bin_file.cast(File.Wasm).?;
2314 const debug_line = &wasm_file.debug_line_atom.?.code;
2315 mem.copy(u8, buffer, debug_line.items[src_fn.off..]);
2316 try debug_line.resize(self.allocator, debug_line.items.len + delta);
2317 mem.copy(u8, debug_line.items[src_fn.off + delta ..], buffer);
2318 },
2319 else => unreachable,
2320 }
2321
2322 while (true) {
2323 src_fn.off += delta;
2324
2325 if (src_fn.next) |next| {
2326 src_fn = next;
2327 } else break;
2328 }
2329 }
2330
2331 // Backpatch actual length of the debug line program
2332 const init_len = self.getDebugLineProgramEnd().? - before_init_len - init_len_size;
2333 switch (self.bin_file.tag) {
2334 .macho => {
2335 mem.writeIntLittle(u32, di_buf.items[before_init_len..][0..4], @intCast(u32, init_len));
2336 },
2337 else => switch (self.ptr_width) {
2338 .p32 => {
2339 mem.writeInt(u32, di_buf.items[before_init_len..][0..4], @intCast(u32, init_len), target_endian);
2340 },
2341 .p64 => {
2342 mem.writeInt(u64, di_buf.items[before_init_len + 4 ..][0..8], init_len, target_endian);
2343 },
2344 },
23542345 }
2355 const jmp_amt = dbg_line_prg_off - di_buf.items.len;
2356 switch (self.tag) {
2346
2347 // We use NOPs because consumers empirically do not respect the header length field.
2348 const jmp_amt = self.getDebugLineProgramOff().? - di_buf.items.len;
2349 switch (self.bin_file.tag) {
23572350 .elf => {
2358 const elf_file = file.cast(File.Elf).?;
2351 const elf_file = self.bin_file.cast(File.Elf).?;
23592352 const debug_line_sect = elf_file.sections.items[elf_file.debug_line_section_index.?];
23602353 const file_pos = debug_line_sect.sh_offset;
23612354 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
23622355 },
23632356 .macho => {
2364 const macho_file = file.cast(File.MachO).?;
2365 const d_sym = &macho_file.d_sym.?;
2366 const debug_line_sect = d_sym.sections.items[d_sym.debug_line_section_index.?];
2357 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
2358 const debug_line_sect = d_sym.getSection(d_sym.debug_line_section_index.?);
23672359 const file_pos = debug_line_sect.offset;
23682360 try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt);
23692361 },
23702362 .wasm => {
2371 const wasm_file = file.cast(File.Wasm).?;
2363 const wasm_file = self.bin_file.cast(File.Wasm).?;
23722364 const debug_line = wasm_file.debug_line_atom.?.code;
23732365 writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);
23742366 },
......@@ -2404,19 +2396,32 @@ fn ptrWidthBytes(self: Dwarf) u8 {
24042396 };
24052397}
24062398
2407fn dbgLineNeededHeaderBytes(self: Dwarf, module: *Module) u32 {
2408 _ = self;
2409 const directory_entry_format_count = 1;
2410 const file_name_entry_format_count = 1;
2411 const directory_count = 1;
2412 const file_name_count = 1;
2413 const root_src_dir_path_len = if (module.root_pkg.root_src_directory.path) |p| p.len else 1; // "."
2414 return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 +
2415 directory_count * 8 + file_name_count * 8 +
2416 // These are encoded as DW.FORM.string rather than DW.FORM.strp as we would like
2417 // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly.
2418 root_src_dir_path_len +
2419 module.root_pkg.root_src_path.len);
2399fn dbgLineNeededHeaderBytes(self: Dwarf, dirs: []const []const u8, files: []const []const u8) u32 {
2400 var size = switch (self.bin_file.tag) { // length field
2401 .macho => @sizeOf(u32),
2402 else => switch (self.ptr_width) {
2403 .p32 => @as(usize, @sizeOf(u32)),
2404 .p64 => @sizeOf(u32) + @sizeOf(u64),
2405 },
2406 };
2407 size += @sizeOf(u16); // version field
2408 size += switch (self.bin_file.tag) { // offset to end-of-header
2409 .macho => @sizeOf(u32),
2410 else => self.ptrWidthBytes(),
2411 };
2412 size += 18; // opcodes
2413
2414 for (dirs) |dir| { // include dirs
2415 size += dir.len + 1;
2416 }
2417 size += 1; // include dirs sentinel
2418
2419 for (files) |file| { // file names
2420 size += file.len + 1 + 1 + 1 + 1;
2421 }
2422 size += 1; // file names sentinel
2423
2424 return @intCast(u32, size);
24202425}
24212426
24222427/// The reloc offset for the line offset of a function from the previous function's line.
......@@ -2448,7 +2453,7 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
24482453 std.math.maxInt(@TypeOf(actual_size));
24492454}
24502455
2451pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {
2456pub fn flushModule(self: *Dwarf, module: *Module) !void {
24522457 if (self.global_abbrev_relocs.items.len > 0) {
24532458 const gpa = self.allocator;
24542459 var arena_alloc = std.heap.ArenaAllocator.init(gpa);
......@@ -2479,21 +2484,20 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {
24792484
24802485 try self.managed_atoms.append(gpa, atom);
24812486 log.debug("updateDeclDebugInfoAllocation in flushModule", .{});
2482 try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));
2487 try self.updateDeclDebugInfoAllocation(atom, @intCast(u32, dbg_info_buffer.items.len));
24832488 log.debug("writeDeclDebugInfo in flushModule", .{});
2484 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
2489 try self.writeDeclDebugInfo(atom, dbg_info_buffer.items);
24852490
24862491 const file_pos = blk: {
2487 switch (self.tag) {
2492 switch (self.bin_file.tag) {
24882493 .elf => {
2489 const elf_file = file.cast(File.Elf).?;
2494 const elf_file = self.bin_file.cast(File.Elf).?;
24902495 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];
24912496 break :blk debug_info_sect.sh_offset;
24922497 },
24932498 .macho => {
2494 const macho_file = file.cast(File.MachO).?;
2495 const d_sym = &macho_file.d_sym.?;
2496 const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?];
2499 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
2500 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
24972501 break :blk debug_info_sect.offset;
24982502 },
24992503 // for wasm, the offset is always 0 as we write to memory first
......@@ -2506,18 +2510,17 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {
25062510 mem.writeInt(u32, &buf, atom.off, self.target.cpu.arch.endian());
25072511
25082512 while (self.global_abbrev_relocs.popOrNull()) |reloc| {
2509 switch (self.tag) {
2513 switch (self.bin_file.tag) {
25102514 .elf => {
2511 const elf_file = file.cast(File.Elf).?;
2515 const elf_file = self.bin_file.cast(File.Elf).?;
25122516 try elf_file.base.file.?.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset);
25132517 },
25142518 .macho => {
2515 const macho_file = file.cast(File.MachO).?;
2516 const d_sym = &macho_file.d_sym.?;
2519 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
25172520 try d_sym.file.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset);
25182521 },
25192522 .wasm => {
2520 const wasm_file = file.cast(File.Wasm).?;
2523 const wasm_file = self.bin_file.cast(File.Wasm).?;
25212524 const debug_info = wasm_file.debug_info_atom.?.code;
25222525 mem.copy(u8, debug_info.items[reloc.atom.off + reloc.offset ..], &buf);
25232526 },
......@@ -2527,6 +2530,68 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {
25272530 }
25282531}
25292532
2533fn addDIFile(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) !u28 {
2534 const decl = mod.declPtr(decl_index);
2535 const file_scope = decl.getFileScope();
2536 const gop = try self.di_files.getOrPut(self.allocator, file_scope);
2537 if (!gop.found_existing) {
2538 switch (self.bin_file.tag) {
2539 .elf => {
2540 const elf_file = self.bin_file.cast(File.Elf).?;
2541 elf_file.markDirty(elf_file.debug_line_section_index.?, null);
2542 },
2543 .macho => {
2544 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
2545 d_sym.markDirty(d_sym.debug_line_section_index.?);
2546 },
2547 .wasm => {},
2548 else => unreachable,
2549 }
2550 }
2551 return @intCast(u28, gop.index + 1);
2552}
2553
2554fn genIncludeDirsAndFileNames(self: *Dwarf, arena: Allocator, module: *Module) !struct {
2555 dirs: []const []const u8,
2556 files: []const []const u8,
2557 files_dirs_indexes: []u28,
2558} {
2559 var dirs = std.StringArrayHashMap(void).init(arena);
2560 try dirs.ensureTotalCapacity(self.di_files.count());
2561
2562 var files = std.ArrayList([]const u8).init(arena);
2563 try files.ensureTotalCapacityPrecise(self.di_files.count());
2564
2565 var files_dir_indexes = std.ArrayList(u28).init(arena);
2566 try files_dir_indexes.ensureTotalCapacity(self.di_files.count());
2567
2568 const comp_dir = self.getCompDir(module);
2569
2570 for (self.di_files.keys()) |dif| {
2571 const full_path = try dif.fullPath(arena);
2572 const dir_path = std.fs.path.dirname(full_path) orelse ".";
2573 const sub_file_path = std.fs.path.basename(full_path);
2574
2575 const dir_index: u28 = blk: {
2576 const actual_dir_path = if (mem.indexOf(u8, dir_path, comp_dir)) |_| inner: {
2577 if (comp_dir.len == dir_path.len) break :blk 0;
2578 break :inner dir_path[comp_dir.len + 1 ..];
2579 } else dir_path;
2580 const dirs_gop = dirs.getOrPutAssumeCapacity(actual_dir_path);
2581 break :blk @intCast(u28, dirs_gop.index + 1);
2582 };
2583
2584 files_dir_indexes.appendAssumeCapacity(dir_index);
2585 files.appendAssumeCapacity(sub_file_path);
2586 }
2587
2588 return .{
2589 .dirs = dirs.keys(),
2590 .files = files.items,
2591 .files_dirs_indexes = files_dir_indexes.items,
2592 };
2593}
2594
25302595fn addDbgInfoErrorSet(
25312596 arena: Allocator,
25322597 module: *Module,
src/link/Elf.zig+118-113
......@@ -312,7 +312,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
312312 };
313313
314314 var dwarf: ?Dwarf = if (!options.strip and options.module != null)
315 Dwarf.init(gpa, .elf, options.target)
315 Dwarf.init(gpa, &self.base, options.target)
316316 else
317317 null;
318318
......@@ -931,6 +931,104 @@ pub fn populateMissingMetadata(self: *Elf) !void {
931931 }
932932}
933933
934fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u64) !void {
935 // TODO Also detect virtual address collisions.
936 const shdr = &self.sections.items[shdr_index];
937 const phdr = &self.program_headers.items[phdr_index];
938
939 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
940 // Must move the entire section.
941 const new_offset = self.findFreeSpace(needed_size, self.page_size);
942 const existing_size = if (self.atoms.get(phdr_index)) |last| blk: {
943 const sym = self.local_symbols.items[last.local_sym_index];
944 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;
945 } else if (shdr_index == self.got_section_index.?) blk: {
946 break :blk shdr.sh_size;
947 } else 0;
948 shdr.sh_size = 0;
949
950 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
951 self.getString(shdr.sh_name),
952 new_offset,
953 new_offset + existing_size,
954 });
955
956 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, existing_size);
957 if (amt != existing_size) return error.InputOutput;
958
959 shdr.sh_offset = new_offset;
960 phdr.p_offset = new_offset;
961 }
962
963 shdr.sh_size = needed_size;
964 phdr.p_memsz = needed_size;
965 phdr.p_filesz = needed_size;
966
967 self.markDirty(shdr_index, phdr_index);
968}
969
970pub fn growNonAllocSection(
971 self: *Elf,
972 shdr_index: u16,
973 needed_size: u64,
974 min_alignment: u32,
975 requires_file_copy: bool,
976) !void {
977 const shdr = &self.sections.items[shdr_index];
978
979 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
980 const existing_size = if (self.symtab_section_index.? == shdr_index) blk: {
981 const sym_size: u64 = switch (self.ptr_width) {
982 .p32 => @sizeOf(elf.Elf32_Sym),
983 .p64 => @sizeOf(elf.Elf64_Sym),
984 };
985 break :blk @as(u64, shdr.sh_info) * sym_size;
986 } else shdr.sh_size;
987 shdr.sh_size = 0;
988 // Move all the symbols to a new file location.
989 const new_offset = self.findFreeSpace(needed_size, min_alignment);
990 log.debug("moving '{s}' from 0x{x} to 0x{x}", .{ self.getString(shdr.sh_name), shdr.sh_offset, new_offset });
991
992 if (requires_file_copy) {
993 const amt = try self.base.file.?.copyRangeAll(
994 shdr.sh_offset,
995 self.base.file.?,
996 new_offset,
997 existing_size,
998 );
999 if (amt != existing_size) return error.InputOutput;
1000 }
1001
1002 shdr.sh_offset = new_offset;
1003 }
1004
1005 shdr.sh_size = needed_size; // anticipating adding the global symbols later
1006
1007 self.markDirty(shdr_index, null);
1008}
1009
1010pub fn markDirty(self: *Elf, shdr_index: u16, phdr_index: ?u16) void {
1011 self.shdr_table_dirty = true; // TODO look into only writing one section
1012
1013 if (phdr_index) |_| {
1014 self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
1015 }
1016
1017 if (self.dwarf) |_| {
1018 if (self.debug_info_section_index.? == shdr_index) {
1019 self.debug_info_header_dirty = true;
1020 } else if (self.debug_line_section_index.? == shdr_index) {
1021 self.debug_line_header_dirty = true;
1022 } else if (self.debug_abbrev_section_index.? == shdr_index) {
1023 self.debug_abbrev_section_dirty = true;
1024 } else if (self.debug_str_section_index.? == shdr_index) {
1025 self.debug_strtab_dirty = true;
1026 } else if (self.debug_aranges_section_index.? == shdr_index) {
1027 self.debug_aranges_section_dirty = true;
1028 }
1029 }
1030}
1031
9341032pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
9351033 if (self.base.options.emit == null) {
9361034 if (build_options.have_llvm) {
......@@ -972,7 +1070,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
9721070 const foreign_endian = target_endian != builtin.cpu.arch.endian();
9731071
9741072 if (self.dwarf) |*dw| {
975 try dw.flushModule(&self.base, module);
1073 try dw.flushModule(module);
9761074 }
9771075
9781076 {
......@@ -1020,7 +1118,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10201118
10211119 if (self.dwarf) |*dw| {
10221120 if (self.debug_abbrev_section_dirty) {
1023 try dw.writeDbgAbbrev(&self.base);
1121 try dw.writeDbgAbbrev();
10241122 if (!self.shdr_table_dirty) {
10251123 // Then it won't get written with the others and we need to do it.
10261124 try self.writeSectHeader(self.debug_abbrev_section_index.?);
......@@ -1034,7 +1132,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10341132 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
10351133 const low_pc = text_phdr.p_vaddr;
10361134 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
1037 try dw.writeDbgInfoHeader(&self.base, module, low_pc, high_pc);
1135 try dw.writeDbgInfoHeader(module, low_pc, high_pc);
10381136 self.debug_info_header_dirty = false;
10391137 }
10401138
......@@ -1042,7 +1140,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10421140 // Currently only one compilation unit is supported, so the address range is simply
10431141 // identical to the main program header virtual address and memory size.
10441142 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1045 try dw.writeDbgAranges(&self.base, text_phdr.p_vaddr, text_phdr.p_memsz);
1143 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
10461144 if (!self.shdr_table_dirty) {
10471145 // Then it won't get written with the others and we need to do it.
10481146 try self.writeSectHeader(self.debug_aranges_section_index.?);
......@@ -1051,7 +1149,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10511149 }
10521150
10531151 if (self.debug_line_header_dirty) {
1054 try dw.writeDbgLineHeader(&self.base, module);
1152 try dw.writeDbgLineHeader(module);
10551153 self.debug_line_header_dirty = false;
10561154 }
10571155 }
......@@ -1103,45 +1201,21 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11031201 }
11041202
11051203 {
1106 const shstrtab_sect = &self.sections.items[self.shstrtab_index.?];
1107 if (self.shstrtab_dirty or self.shstrtab.items.len != shstrtab_sect.sh_size) {
1108 const allocated_size = self.allocatedSize(shstrtab_sect.sh_offset);
1109 const needed_size = self.shstrtab.items.len;
1110
1111 if (needed_size > allocated_size) {
1112 shstrtab_sect.sh_size = 0; // free the space
1113 shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);
1114 }
1115 shstrtab_sect.sh_size = needed_size;
1116 log.debug("writing shstrtab start=0x{x} end=0x{x}", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
1117
1204 const shdr_index = self.shstrtab_index.?;
1205 if (self.shstrtab_dirty or self.shstrtab.items.len != self.sections.items[shdr_index].sh_size) {
1206 try self.growNonAllocSection(shdr_index, self.shstrtab.items.len, 1, false);
1207 const shstrtab_sect = self.sections.items[shdr_index];
11181208 try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
1119 if (!self.shdr_table_dirty) {
1120 // Then it won't get written with the others and we need to do it.
1121 try self.writeSectHeader(self.shstrtab_index.?);
1122 }
11231209 self.shstrtab_dirty = false;
11241210 }
11251211 }
11261212
11271213 if (self.dwarf) |dwarf| {
1128 const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?];
1129 if (self.debug_strtab_dirty or dwarf.strtab.items.len != debug_strtab_sect.sh_size) {
1130 const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset);
1131 const needed_size = dwarf.strtab.items.len;
1132
1133 if (needed_size > allocated_size) {
1134 debug_strtab_sect.sh_size = 0; // free the space
1135 debug_strtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);
1136 }
1137 debug_strtab_sect.sh_size = needed_size;
1138 log.debug("debug_strtab start=0x{x} end=0x{x}", .{ debug_strtab_sect.sh_offset, debug_strtab_sect.sh_offset + needed_size });
1139
1214 const shdr_index = self.debug_str_section_index.?;
1215 if (self.debug_strtab_dirty or dwarf.strtab.items.len != self.sections.items[shdr_index].sh_size) {
1216 try self.growNonAllocSection(shdr_index, dwarf.strtab.items.len, 1, false);
1217 const debug_strtab_sect = self.sections.items[shdr_index];
11401218 try self.base.file.?.pwriteAll(dwarf.strtab.items, debug_strtab_sect.sh_offset);
1141 if (!self.shdr_table_dirty) {
1142 // Then it won't get written with the others and we need to do it.
1143 try self.writeSectHeader(self.debug_str_section_index.?);
1144 }
11451219 self.debug_strtab_dirty = false;
11461220 }
11471221 }
......@@ -2134,27 +2208,10 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
21342208
21352209 const expand_text_section = block_placement == null or block_placement.?.next == null;
21362210 if (expand_text_section) {
2137 const text_capacity = self.allocatedSize(shdr.sh_offset);
21382211 const needed_size = (vaddr + new_block_size) - phdr.p_vaddr;
2139 if (needed_size > text_capacity) {
2140 // Must move the entire section.
2141 const new_offset = self.findFreeSpace(needed_size, self.page_size);
2142 const text_size = if (self.atoms.get(phdr_index)) |last| blk: {
2143 const sym = self.local_symbols.items[last.local_sym_index];
2144 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;
2145 } else 0;
2146 log.debug("new PT_LOAD file offset 0x{x} to 0x{x}", .{ new_offset, new_offset + text_size });
2147 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, text_size);
2148 if (amt != text_size) return error.InputOutput;
2149 shdr.sh_offset = new_offset;
2150 phdr.p_offset = new_offset;
2151 }
2212 try self.growAllocSection(shdr_index, phdr_index, needed_size);
21522213 _ = try self.atoms.put(self.base.allocator, phdr_index, text_block);
21532214
2154 shdr.sh_size = needed_size;
2155 phdr.p_memsz = needed_size;
2156 phdr.p_filesz = needed_size;
2157
21582215 if (self.dwarf) |_| {
21592216 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
21602217 // range of the compilation unit. When we expand the text section, this range changes,
......@@ -2165,9 +2222,6 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
21652222 // model each package as a different compilation unit.
21662223 self.debug_aranges_section_dirty = true;
21672224 }
2168
2169 self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
2170 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
21712225 }
21722226 shdr.sh_addralign = math.max(shdr.sh_addralign, alignment);
21732227
......@@ -2422,7 +2476,6 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
24222476 const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC);
24232477 if (decl_state) |*ds| {
24242478 try self.dwarf.?.commitDeclState(
2425 &self.base,
24262479 module,
24272480 decl_index,
24282481 local_sym.st_value,
......@@ -2499,7 +2552,6 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
24992552 const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT);
25002553 if (decl_state) |*ds| {
25012554 try self.dwarf.?.commitDeclState(
2502 &self.base,
25032555 module,
25042556 decl_index,
25052557 local_sym.st_value,
......@@ -2692,7 +2744,7 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl)
26922744
26932745 if (self.llvm_object) |_| return;
26942746 if (self.dwarf) |*dw| {
2695 try dw.updateDeclLineNumber(&self.base, decl);
2747 try dw.updateDeclLineNumber(decl);
26962748 }
26972749}
26982750
......@@ -2749,31 +2801,14 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
27492801}
27502802
27512803fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
2752 const shdr = &self.sections.items[self.got_section_index.?];
2753 const phdr = &self.program_headers.items[self.phdr_got_index.?];
27542804 const entry_size: u16 = self.archPtrWidthBytes();
27552805 if (self.offset_table_count_dirty) {
2756 // TODO Also detect virtual address collisions.
2757 const allocated_size = self.allocatedSize(shdr.sh_offset);
27582806 const needed_size = self.offset_table.items.len * entry_size;
2759 if (needed_size > allocated_size) {
2760 // Must move the entire got section.
2761 const new_offset = self.findFreeSpace(needed_size, self.page_size);
2762 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, shdr.sh_size);
2763 if (amt != shdr.sh_size) return error.InputOutput;
2764 shdr.sh_offset = new_offset;
2765 phdr.p_offset = new_offset;
2766 }
2767 shdr.sh_size = needed_size;
2768 phdr.p_memsz = needed_size;
2769 phdr.p_filesz = needed_size;
2770
2771 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
2772 self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
2773
2807 try self.growAllocSection(self.got_section_index.?, self.phdr_got_index.?, needed_size);
27742808 self.offset_table_count_dirty = false;
27752809 }
27762810 const endian = self.base.options.target.cpu.arch.endian();
2811 const shdr = &self.sections.items[self.got_section_index.?];
27772812 const off = shdr.sh_offset + @as(u64, entry_size) * index;
27782813 switch (entry_size) {
27792814 2 => {
......@@ -2812,23 +2847,8 @@ fn writeSymbol(self: *Elf, index: usize) !void {
28122847 .p64 => @alignOf(elf.Elf64_Sym),
28132848 };
28142849 const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size;
2815 if (needed_size > self.allocatedSize(syms_sect.sh_offset)) {
2816 // Move all the symbols to a new file location.
2817 const new_offset = self.findFreeSpace(needed_size, sym_align);
2818 log.debug("moving '.symtab' from 0x{x} to 0x{x}", .{ syms_sect.sh_offset, new_offset });
2819 const existing_size = @as(u64, syms_sect.sh_info) * sym_size;
2820 const amt = try self.base.file.?.copyRangeAll(
2821 syms_sect.sh_offset,
2822 self.base.file.?,
2823 new_offset,
2824 existing_size,
2825 );
2826 if (amt != existing_size) return error.InputOutput;
2827 syms_sect.sh_offset = new_offset;
2828 }
2850 try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, true);
28292851 syms_sect.sh_info = @intCast(u32, self.local_symbols.items.len);
2830 syms_sect.sh_size = needed_size; // anticipating adding the global symbols later
2831 self.shdr_table_dirty = true; // TODO look into only writing one section
28322852 }
28332853 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
28342854 const off = switch (self.ptr_width) {
......@@ -2876,22 +2896,7 @@ fn writeAllGlobalSymbols(self: *Elf) !void {
28762896 .p64 => @alignOf(elf.Elf64_Sym),
28772897 };
28782898 const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size;
2879 if (needed_size > self.allocatedSize(syms_sect.sh_offset)) {
2880 // Move all the symbols to a new file location.
2881 const new_offset = self.findFreeSpace(needed_size, sym_align);
2882 log.debug("moving '.symtab' from 0x{x} to 0x{x}", .{ syms_sect.sh_offset, new_offset });
2883 const existing_size = @as(u64, syms_sect.sh_info) * sym_size;
2884 const amt = try self.base.file.?.copyRangeAll(
2885 syms_sect.sh_offset,
2886 self.base.file.?,
2887 new_offset,
2888 existing_size,
2889 );
2890 if (amt != existing_size) return error.InputOutput;
2891 syms_sect.sh_offset = new_offset;
2892 }
2893 syms_sect.sh_size = needed_size; // anticipating adding the global symbols later
2894 self.shdr_table_dirty = true; // TODO look into only writing one section
2899 try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, true);
28952900
28962901 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
28972902 const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size;
src/link/MachO.zig+8-5
......@@ -347,7 +347,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
347347
348348 self.d_sym = .{
349349 .allocator = allocator,
350 .dwarf = link.File.Dwarf.init(allocator, .macho, options.target),
350 .dwarf = link.File.Dwarf.init(allocator, &self.base, options.target),
351351 .file = d_sym_file,
352352 .page_size = self.page_size,
353353 };
......@@ -449,7 +449,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
449449 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
450450
451451 if (self.d_sym) |*d_sym| {
452 try d_sym.dwarf.flushModule(&self.base, module);
452 try d_sym.dwarf.flushModule(module);
453453 }
454454
455455 var libs = std.StringArrayHashMap(link.SystemLib).init(arena);
......@@ -2213,7 +2213,6 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
22132213
22142214 if (decl_state) |*ds| {
22152215 try self.d_sym.?.dwarf.commitDeclState(
2216 &self.base,
22172216 module,
22182217 decl_index,
22192218 addr,
......@@ -2364,7 +2363,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
23642363
23652364 if (decl_state) |*ds| {
23662365 try self.d_sym.?.dwarf.commitDeclState(
2367 &self.base,
23682366 module,
23692367 decl_index,
23702368 addr,
......@@ -2603,7 +2601,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
26032601pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {
26042602 _ = module;
26052603 if (self.d_sym) |*d_sym| {
2606 try d_sym.dwarf.updateDeclLineNumber(&self.base, decl);
2604 try d_sym.dwarf.updateDeclLineNumber(decl);
26072605 }
26082606}
26092607
......@@ -4302,6 +4300,11 @@ pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {
43024300 return global;
43034301}
43044302
4303pub fn getDebugSymbols(self: *MachO) ?*DebugSymbols {
4304 if (self.d_sym == null) return null;
4305 return &self.d_sym.?;
4306}
4307
43054308pub fn findFirst(comptime T: type, haystack: []align(1) const T, start: usize, predicate: anytype) usize {
43064309 if (!@hasDecl(@TypeOf(predicate), "predicate"))
43074310 @compileError("Predicate is required to define fn predicate(@This(), T) bool");
src/link/MachO/DebugSymbols.zig+67-27
......@@ -137,7 +137,6 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
137137 off + size,
138138 });
139139
140 sect.addr = segment.vmaddr + off - segment.fileoff;
141140 sect.offset = @intCast(u32, off);
142141
143142 const index = @intCast(u8, self.sections.items.len);
......@@ -148,6 +147,52 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
148147 return index;
149148}
150149
150pub fn growSection(self: *DebugSymbols, sect_index: u8, needed_size: u32, requires_file_copy: bool) !void {
151 const sect = self.getSectionPtr(sect_index);
152
153 if (needed_size > self.allocatedSize(sect.offset)) {
154 const existing_size = sect.size;
155 sect.size = 0; // free the space
156 const new_offset = self.findFreeSpace(needed_size, 1);
157
158 log.debug("moving {s} section: {} bytes from 0x{x} to 0x{x}", .{
159 sect.sectName(),
160 existing_size,
161 sect.offset,
162 new_offset,
163 });
164
165 if (requires_file_copy) {
166 const amt = try self.file.copyRangeAll(
167 sect.offset,
168 self.file,
169 new_offset,
170 existing_size,
171 );
172 if (amt != existing_size) return error.InputOutput;
173 }
174
175 sect.offset = @intCast(u32, new_offset);
176 }
177
178 sect.size = needed_size;
179 self.markDirty(sect_index);
180}
181
182pub fn markDirty(self: *DebugSymbols, sect_index: u8) void {
183 if (self.debug_info_section_index.? == sect_index) {
184 self.debug_info_header_dirty = true;
185 } else if (self.debug_line_section_index.? == sect_index) {
186 self.debug_line_header_dirty = true;
187 } else if (self.debug_abbrev_section_index.? == sect_index) {
188 self.debug_abbrev_section_dirty = true;
189 } else if (self.debug_str_section_index.? == sect_index) {
190 self.debug_string_table_dirty = true;
191 } else if (self.debug_aranges_section_index.? == sect_index) {
192 self.debug_aranges_section_dirty = true;
193 }
194}
195
151196fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {
152197 const end = start + padToIdeal(size);
153198 for (self.sections.items) |section| {
......@@ -160,7 +205,7 @@ fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {
160205 return null;
161206}
162207
163pub fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 {
208fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 {
164209 const segment = self.getDwarfSegmentPtr();
165210 var offset: u64 = segment.fileoff;
166211 while (self.detectAllocCollision(offset, object_size)) |item_end| {
......@@ -213,7 +258,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
213258 }
214259
215260 if (self.debug_abbrev_section_dirty) {
216 try self.dwarf.writeDbgAbbrev(&macho_file.base);
261 try self.dwarf.writeDbgAbbrev();
217262 self.debug_abbrev_section_dirty = false;
218263 }
219264
......@@ -223,7 +268,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
223268 const text_section = macho_file.sections.items(.header)[macho_file.text_section_index.?];
224269 const low_pc = text_section.addr;
225270 const high_pc = text_section.addr + text_section.size;
226 try self.dwarf.writeDbgInfoHeader(&macho_file.base, module, low_pc, high_pc);
271 try self.dwarf.writeDbgInfoHeader(module, low_pc, high_pc);
227272 self.debug_info_header_dirty = false;
228273 }
229274
......@@ -231,36 +276,21 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
231276 // Currently only one compilation unit is supported, so the address range is simply
232277 // identical to the main program header virtual address and memory size.
233278 const text_section = macho_file.sections.items(.header)[macho_file.text_section_index.?];
234 try self.dwarf.writeDbgAranges(&macho_file.base, text_section.addr, text_section.size);
279 try self.dwarf.writeDbgAranges(text_section.addr, text_section.size);
235280 self.debug_aranges_section_dirty = false;
236281 }
237282
238283 if (self.debug_line_header_dirty) {
239 try self.dwarf.writeDbgLineHeader(&macho_file.base, module);
284 try self.dwarf.writeDbgLineHeader(module);
240285 self.debug_line_header_dirty = false;
241286 }
242287
243288 {
244 const dwarf_segment = self.getDwarfSegmentPtr();
245 const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?];
246 if (self.debug_string_table_dirty or self.dwarf.strtab.items.len != debug_strtab_sect.size) {
247 const allocated_size = self.allocatedSize(debug_strtab_sect.offset);
248 const needed_size = self.dwarf.strtab.items.len;
249
250 if (needed_size > allocated_size) {
251 debug_strtab_sect.size = 0; // free the space
252 const new_offset = self.findFreeSpace(needed_size, 1);
253 debug_strtab_sect.addr = dwarf_segment.vmaddr + new_offset - dwarf_segment.fileoff;
254 debug_strtab_sect.offset = @intCast(u32, new_offset);
255 }
256 debug_strtab_sect.size = @intCast(u32, needed_size);
257
258 log.debug("__debug_strtab start=0x{x} end=0x{x}", .{
259 debug_strtab_sect.offset,
260 debug_strtab_sect.offset + needed_size,
261 });
262
263 try self.file.pwriteAll(self.dwarf.strtab.items, debug_strtab_sect.offset);
289 const sect_index = self.debug_str_section_index.?;
290 if (self.debug_string_table_dirty or self.dwarf.strtab.items.len != self.getSection(sect_index).size) {
291 const needed_size = @intCast(u32, self.dwarf.strtab.items.len);
292 try self.growSection(sect_index, needed_size, false);
293 try self.file.pwriteAll(self.dwarf.strtab.items, self.getSection(sect_index).offset);
264294 self.debug_string_table_dirty = false;
265295 }
266296 }
......@@ -424,7 +454,7 @@ fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: u32, sizeofcmds:
424454 try self.file.pwriteAll(mem.asBytes(&header), 0);
425455}
426456
427pub fn allocatedSize(self: *DebugSymbols, start: u64) u64 {
457fn allocatedSize(self: *DebugSymbols, start: u64) u64 {
428458 const seg = self.getDwarfSegmentPtr();
429459 assert(start >= seg.fileoff);
430460 var min_pos: u64 = std.math.maxInt(u64);
......@@ -556,3 +586,13 @@ fn getLinkeditSegmentPtr(self: *DebugSymbols) *macho.segment_command_64 {
556586 const index = self.linkedit_segment_cmd_index.?;
557587 return &self.segments.items[index];
558588}
589
590pub fn getSectionPtr(self: *DebugSymbols, sect: u8) *macho.section_64 {
591 assert(sect < self.sections.items.len);
592 return &self.sections.items[sect];
593}
594
595pub fn getSection(self: DebugSymbols, sect: u8) macho.section_64 {
596 assert(sect < self.sections.items.len);
597 return self.sections.items[sect];
598}
src/link/Wasm.zig+7-8
......@@ -361,7 +361,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
361361 }
362362
363363 if (!options.strip and options.module != null) {
364 wasm_bin.dwarf = Dwarf.init(allocator, .wasm, options.target);
364 wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, options.target);
365365 try wasm_bin.initDebugSections();
366366 }
367367
......@@ -910,7 +910,6 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
910910
911911 if (wasm.dwarf) |*dwarf| {
912912 try dwarf.commitDeclState(
913 &wasm.base,
914913 mod,
915914 decl_index,
916915 // Actual value will be written after relocation.
......@@ -990,7 +989,7 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl: *const Module.Decl)
990989 defer wasm.base.allocator.free(decl_name);
991990
992991 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
993 try dw.updateDeclLineNumber(&wasm.base, decl);
992 try dw.updateDeclLineNumber(decl);
994993 }
995994}
996995
......@@ -2299,7 +2298,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
22992298 }
23002299
23012300 if (wasm.dwarf) |*dwarf| {
2302 try dwarf.flushModule(&wasm.base, wasm.base.options.module.?);
2301 try dwarf.flushModule(wasm.base.options.module.?);
23032302 }
23042303 }
23052304
......@@ -2668,12 +2667,12 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
26682667 if (!wasm.base.options.strip) {
26692668 if (wasm.dwarf) |*dwarf| {
26702669 const mod = wasm.base.options.module.?;
2671 try dwarf.writeDbgAbbrev(&wasm.base);
2670 try dwarf.writeDbgAbbrev();
26722671 // for debug info and ranges, the address is always 0,
26732672 // as locations are always offsets relative to 'code' section.
2674 try dwarf.writeDbgInfoHeader(&wasm.base, mod, 0, code_section_size);
2675 try dwarf.writeDbgAranges(&wasm.base, 0, code_section_size);
2676 try dwarf.writeDbgLineHeader(&wasm.base, mod);
2673 try dwarf.writeDbgInfoHeader(mod, 0, code_section_size);
2674 try dwarf.writeDbgAranges(0, code_section_size);
2675 try dwarf.writeDbgLineHeader(mod);
26772676 }
26782677
26792678 var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator);