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
signaturebadge-question-mark 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;...@@ -22,7 +22,7 @@ const Value = @import("../value.zig").Value;
22const Type = @import("../type.zig").Type;22const Type = @import("../type.zig").Type;
2323
24allocator: Allocator,24allocator: Allocator,
25tag: File.Tag,25bin_file: *File,
26ptr_width: PtrWidth,26ptr_width: PtrWidth,
27target: std.Target,27target: std.Target,
2828
...@@ -44,6 +44,12 @@ abbrev_table_offset: ?u64 = null,...@@ -44,6 +44,12 @@ abbrev_table_offset: ?u64 = null,
44/// Table of debug symbol names.44/// Table of debug symbol names.
45strtab: std.ArrayListUnmanaged(u8) = .{},45strtab: 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
47/// List of atoms that are owned directly by the DWARF module.53/// List of atoms that are owned directly by the DWARF module.
48/// TODO convert links in DebugInfoAtom into indices and make54/// TODO convert links in DebugInfoAtom into indices and make
49/// sure every atom is owned by this module.55/// sure every atom is owned by this module.
...@@ -887,7 +893,7 @@ const min_nop_size = 2;...@@ -887,7 +893,7 @@ const min_nop_size = 2;
887/// actual_capacity + (actual_capacity / ideal_factor)893/// actual_capacity + (actual_capacity / ideal_factor)
888const ideal_factor = 3;894const 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 {
891 const ptr_width: PtrWidth = switch (target.cpu.arch.ptrBitWidth()) {897 const ptr_width: PtrWidth = switch (target.cpu.arch.ptrBitWidth()) {
892 0...32 => .p32,898 0...32 => .p32,
893 33...64 => .p64,899 33...64 => .p64,
...@@ -895,7 +901,7 @@ pub fn init(allocator: Allocator, tag: File.Tag, target: std.Target) Dwarf {...@@ -895,7 +901,7 @@ pub fn init(allocator: Allocator, tag: File.Tag, target: std.Target) Dwarf {
895 };901 };
896 return Dwarf{902 return Dwarf{
897 .allocator = allocator,903 .allocator = allocator,
898 .tag = tag,904 .bin_file = bin_file,
899 .ptr_width = ptr_width,905 .ptr_width = ptr_width,
900 .target = target,906 .target = target,
901 };907 };
...@@ -906,6 +912,7 @@ pub fn deinit(self: *Dwarf) void {...@@ -906,6 +912,7 @@ pub fn deinit(self: *Dwarf) void {
906 self.dbg_line_fn_free_list.deinit(gpa);912 self.dbg_line_fn_free_list.deinit(gpa);
907 self.atom_free_list.deinit(gpa);913 self.atom_free_list.deinit(gpa);
908 self.strtab.deinit(gpa);914 self.strtab.deinit(gpa);
915 self.di_files.deinit(gpa);
909 self.global_abbrev_relocs.deinit(gpa);916 self.global_abbrev_relocs.deinit(gpa);
910917
911 for (self.managed_atoms.items) |atom| {918 for (self.managed_atoms.items) |atom| {
...@@ -968,7 +975,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)...@@ -968,7 +975,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
968 assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len);975 assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len);
969 // Once we support more than one source file, this will have the ability to be more976 // Once we support more than one source file, this will have the ability to be more
970 // than one possible value.977 // than one possible value.
971 const file_index = 1;978 const file_index = try self.addDIFile(mod, decl_index);
972 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);979 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);
973980
974 // Emit a line for the begin curly with prologue_end=false. The codegen will981 // 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)...@@ -995,7 +1002,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
995 dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data41002 dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4
996 //1003 //
997 if (fn_ret_has_bits) {1004 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);
999 try decl_state.addTypeRelocGlobal(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len));1006 try decl_state.addTypeRelocGlobal(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len));
1000 dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref41007 dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4
1001 }1008 }
...@@ -1013,7 +1020,6 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)...@@ -1013,7 +1020,6 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
10131020
1014pub fn commitDeclState(1021pub fn commitDeclState(
1015 self: *Dwarf,1022 self: *Dwarf,
1016 file: *File,
1017 module: *Module,1023 module: *Module,
1018 decl_index: Module.Decl.Index,1024 decl_index: Module.Decl.Index,
1019 sym_addr: u64,1025 sym_addr: u64,
...@@ -1069,7 +1075,7 @@ pub fn commitDeclState(...@@ -1069,7 +1075,7 @@ pub fn commitDeclState(
1069 // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for1075 // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for
1070 // `TextBlock` and the .debug_info. If you are editing this logic, you1076 // `TextBlock` and the .debug_info. If you are editing this logic, you
1071 // probably need to edit that logic too.1077 // probably need to edit that logic too.
1072 const src_fn = switch (self.tag) {1078 const src_fn = switch (self.bin_file.tag) {
1073 .elf => &decl.fn_link.elf,1079 .elf => &decl.fn_link.elf,
1074 .macho => &decl.fn_link.macho,1080 .macho => &decl.fn_link.macho,
1075 .wasm => &decl.fn_link.wasm.src_fn,1081 .wasm => &decl.fn_link.wasm.src_fn,
...@@ -1090,22 +1096,21 @@ pub fn commitDeclState(...@@ -1090,22 +1096,21 @@ pub fn commitDeclState(
1090 next.prev = src_fn.prev;1096 next.prev = src_fn.prev;
1091 src_fn.next = null;1097 src_fn.next = null;
1092 // Populate where it used to be with NOPs.1098 // Populate where it used to be with NOPs.
1093 switch (self.tag) {1099 switch (self.bin_file.tag) {
1094 .elf => {1100 .elf => {
1095 const elf_file = file.cast(File.Elf).?;1101 const elf_file = self.bin_file.cast(File.Elf).?;
1096 const debug_line_sect = &elf_file.sections.items[elf_file.debug_line_section_index.?];1102 const debug_line_sect = &elf_file.sections.items[elf_file.debug_line_section_index.?];
1097 const file_pos = debug_line_sect.sh_offset + src_fn.off;1103 const file_pos = debug_line_sect.sh_offset + src_fn.off;
1098 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);1104 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
1099 },1105 },
1100 .macho => {1106 .macho => {
1101 const macho_file = file.cast(File.MachO).?;1107 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1102 const d_sym = &macho_file.d_sym.?;1108 const debug_line_sect = d_sym.getSectionPtr(d_sym.debug_line_section_index.?);
1103 const debug_line_sect = &d_sym.sections.items[d_sym.debug_line_section_index.?];
1104 const file_pos = debug_line_sect.offset + src_fn.off;1109 const file_pos = debug_line_sect.offset + src_fn.off;
1105 try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len);1110 try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len);
1106 },1111 },
1107 .wasm => {1112 .wasm => {
1108 const wasm_file = file.cast(File.Wasm).?;1113 const wasm_file = self.bin_file.cast(File.Wasm).?;
1109 const debug_line = wasm_file.debug_line_atom.?.code;1114 const debug_line = wasm_file.debug_line_atom.?.code;
1110 writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len);1115 writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len);
1111 },1116 },
...@@ -1132,7 +1137,7 @@ pub fn commitDeclState(...@@ -1132,7 +1137,7 @@ pub fn commitDeclState(
1132 self.dbg_line_fn_first = src_fn;1137 self.dbg_line_fn_first = src_fn;
1133 self.dbg_line_fn_last = src_fn;1138 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{}));
1136 }1141 }
11371142
1138 const last_src_fn = self.dbg_line_fn_last.?;1143 const last_src_fn = self.dbg_line_fn_last.?;
...@@ -1142,32 +1147,12 @@ pub fn commitDeclState(...@@ -1142,32 +1147,12 @@ pub fn commitDeclState(
11421147
1143 // We only have support for one compilation unit so far, so the offsets are directly1148 // We only have support for one compilation unit so far, so the offsets are directly
1144 // from the .debug_line section.1149 // from the .debug_line section.
1145 switch (self.tag) {1150 switch (self.bin_file.tag) {
1146 .elf => {1151 .elf => {
1147 const elf_file = file.cast(File.Elf).?;1152 const elf_file = self.bin_file.cast(File.Elf).?;
1148 const debug_line_sect = &elf_file.sections.items[elf_file.debug_line_section_index.?];1153 const shdr_index = elf_file.debug_line_section_index.?;
1149 if (needed_size != debug_line_sect.sh_size) {1154 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
1150 if (needed_size > elf_file.allocatedSize(debug_line_sect.sh_offset)) {1155 const debug_line_sect = elf_file.sections.items[shdr_index];
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 }
1171 const file_pos = debug_line_sect.sh_offset + src_fn.off;1156 const file_pos = debug_line_sect.sh_offset + src_fn.off;
1172 try pwriteDbgLineNops(1157 try pwriteDbgLineNops(
1173 elf_file.base.file.?,1158 elf_file.base.file.?,
...@@ -1179,31 +1164,11 @@ pub fn commitDeclState(...@@ -1179,31 +1164,11 @@ pub fn commitDeclState(
1179 },1164 },
11801165
1181 .macho => {1166 .macho => {
1182 const macho_file = file.cast(File.MachO).?;1167 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1183 const d_sym = &macho_file.d_sym.?;1168 const sect_index = d_sym.debug_line_section_index.?;
1184 const debug_line_sect = &d_sym.sections.items[d_sym.debug_line_section_index.?];1169 try d_sym.growSection(sect_index, needed_size, true);
1185 if (needed_size != debug_line_sect.size) {1170 const sect = d_sym.getSection(sect_index);
1186 if (needed_size > d_sym.allocatedSize(debug_line_sect.offset)) {1171 const file_pos = sect.offset + src_fn.off;
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;
1207 try pwriteDbgLineNops(1172 try pwriteDbgLineNops(
1208 d_sym.file,1173 d_sym.file,
1209 file_pos,1174 file_pos,
...@@ -1214,7 +1179,7 @@ pub fn commitDeclState(...@@ -1214,7 +1179,7 @@ pub fn commitDeclState(
1214 },1179 },
12151180
1216 .wasm => {1181 .wasm => {
1217 const wasm_file = file.cast(File.Wasm).?;1182 const wasm_file = self.bin_file.cast(File.Wasm).?;
1218 const atom = wasm_file.debug_line_atom.?;1183 const atom = wasm_file.debug_line_atom.?;
1219 const debug_line = &atom.code;1184 const debug_line = &atom.code;
1220 const segment_size = debug_line.items.len;1185 const segment_size = debug_line.items.len;
...@@ -1247,7 +1212,7 @@ pub fn commitDeclState(...@@ -1247,7 +1212,7 @@ pub fn commitDeclState(
1247 if (dbg_info_buffer.items.len == 0)1212 if (dbg_info_buffer.items.len == 0)
1248 return;1213 return;
12491214
1250 const atom = getDbgInfoAtom(self.tag, module, decl_index);1215 const atom = getDbgInfoAtom(self.bin_file.tag, module, decl_index);
1251 if (decl_state.abbrev_table.items.len > 0) {1216 if (decl_state.abbrev_table.items.len > 0) {
1252 // Now we emit the .debug_info types of the Decl. These will count towards the size of1217 // Now we emit the .debug_info types of the Decl. These will count towards the size of
1253 // the buffer, so we have to do it before computing the offset, and we can't perform the actual1218 // 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(...@@ -1274,7 +1239,7 @@ pub fn commitDeclState(
1274 }1239 }
12751240
1276 log.debug("updateDeclDebugInfoAllocation for '{s}'", .{decl.name});1241 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
1279 while (decl_state.abbrev_relocs.popOrNull()) |reloc| {1244 while (decl_state.abbrev_relocs.popOrNull()) |reloc| {
1280 if (reloc.target) |target| {1245 if (reloc.target) |target| {
...@@ -1319,10 +1284,9 @@ pub fn commitDeclState(...@@ -1319,10 +1284,9 @@ pub fn commitDeclState(
1319 }1284 }
13201285
1321 while (decl_state.exprloc_relocs.popOrNull()) |reloc| {1286 while (decl_state.exprloc_relocs.popOrNull()) |reloc| {
1322 switch (self.tag) {1287 switch (self.bin_file.tag) {
1323 .macho => {1288 .macho => {
1324 const macho_file = file.cast(File.MachO).?;1289 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1325 const d_sym = &macho_file.d_sym.?;
1326 try d_sym.relocs.append(d_sym.allocator, .{1290 try d_sym.relocs.append(d_sym.allocator, .{
1327 .type = switch (reloc.type) {1291 .type = switch (reloc.type) {
1328 .direct_load => .direct_load,1292 .direct_load => .direct_load,
...@@ -1339,10 +1303,10 @@ pub fn commitDeclState(...@@ -1339,10 +1303,10 @@ pub fn commitDeclState(
1339 }1303 }
13401304
1341 log.debug("writeDeclDebugInfo for '{s}", .{decl.name});1305 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);
1343}1307}
13441308
1345fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u32) !void {1309fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {
1346 const tracy = trace(@src());1310 const tracy = trace(@src());
1347 defer tracy.end();1311 defer tracy.end();
13481312
...@@ -1365,22 +1329,21 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3...@@ -1365,22 +1329,21 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3
1365 next.prev = atom.prev;1329 next.prev = atom.prev;
1366 atom.next = null;1330 atom.next = null;
1367 // Populate where it used to be with NOPs.1331 // Populate where it used to be with NOPs.
1368 switch (self.tag) {1332 switch (self.bin_file.tag) {
1369 .elf => {1333 .elf => {
1370 const elf_file = file.cast(File.Elf).?;1334 const elf_file = self.bin_file.cast(File.Elf).?;
1371 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];1335 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];
1372 const file_pos = debug_info_sect.sh_offset + atom.off;1336 const file_pos = debug_info_sect.sh_offset + atom.off;
1373 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);1337 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
1374 },1338 },
1375 .macho => {1339 .macho => {
1376 const macho_file = file.cast(File.MachO).?;1340 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1377 const d_sym = &macho_file.d_sym.?;1341 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
1378 const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?];
1379 const file_pos = debug_info_sect.offset + atom.off;1342 const file_pos = debug_info_sect.offset + atom.off;
1380 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false);1343 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false);
1381 },1344 },
1382 .wasm => {1345 .wasm => {
1383 const wasm_file = file.cast(File.Wasm).?;1346 const wasm_file = self.bin_file.cast(File.Wasm).?;
1384 const debug_info = &wasm_file.debug_info_atom.?.code;1347 const debug_info = &wasm_file.debug_info_atom.?.code;
1385 try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false);1348 try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false);
1386 },1349 },
...@@ -1411,7 +1374,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3...@@ -1411,7 +1374,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3
1411 }1374 }
1412}1375}
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 {
1415 const tracy = trace(@src());1378 const tracy = trace(@src());
1416 defer tracy.end();1379 defer tracy.end();
14171380
...@@ -1431,32 +1394,12 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co...@@ -1431,32 +1394,12 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
14311394
1432 // We only have support for one compilation unit so far, so the offsets are directly1395 // We only have support for one compilation unit so far, so the offsets are directly
1433 // from the .debug_info section.1396 // from the .debug_info section.
1434 switch (self.tag) {1397 switch (self.bin_file.tag) {
1435 .elf => {1398 .elf => {
1436 const elf_file = file.cast(File.Elf).?;1399 const elf_file = self.bin_file.cast(File.Elf).?;
1437 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];1400 const shdr_index = elf_file.debug_info_section_index.?;
1438 if (needed_size != debug_info_sect.sh_size) {1401 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
1439 if (needed_size > elf_file.allocatedSize(debug_info_sect.sh_offset)) {1402 const debug_info_sect = elf_file.sections.items[shdr_index];
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 }
1460 const file_pos = debug_info_sect.sh_offset + atom.off;1403 const file_pos = debug_info_sect.sh_offset + atom.off;
1461 try pwriteDbgInfoNops(1404 try pwriteDbgInfoNops(
1462 elf_file.base.file.?,1405 elf_file.base.file.?,
...@@ -1469,31 +1412,11 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co...@@ -1469,31 +1412,11 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
1469 },1412 },
14701413
1471 .macho => {1414 .macho => {
1472 const macho_file = file.cast(File.MachO).?;1415 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1473 const d_sym = &macho_file.d_sym.?;1416 const sect_index = d_sym.debug_info_section_index.?;
1474 const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?];1417 try d_sym.growSection(sect_index, needed_size, true);
1475 if (needed_size != debug_info_sect.size) {1418 const sect = d_sym.getSection(sect_index);
1476 if (needed_size > d_sym.allocatedSize(debug_info_sect.offset)) {1419 const file_pos = sect.offset + atom.off;
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;
1497 try pwriteDbgInfoNops(1420 try pwriteDbgInfoNops(
1498 d_sym.file,1421 d_sym.file,
1499 file_pos,1422 file_pos,
...@@ -1505,7 +1428,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co...@@ -1505,7 +1428,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
1505 },1428 },
15061429
1507 .wasm => {1430 .wasm => {
1508 const wasm_file = file.cast(File.Wasm).?;1431 const wasm_file = self.bin_file.cast(File.Wasm).?;
1509 const info_atom = wasm_file.debug_info_atom.?;1432 const info_atom = wasm_file.debug_info_atom.?;
1510 const debug_info = &info_atom.code;1433 const debug_info = &info_atom.code;
1511 const segment_size = debug_info.items.len;1434 const segment_size = debug_info.items.len;
...@@ -1535,7 +1458,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co...@@ -1535,7 +1458,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
1535 }1458 }
1536}1459}
15371460
1538pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl) !void {1461pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void {
1539 const tracy = trace(@src());1462 const tracy = trace(@src());
1540 defer tracy.end();1463 defer tracy.end();
15411464
...@@ -1549,22 +1472,21 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl)...@@ -1549,22 +1472,21 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl)
1549 var data: [4]u8 = undefined;1472 var data: [4]u8 = undefined;
1550 leb128.writeUnsignedFixed(4, &data, line);1473 leb128.writeUnsignedFixed(4, &data, line);
15511474
1552 switch (self.tag) {1475 switch (self.bin_file.tag) {
1553 .elf => {1476 .elf => {
1554 const elf_file = file.cast(File.Elf).?;1477 const elf_file = self.bin_file.cast(File.Elf).?;
1555 const shdr = elf_file.sections.items[elf_file.debug_line_section_index.?];1478 const shdr = elf_file.sections.items[elf_file.debug_line_section_index.?];
1556 const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff();1479 const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff();
1557 try elf_file.base.file.?.pwriteAll(&data, file_pos);1480 try elf_file.base.file.?.pwriteAll(&data, file_pos);
1558 },1481 },
1559 .macho => {1482 .macho => {
1560 const macho_file = file.cast(File.MachO).?;1483 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1561 const d_sym = macho_file.d_sym.?;1484 const sect = d_sym.getSection(d_sym.debug_line_section_index.?);
1562 const sect = d_sym.sections.items[d_sym.debug_line_section_index.?];
1563 const file_pos = sect.offset + decl.fn_link.macho.off + self.getRelocDbgLineOff();1485 const file_pos = sect.offset + decl.fn_link.macho.off + self.getRelocDbgLineOff();
1564 try d_sym.file.pwriteAll(&data, file_pos);1486 try d_sym.file.pwriteAll(&data, file_pos);
1565 },1487 },
1566 .wasm => {1488 .wasm => {
1567 const wasm_file = file.cast(File.Wasm).?;1489 const wasm_file = self.bin_file.cast(File.Wasm).?;
1568 const offset = decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff();1490 const offset = decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff();
1569 const atom = wasm_file.debug_line_atom.?;1491 const atom = wasm_file.debug_line_atom.?;
1570 mem.copy(u8, atom.code.items[offset..], &data);1492 mem.copy(u8, atom.code.items[offset..], &data);
...@@ -1601,7 +1523,7 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void {...@@ -1601,7 +1523,7 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void {
1601 // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing1523 // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing
1602 // is desired for both.1524 // is desired for both.
1603 const gpa = self.allocator;1525 const gpa = self.allocator;
1604 const fn_link = switch (self.tag) {1526 const fn_link = switch (self.bin_file.tag) {
1605 .elf => &decl.fn_link.elf,1527 .elf => &decl.fn_link.elf,
1606 .macho => &decl.fn_link.macho,1528 .macho => &decl.fn_link.macho,
1607 .wasm => &decl.fn_link.wasm.src_fn,1529 .wasm => &decl.fn_link.wasm.src_fn,
...@@ -1629,7 +1551,7 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void {...@@ -1629,7 +1551,7 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void {
1629 }1551 }
1630}1552}
16311553
1632pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {1554pub fn writeDbgAbbrev(self: *Dwarf) !void {
1633 // These are LEB encoded but since the values are all less than 1271555 // These are LEB encoded but since the values are all less than 127
1634 // we can simply append these bytes.1556 // we can simply append these bytes.
1635 const abbrev_buf = [_]u8{1557 const abbrev_buf = [_]u8{
...@@ -1763,46 +1685,25 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {...@@ -1763,46 +1685,25 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
1763 self.abbrev_table_offset = abbrev_offset;1685 self.abbrev_table_offset = abbrev_offset;
17641686
1765 const needed_size = abbrev_buf.len;1687 const needed_size = abbrev_buf.len;
1766 switch (self.tag) {1688 switch (self.bin_file.tag) {
1767 .elf => {1689 .elf => {
1768 const elf_file = file.cast(File.Elf).?;1690 const elf_file = self.bin_file.cast(File.Elf).?;
1769 const debug_abbrev_sect = &elf_file.sections.items[elf_file.debug_abbrev_section_index.?];1691 const shdr_index = elf_file.debug_abbrev_section_index.?;
1770 const allocated_size = elf_file.allocatedSize(debug_abbrev_sect.sh_offset);1692 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, false);
1771 if (needed_size > allocated_size) {1693 const debug_abbrev_sect = elf_file.sections.items[shdr_index];
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
1781 const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset;1694 const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset;
1782 try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);1695 try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
1783 },1696 },
1784 .macho => {1697 .macho => {
1785 const macho_file = file.cast(File.MachO).?;1698 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1786 const d_sym = &macho_file.d_sym.?;1699 const sect_index = d_sym.debug_abbrev_section_index.?;
1787 const dwarf_segment = d_sym.segments.items[d_sym.dwarf_segment_cmd_index.?];1700 try d_sym.growSection(sect_index, needed_size, false);
1788 const debug_abbrev_sect = &d_sym.sections.items[d_sym.debug_abbrev_section_index.?];1701 const sect = d_sym.getSection(sect_index);
1789 const allocated_size = d_sym.allocatedSize(debug_abbrev_sect.offset);1702 const file_pos = sect.offset + abbrev_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;
1802 try d_sym.file.pwriteAll(&abbrev_buf, file_pos);1703 try d_sym.file.pwriteAll(&abbrev_buf, file_pos);
1803 },1704 },
1804 .wasm => {1705 .wasm => {
1805 const wasm_file = file.cast(File.Wasm).?;1706 const wasm_file = self.bin_file.cast(File.Wasm).?;
1806 const debug_abbrev = &wasm_file.debug_abbrev_atom.?.code;1707 const debug_abbrev = &wasm_file.debug_abbrev_atom.?.code;
1807 try debug_abbrev.resize(wasm_file.base.allocator, needed_size);1708 try debug_abbrev.resize(wasm_file.base.allocator, needed_size);
1808 mem.copy(u8, debug_abbrev.items, &abbrev_buf);1709 mem.copy(u8, debug_abbrev.items, &abbrev_buf);
...@@ -1816,7 +1717,7 @@ fn dbgInfoHeaderBytes(self: *Dwarf) usize {...@@ -1816,7 +1717,7 @@ fn dbgInfoHeaderBytes(self: *Dwarf) usize {
1816 return 120;1717 return 120;
1817}1718}
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 {
1820 // If this value is null it means there is an error in the module;1721 // If this value is null it means there is an error in the module;
1821 // leave debug_info_header_dirty=true.1722 // leave debug_info_header_dirty=true.
1822 const first_dbg_info_off = self.getDebugInfoOff() orelse return;1723 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...@@ -1828,7 +1729,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
1828 defer di_buf.deinit();1729 defer di_buf.deinit();
18291730
1830 const target_endian = self.target.cpu.arch.endian();1731 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)
1832 41733 4
1833 else switch (self.ptr_width) {1734 else switch (self.ptr_width) {
1834 .p32 => @as(usize, 4),1735 .p32 => @as(usize, 4),
...@@ -1842,7 +1743,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6...@@ -1842,7 +1743,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
1842 // +1 for the final 0 that ends the compilation unit children.1743 // +1 for the final 0 that ends the compilation unit children.
1843 const dbg_info_end = self.getDebugInfoEnd().? + 1;1744 const dbg_info_end = self.getDebugInfoEnd().? + 1;
1844 const init_len = dbg_info_end - after_init_len;1745 const init_len = dbg_info_end - after_init_len;
1845 if (self.tag == .macho) {1746 if (self.bin_file.tag == .macho) {
1846 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len));1747 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len));
1847 } else switch (self.ptr_width) {1748 } else switch (self.ptr_width) {
1848 .p32 => {1749 .p32 => {
...@@ -1855,7 +1756,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6...@@ -1855,7 +1756,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
1855 }1756 }
1856 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version1757 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version
1857 const abbrev_offset = self.abbrev_table_offset.?;1758 const abbrev_offset = self.abbrev_table_offset.?;
1858 if (self.tag == .macho) {1759 if (self.bin_file.tag == .macho) {
1859 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, abbrev_offset));1760 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, abbrev_offset));
1860 di_buf.appendAssumeCapacity(8); // address size1761 di_buf.appendAssumeCapacity(8); // address size
1861 } else switch (self.ptr_width) {1762 } else switch (self.ptr_width) {
...@@ -1870,11 +1771,12 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6...@@ -1870,11 +1771,12 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
1870 }1771 }
1871 // Write the form for the compile unit, which must match the abbrev table above.1772 // Write the form for the compile unit, which must match the abbrev table above.
1872 const name_strp = try self.makeString(module.root_pkg.root_src_path);1773 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);
1874 const producer_strp = try self.makeString(link.producer_string);1776 const producer_strp = try self.makeString(link.producer_string);
18751777
1876 di_buf.appendAssumeCapacity(@enumToInt(AbbrevKind.compile_unit));1778 di_buf.appendAssumeCapacity(@enumToInt(AbbrevKind.compile_unit));
1877 if (self.tag == .macho) {1779 if (self.bin_file.tag == .macho) {
1878 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // DW.AT.stmt_list, DW.FORM.sec_offset1780 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // DW.AT.stmt_list, DW.FORM.sec_offset
1879 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), low_pc);1781 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), low_pc);
1880 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), high_pc);1782 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...@@ -1899,22 +1801,21 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
1899 @panic("TODO: handle .debug_info header exceeding its padding");1801 @panic("TODO: handle .debug_info header exceeding its padding");
1900 }1802 }
1901 const jmp_amt = first_dbg_info_off - di_buf.items.len;1803 const jmp_amt = first_dbg_info_off - di_buf.items.len;
1902 switch (self.tag) {1804 switch (self.bin_file.tag) {
1903 .elf => {1805 .elf => {
1904 const elf_file = file.cast(File.Elf).?;1806 const elf_file = self.bin_file.cast(File.Elf).?;
1905 const debug_info_sect = elf_file.sections.items[elf_file.debug_info_section_index.?];1807 const debug_info_sect = elf_file.sections.items[elf_file.debug_info_section_index.?];
1906 const file_pos = debug_info_sect.sh_offset;1808 const file_pos = debug_info_sect.sh_offset;
1907 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);1809 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
1908 },1810 },
1909 .macho => {1811 .macho => {
1910 const macho_file = file.cast(File.MachO).?;1812 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1911 const d_sym = &macho_file.d_sym.?;1813 const debug_info_sect = d_sym.getSection(d_sym.debug_info_section_index.?);
1912 const debug_info_sect = d_sym.sections.items[d_sym.debug_info_section_index.?];
1913 const file_pos = debug_info_sect.offset;1814 const file_pos = debug_info_sect.offset;
1914 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false);1815 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false);
1915 },1816 },
1916 .wasm => {1817 .wasm => {
1917 const wasm_file = file.cast(File.Wasm).?;1818 const wasm_file = self.bin_file.cast(File.Wasm).?;
1918 const debug_info = &wasm_file.debug_info_atom.?.code;1819 const debug_info = &wasm_file.debug_info_atom.?.code;
1919 try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);1820 try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);
1920 },1821 },
...@@ -1922,6 +1823,21 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6...@@ -1922,6 +1823,21 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
1922 }1823 }
1923}1824}
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
1925fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) void {1841fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) void {
1926 const target_endian = self.target.cpu.arch.endian();1842 const target_endian = self.target.cpu.arch.endian();
1927 switch (self.ptr_width) {1843 switch (self.ptr_width) {
...@@ -2144,9 +2060,9 @@ fn writeDbgInfoNopsToArrayList(...@@ -2144,9 +2060,9 @@ fn writeDbgInfoNopsToArrayList(
2144 }2060 }
2145}2061}
21462062
2147pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {2063pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
2148 const target_endian = self.target.cpu.arch.endian();2064 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)
2150 42066 4
2151 else switch (self.ptr_width) {2067 else switch (self.ptr_width) {
2152 .p32 => @as(usize, 4),2068 .p32 => @as(usize, 4),
...@@ -2168,7 +2084,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {...@@ -2168,7 +2084,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {
2168 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version2084 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version
2169 // When more than one compilation unit is supported, this will be the offset to it.2085 // When more than one compilation unit is supported, this will be the offset to it.
2170 // For now it is always at offset 0 in .debug_info.2086 // For now it is always at offset 0 in .debug_info.
2171 if (self.tag == .macho) {2087 if (self.bin_file.tag == .macho) {
2172 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // __debug_info offset2088 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // __debug_info offset
2173 } else {2089 } else {
2174 self.writeAddrAssumeCapacity(&di_buf, 0); // .debug_info offset2090 self.writeAddrAssumeCapacity(&di_buf, 0); // .debug_info offset
...@@ -2191,7 +2107,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {...@@ -2191,7 +2107,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {
21912107
2192 // Go back and populate the initial length.2108 // Go back and populate the initial length.
2193 const init_len = di_buf.items.len - after_init_len;2109 const init_len = di_buf.items.len - after_init_len;
2194 if (self.tag == .macho) {2110 if (self.bin_file.tag == .macho) {
2195 mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len));2111 mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len));
2196 } else switch (self.ptr_width) {2112 } else switch (self.ptr_width) {
2197 .p32 => {2113 .p32 => {
...@@ -2205,46 +2121,26 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {...@@ -2205,46 +2121,26 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {
2205 },2121 },
2206 }2122 }
22072123
2208 const needed_size = di_buf.items.len;2124 const needed_size = @intCast(u32, di_buf.items.len);
2209 switch (self.tag) {2125 switch (self.bin_file.tag) {
2210 .elf => {2126 .elf => {
2211 const elf_file = file.cast(File.Elf).?;2127 const elf_file = self.bin_file.cast(File.Elf).?;
2212 const debug_aranges_sect = &elf_file.sections.items[elf_file.debug_aranges_section_index.?];2128 const shdr_index = elf_file.debug_aranges_section_index.?;
2213 const allocated_size = elf_file.allocatedSize(debug_aranges_sect.sh_offset);2129 try elf_file.growNonAllocSection(shdr_index, needed_size, 16, false);
2214 if (needed_size > allocated_size) {2130 const debug_aranges_sect = elf_file.sections.items[shdr_index];
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 });
2223 const file_pos = debug_aranges_sect.sh_offset;2131 const file_pos = debug_aranges_sect.sh_offset;
2224 try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);2132 try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);
2225 },2133 },
2226 .macho => {2134 .macho => {
2227 const macho_file = file.cast(File.MachO).?;2135 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
2228 const d_sym = &macho_file.d_sym.?;2136 const sect_index = d_sym.debug_aranges_section_index.?;
2229 const dwarf_seg = d_sym.segments.items[d_sym.dwarf_segment_cmd_index.?];2137 try d_sym.growSection(sect_index, needed_size, false);
2230 const debug_aranges_sect = &d_sym.sections.items[d_sym.debug_aranges_section_index.?];2138 const sect = d_sym.getSection(sect_index);
2231 const allocated_size = d_sym.allocatedSize(debug_aranges_sect.offset);2139 const file_pos = 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;
2244 try d_sym.file.pwriteAll(di_buf.items, file_pos);2140 try d_sym.file.pwriteAll(di_buf.items, file_pos);
2245 },2141 },
2246 .wasm => {2142 .wasm => {
2247 const wasm_file = file.cast(File.Wasm).?;2143 const wasm_file = self.bin_file.cast(File.Wasm).?;
2248 const debug_ranges = &wasm_file.debug_ranges_atom.?.code;2144 const debug_ranges = &wasm_file.debug_ranges_atom.?.code;
2249 try debug_ranges.resize(wasm_file.base.allocator, needed_size);2145 try debug_ranges.resize(wasm_file.base.allocator, needed_size);
2250 mem.copy(u8, debug_ranges.items, di_buf.items);2146 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 {...@@ -2253,10 +2149,12 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {
2253 }2149 }
2254}2150}
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
2257 const ptr_width_bytes: u8 = self.ptrWidthBytes();2155 const ptr_width_bytes: u8 = self.ptrWidthBytes();
2258 const target_endian = self.target.cpu.arch.endian();2156 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)
2260 42158 4
2261 else switch (self.ptr_width) {2159 else switch (self.ptr_width) {
2262 .p32 => @as(usize, 4),2160 .p32 => @as(usize, 4),
...@@ -2264,29 +2162,37 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {...@@ -2264,29 +2162,37 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {
2264 };2162 };
22652163
2266 const dbg_line_prg_off = self.getDebugLineProgramOff() orelse return;2164 const dbg_line_prg_off = self.getDebugLineProgramOff() orelse return;
2267 const dbg_line_prg_end = self.getDebugLineProgramEnd().?;2165 assert(self.getDebugLineProgramEnd().? != 0);
2268 assert(dbg_line_prg_end != 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
2270 // The size of this header is variable, depending on the number of directories,2172 // The size of this header is variable, depending on the number of directories,
2271 // files, and padding. We have a function to compute the upper bound size, however,2173 // files, and padding. We have a function to compute the upper bound size, however,
2272 // because it's needed for determining where to put the offset of the first `SrcFn`.2174 // because it's needed for determining where to put the offset of the first `SrcFn`.
2273 const needed_bytes = self.dbgLineNeededHeaderBytes(module);2175 const needed_bytes = self.dbgLineNeededHeaderBytes(paths.dirs, paths.files);
2274 var di_buf = try std.ArrayList(u8).initCapacity(self.allocator, needed_bytes);2176 var di_buf = try std.ArrayList(u8).initCapacity(gpa, needed_bytes);
2275 defer di_buf.deinit();2177 defer di_buf.deinit();
22762178
2277 // initial length - length of the .debug_line contribution for this compilation unit,2179 // initial length - length of the .debug_line contribution for this compilation unit,
2278 // not including the initial length itself.2180 // not including the initial length itself.
2279 const after_init_len = di_buf.items.len + init_len_size;2181 // We will backpatch this value later so just remember where we need to write it.
2280 const init_len = dbg_line_prg_end - after_init_len;2182 const before_init_len = di_buf.items.len;
2281 if (self.tag == .macho) {2183
2282 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len));2184 switch (self.bin_file.tag) {
2283 } else switch (self.ptr_width) {2185 .macho => {
2284 .p32 => {2186 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, 0));
2285 mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian);
2286 },2187 },
2287 .p64 => {2188 else => switch (self.ptr_width) {
2288 di_buf.appendNTimesAssumeCapacity(0xff, 4);2189 .p32 => {
2289 mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian);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 },
2290 },2196 },
2291 }2197 }
22922198
...@@ -2297,7 +2203,12 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {...@@ -2297,7 +2203,12 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {
2297 // Therefore we rely on the NOP jump at the beginning of the Line Number Program for2203 // Therefore we rely on the NOP jump at the beginning of the Line Number Program for
2298 // padding rather than this field.2204 // padding rather than this field.
2299 const before_header_len = di_buf.items.len;2205 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
2301 const after_header_len = di_buf.items.len;2212 const after_header_len = di_buf.items.len;
23022213
2303 const opcode_base = DW.LNS.set_isa + 1;2214 const opcode_base = DW.LNS.set_isa + 1;
...@@ -2323,52 +2234,133 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {...@@ -2323,52 +2234,133 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {
2323 0, // `DW.LNS.set_prologue_end`2234 0, // `DW.LNS.set_prologue_end`
2324 0, // `DW.LNS.set_epilogue_begin`2235 0, // `DW.LNS.set_epilogue_begin`
2325 1, // `DW.LNS.set_isa`2236 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
2336 });2237 });
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
2338 const header_len = di_buf.items.len - after_header_len;2259 const header_len = di_buf.items.len - after_header_len;
2339 if (self.tag == .macho) {2260
2340 mem.writeIntLittle(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len));2261 switch (self.bin_file.tag) {
2341 } else switch (self.ptr_width) {2262 .macho => {
2342 .p32 => {2263 mem.writeIntLittle(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len));
2343 mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len), target_endian);
2344 },2264 },
2345 .p64 => {2265 else => switch (self.ptr_width) {
2346 mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian);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 },
2347 },2272 },
2348 }2273 }
23492274
2350 // We use NOPs because consumers empirically do not respect the header length field.2275 assert(needed_bytes == di_buf.items.len);
2276
2351 if (di_buf.items.len > dbg_line_prg_off) {2277 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.2278 const needed_with_padding = padToIdeal(needed_bytes);
2353 @panic("TODO: handle .debug_line header exceeding its padding");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 },
2354 }2345 }
2355 const jmp_amt = dbg_line_prg_off - di_buf.items.len;2346
2356 switch (self.tag) {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) {
2357 .elf => {2350 .elf => {
2358 const elf_file = file.cast(File.Elf).?;2351 const elf_file = self.bin_file.cast(File.Elf).?;
2359 const debug_line_sect = elf_file.sections.items[elf_file.debug_line_section_index.?];2352 const debug_line_sect = elf_file.sections.items[elf_file.debug_line_section_index.?];
2360 const file_pos = debug_line_sect.sh_offset;2353 const file_pos = debug_line_sect.sh_offset;
2361 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);2354 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
2362 },2355 },
2363 .macho => {2356 .macho => {
2364 const macho_file = file.cast(File.MachO).?;2357 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
2365 const d_sym = &macho_file.d_sym.?;2358 const debug_line_sect = d_sym.getSection(d_sym.debug_line_section_index.?);
2366 const debug_line_sect = d_sym.sections.items[d_sym.debug_line_section_index.?];
2367 const file_pos = debug_line_sect.offset;2359 const file_pos = debug_line_sect.offset;
2368 try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt);2360 try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt);
2369 },2361 },
2370 .wasm => {2362 .wasm => {
2371 const wasm_file = file.cast(File.Wasm).?;2363 const wasm_file = self.bin_file.cast(File.Wasm).?;
2372 const debug_line = wasm_file.debug_line_atom.?.code;2364 const debug_line = wasm_file.debug_line_atom.?.code;
2373 writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);2365 writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);
2374 },2366 },
...@@ -2404,19 +2396,32 @@ fn ptrWidthBytes(self: Dwarf) u8 {...@@ -2404,19 +2396,32 @@ fn ptrWidthBytes(self: Dwarf) u8 {
2404 };2396 };
2405}2397}
24062398
2407fn dbgLineNeededHeaderBytes(self: Dwarf, module: *Module) u32 {2399fn dbgLineNeededHeaderBytes(self: Dwarf, dirs: []const []const u8, files: []const []const u8) u32 {
2408 _ = self;2400 var size = switch (self.bin_file.tag) { // length field
2409 const directory_entry_format_count = 1;2401 .macho => @sizeOf(u32),
2410 const file_name_entry_format_count = 1;2402 else => switch (self.ptr_width) {
2411 const directory_count = 1;2403 .p32 => @as(usize, @sizeOf(u32)),
2412 const file_name_count = 1;2404 .p64 => @sizeOf(u32) + @sizeOf(u64),
2413 const root_src_dir_path_len = if (module.root_pkg.root_src_directory.path) |p| p.len else 1; // "."2405 },
2414 return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 +2406 };
2415 directory_count * 8 + file_name_count * 8 +2407 size += @sizeOf(u16); // version field
2416 // These are encoded as DW.FORM.string rather than DW.FORM.strp as we would like2408 size += switch (self.bin_file.tag) { // offset to end-of-header
2417 // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly.2409 .macho => @sizeOf(u32),
2418 root_src_dir_path_len +2410 else => self.ptrWidthBytes(),
2419 module.root_pkg.root_src_path.len);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);
2420}2425}
24212426
2422/// The reloc offset for the line offset of a function from the previous function's line.2427/// 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) {...@@ -2448,7 +2453,7 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
2448 std.math.maxInt(@TypeOf(actual_size));2453 std.math.maxInt(@TypeOf(actual_size));
2449}2454}
24502455
2451pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {2456pub fn flushModule(self: *Dwarf, module: *Module) !void {
2452 if (self.global_abbrev_relocs.items.len > 0) {2457 if (self.global_abbrev_relocs.items.len > 0) {
2453 const gpa = self.allocator;2458 const gpa = self.allocator;
2454 var arena_alloc = std.heap.ArenaAllocator.init(gpa);2459 var arena_alloc = std.heap.ArenaAllocator.init(gpa);
...@@ -2479,21 +2484,20 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {...@@ -2479,21 +2484,20 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {
24792484
2480 try self.managed_atoms.append(gpa, atom);2485 try self.managed_atoms.append(gpa, atom);
2481 log.debug("updateDeclDebugInfoAllocation in flushModule", .{});2486 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));
2483 log.debug("writeDeclDebugInfo in flushModule", .{});2488 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
2486 const file_pos = blk: {2491 const file_pos = blk: {
2487 switch (self.tag) {2492 switch (self.bin_file.tag) {
2488 .elf => {2493 .elf => {
2489 const elf_file = file.cast(File.Elf).?;2494 const elf_file = self.bin_file.cast(File.Elf).?;
2490 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];2495 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];
2491 break :blk debug_info_sect.sh_offset;2496 break :blk debug_info_sect.sh_offset;
2492 },2497 },
2493 .macho => {2498 .macho => {
2494 const macho_file = file.cast(File.MachO).?;2499 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
2495 const d_sym = &macho_file.d_sym.?;2500 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
2496 const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?];
2497 break :blk debug_info_sect.offset;2501 break :blk debug_info_sect.offset;
2498 },2502 },
2499 // for wasm, the offset is always 0 as we write to memory first2503 // 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 {...@@ -2506,18 +2510,17 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {
2506 mem.writeInt(u32, &buf, atom.off, self.target.cpu.arch.endian());2510 mem.writeInt(u32, &buf, atom.off, self.target.cpu.arch.endian());
25072511
2508 while (self.global_abbrev_relocs.popOrNull()) |reloc| {2512 while (self.global_abbrev_relocs.popOrNull()) |reloc| {
2509 switch (self.tag) {2513 switch (self.bin_file.tag) {
2510 .elf => {2514 .elf => {
2511 const elf_file = file.cast(File.Elf).?;2515 const elf_file = self.bin_file.cast(File.Elf).?;
2512 try elf_file.base.file.?.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset);2516 try elf_file.base.file.?.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset);
2513 },2517 },
2514 .macho => {2518 .macho => {
2515 const macho_file = file.cast(File.MachO).?;2519 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
2516 const d_sym = &macho_file.d_sym.?;
2517 try d_sym.file.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset);2520 try d_sym.file.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset);
2518 },2521 },
2519 .wasm => {2522 .wasm => {
2520 const wasm_file = file.cast(File.Wasm).?;2523 const wasm_file = self.bin_file.cast(File.Wasm).?;
2521 const debug_info = wasm_file.debug_info_atom.?.code;2524 const debug_info = wasm_file.debug_info_atom.?.code;
2522 mem.copy(u8, debug_info.items[reloc.atom.off + reloc.offset ..], &buf);2525 mem.copy(u8, debug_info.items[reloc.atom.off + reloc.offset ..], &buf);
2523 },2526 },
...@@ -2527,6 +2530,68 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {...@@ -2527,6 +2530,68 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {
2527 }2530 }
2528}2531}
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
2530fn addDbgInfoErrorSet(2595fn addDbgInfoErrorSet(
2531 arena: Allocator,2596 arena: Allocator,
2532 module: *Module,2597 module: *Module,
src/link/Elf.zig+118-113
...@@ -312,7 +312,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {...@@ -312,7 +312,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
312 };312 };
313313
314 var dwarf: ?Dwarf = if (!options.strip and options.module != null)314 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)
316 else316 else
317 null;317 null;
318318
...@@ -931,6 +931,104 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -931,6 +931,104 @@ pub fn populateMissingMetadata(self: *Elf) !void {
931 }931 }
932}932}
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
934pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {1032pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
935 if (self.base.options.emit == null) {1033 if (self.base.options.emit == null) {
936 if (build_options.have_llvm) {1034 if (build_options.have_llvm) {
...@@ -972,7 +1070,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -972,7 +1070,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
972 const foreign_endian = target_endian != builtin.cpu.arch.endian();1070 const foreign_endian = target_endian != builtin.cpu.arch.endian();
9731071
974 if (self.dwarf) |*dw| {1072 if (self.dwarf) |*dw| {
975 try dw.flushModule(&self.base, module);1073 try dw.flushModule(module);
976 }1074 }
9771075
978 {1076 {
...@@ -1020,7 +1118,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1020,7 +1118,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10201118
1021 if (self.dwarf) |*dw| {1119 if (self.dwarf) |*dw| {
1022 if (self.debug_abbrev_section_dirty) {1120 if (self.debug_abbrev_section_dirty) {
1023 try dw.writeDbgAbbrev(&self.base);1121 try dw.writeDbgAbbrev();
1024 if (!self.shdr_table_dirty) {1122 if (!self.shdr_table_dirty) {
1025 // Then it won't get written with the others and we need to do it.1123 // Then it won't get written with the others and we need to do it.
1026 try self.writeSectHeader(self.debug_abbrev_section_index.?);1124 try self.writeSectHeader(self.debug_abbrev_section_index.?);
...@@ -1034,7 +1132,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1034,7 +1132,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1034 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];1132 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1035 const low_pc = text_phdr.p_vaddr;1133 const low_pc = text_phdr.p_vaddr;
1036 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;1134 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);
1038 self.debug_info_header_dirty = false;1136 self.debug_info_header_dirty = false;
1039 }1137 }
10401138
...@@ -1042,7 +1140,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1042,7 +1140,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1042 // Currently only one compilation unit is supported, so the address range is simply1140 // Currently only one compilation unit is supported, so the address range is simply
1043 // identical to the main program header virtual address and memory size.1141 // identical to the main program header virtual address and memory size.
1044 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];1142 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);
1046 if (!self.shdr_table_dirty) {1144 if (!self.shdr_table_dirty) {
1047 // Then it won't get written with the others and we need to do it.1145 // Then it won't get written with the others and we need to do it.
1048 try self.writeSectHeader(self.debug_aranges_section_index.?);1146 try self.writeSectHeader(self.debug_aranges_section_index.?);
...@@ -1051,7 +1149,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1051,7 +1149,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1051 }1149 }
10521150
1053 if (self.debug_line_header_dirty) {1151 if (self.debug_line_header_dirty) {
1054 try dw.writeDbgLineHeader(&self.base, module);1152 try dw.writeDbgLineHeader(module);
1055 self.debug_line_header_dirty = false;1153 self.debug_line_header_dirty = false;
1056 }1154 }
1057 }1155 }
...@@ -1103,45 +1201,21 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1103,45 +1201,21 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1103 }1201 }
11041202
1105 {1203 {
1106 const shstrtab_sect = &self.sections.items[self.shstrtab_index.?];1204 const shdr_index = self.shstrtab_index.?;
1107 if (self.shstrtab_dirty or self.shstrtab.items.len != shstrtab_sect.sh_size) {1205 if (self.shstrtab_dirty or self.shstrtab.items.len != self.sections.items[shdr_index].sh_size) {
1108 const allocated_size = self.allocatedSize(shstrtab_sect.sh_offset);1206 try self.growNonAllocSection(shdr_index, self.shstrtab.items.len, 1, false);
1109 const needed_size = self.shstrtab.items.len;1207 const shstrtab_sect = self.sections.items[shdr_index];
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
1118 try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);1208 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 }
1123 self.shstrtab_dirty = false;1209 self.shstrtab_dirty = false;
1124 }1210 }
1125 }1211 }
11261212
1127 if (self.dwarf) |dwarf| {1213 if (self.dwarf) |dwarf| {
1128 const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?];1214 const shdr_index = self.debug_str_section_index.?;
1129 if (self.debug_strtab_dirty or dwarf.strtab.items.len != debug_strtab_sect.sh_size) {1215 if (self.debug_strtab_dirty or dwarf.strtab.items.len != self.sections.items[shdr_index].sh_size) {
1130 const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset);1216 try self.growNonAllocSection(shdr_index, dwarf.strtab.items.len, 1, false);
1131 const needed_size = dwarf.strtab.items.len;1217 const debug_strtab_sect = self.sections.items[shdr_index];
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
1140 try self.base.file.?.pwriteAll(dwarf.strtab.items, debug_strtab_sect.sh_offset);1218 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 }
1145 self.debug_strtab_dirty = false;1219 self.debug_strtab_dirty = false;
1146 }1220 }
1147 }1221 }
...@@ -2134,27 +2208,10 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al...@@ -2134,27 +2208,10 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
21342208
2135 const expand_text_section = block_placement == null or block_placement.?.next == null;2209 const expand_text_section = block_placement == null or block_placement.?.next == null;
2136 if (expand_text_section) {2210 if (expand_text_section) {
2137 const text_capacity = self.allocatedSize(shdr.sh_offset);
2138 const needed_size = (vaddr + new_block_size) - phdr.p_vaddr;2211 const needed_size = (vaddr + new_block_size) - phdr.p_vaddr;
2139 if (needed_size > text_capacity) {2212 try self.growAllocSection(shdr_index, phdr_index, needed_size);
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 }
2152 _ = try self.atoms.put(self.base.allocator, phdr_index, text_block);2213 _ = 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
2158 if (self.dwarf) |_| {2215 if (self.dwarf) |_| {
2159 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address2216 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
2160 // range of the compilation unit. When we expand the text section, this range changes,2217 // 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...@@ -2165,9 +2222,6 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
2165 // model each package as a different compilation unit.2222 // model each package as a different compilation unit.
2166 self.debug_aranges_section_dirty = true;2223 self.debug_aranges_section_dirty = true;
2167 }2224 }
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
2171 }2225 }
2172 shdr.sh_addralign = math.max(shdr.sh_addralign, alignment);2226 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...@@ -2422,7 +2476,6 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
2422 const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC);2476 const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC);
2423 if (decl_state) |*ds| {2477 if (decl_state) |*ds| {
2424 try self.dwarf.?.commitDeclState(2478 try self.dwarf.?.commitDeclState(
2425 &self.base,
2426 module,2479 module,
2427 decl_index,2480 decl_index,
2428 local_sym.st_value,2481 local_sym.st_value,
...@@ -2499,7 +2552,6 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v...@@ -2499,7 +2552,6 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
2499 const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT);2552 const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT);
2500 if (decl_state) |*ds| {2553 if (decl_state) |*ds| {
2501 try self.dwarf.?.commitDeclState(2554 try self.dwarf.?.commitDeclState(
2502 &self.base,
2503 module,2555 module,
2504 decl_index,2556 decl_index,
2505 local_sym.st_value,2557 local_sym.st_value,
...@@ -2692,7 +2744,7 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl)...@@ -2692,7 +2744,7 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl)
26922744
2693 if (self.llvm_object) |_| return;2745 if (self.llvm_object) |_| return;
2694 if (self.dwarf) |*dw| {2746 if (self.dwarf) |*dw| {
2695 try dw.updateDeclLineNumber(&self.base, decl);2747 try dw.updateDeclLineNumber(decl);
2696 }2748 }
2697}2749}
26982750
...@@ -2749,31 +2801,14 @@ fn writeSectHeader(self: *Elf, index: usize) !void {...@@ -2749,31 +2801,14 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
2749}2801}
27502802
2751fn writeOffsetTableEntry(self: *Elf, index: usize) !void {2803fn 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.?];
2754 const entry_size: u16 = self.archPtrWidthBytes();2804 const entry_size: u16 = self.archPtrWidthBytes();
2755 if (self.offset_table_count_dirty) {2805 if (self.offset_table_count_dirty) {
2756 // TODO Also detect virtual address collisions.
2757 const allocated_size = self.allocatedSize(shdr.sh_offset);
2758 const needed_size = self.offset_table.items.len * entry_size;2806 const needed_size = self.offset_table.items.len * entry_size;
2759 if (needed_size > allocated_size) {2807 try self.growAllocSection(self.got_section_index.?, self.phdr_got_index.?, needed_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
2774 self.offset_table_count_dirty = false;2808 self.offset_table_count_dirty = false;
2775 }2809 }
2776 const endian = self.base.options.target.cpu.arch.endian();2810 const endian = self.base.options.target.cpu.arch.endian();
2811 const shdr = &self.sections.items[self.got_section_index.?];
2777 const off = shdr.sh_offset + @as(u64, entry_size) * index;2812 const off = shdr.sh_offset + @as(u64, entry_size) * index;
2778 switch (entry_size) {2813 switch (entry_size) {
2779 2 => {2814 2 => {
...@@ -2812,23 +2847,8 @@ fn writeSymbol(self: *Elf, index: usize) !void {...@@ -2812,23 +2847,8 @@ fn writeSymbol(self: *Elf, index: usize) !void {
2812 .p64 => @alignOf(elf.Elf64_Sym),2847 .p64 => @alignOf(elf.Elf64_Sym),
2813 };2848 };
2814 const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size;2849 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)) {2850 try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, true);
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 }
2829 syms_sect.sh_info = @intCast(u32, self.local_symbols.items.len);2851 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
2832 }2852 }
2833 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();2853 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
2834 const off = switch (self.ptr_width) {2854 const off = switch (self.ptr_width) {
...@@ -2876,22 +2896,7 @@ fn writeAllGlobalSymbols(self: *Elf) !void {...@@ -2876,22 +2896,7 @@ fn writeAllGlobalSymbols(self: *Elf) !void {
2876 .p64 => @alignOf(elf.Elf64_Sym),2896 .p64 => @alignOf(elf.Elf64_Sym),
2877 };2897 };
2878 const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size;2898 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)) {2899 try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, true);
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
28952900
2896 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();2901 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
2897 const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size;2902 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 {...@@ -347,7 +347,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
347347
348 self.d_sym = .{348 self.d_sym = .{
349 .allocator = allocator,349 .allocator = allocator,
350 .dwarf = link.File.Dwarf.init(allocator, .macho, options.target),350 .dwarf = link.File.Dwarf.init(allocator, &self.base, options.target),
351 .file = d_sym_file,351 .file = d_sym_file,
352 .page_size = self.page_size,352 .page_size = self.page_size,
353 };353 };
...@@ -449,7 +449,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -449,7 +449,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
449 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;449 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
450450
451 if (self.d_sym) |*d_sym| {451 if (self.d_sym) |*d_sym| {
452 try d_sym.dwarf.flushModule(&self.base, module);452 try d_sym.dwarf.flushModule(module);
453 }453 }
454454
455 var libs = std.StringArrayHashMap(link.SystemLib).init(arena);455 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...@@ -2213,7 +2213,6 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
22132213
2214 if (decl_state) |*ds| {2214 if (decl_state) |*ds| {
2215 try self.d_sym.?.dwarf.commitDeclState(2215 try self.d_sym.?.dwarf.commitDeclState(
2216 &self.base,
2217 module,2216 module,
2218 decl_index,2217 decl_index,
2219 addr,2218 addr,
...@@ -2364,7 +2363,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -2364,7 +2363,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
23642363
2365 if (decl_state) |*ds| {2364 if (decl_state) |*ds| {
2366 try self.d_sym.?.dwarf.commitDeclState(2365 try self.d_sym.?.dwarf.commitDeclState(
2367 &self.base,
2368 module,2366 module,
2369 decl_index,2367 decl_index,
2370 addr,2368 addr,
...@@ -2603,7 +2601,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)...@@ -2603,7 +2601,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
2603pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {2601pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {
2604 _ = module;2602 _ = module;
2605 if (self.d_sym) |*d_sym| {2603 if (self.d_sym) |*d_sym| {
2606 try d_sym.dwarf.updateDeclLineNumber(&self.base, decl);2604 try d_sym.dwarf.updateDeclLineNumber(decl);
2607 }2605 }
2608}2606}
26092607
...@@ -4302,6 +4300,11 @@ pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {...@@ -4302,6 +4300,11 @@ pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {
4302 return global;4300 return global;
4303}4301}
43044302
4303pub fn getDebugSymbols(self: *MachO) ?*DebugSymbols {
4304 if (self.d_sym == null) return null;
4305 return &self.d_sym.?;
4306}
4307
4305pub fn findFirst(comptime T: type, haystack: []align(1) const T, start: usize, predicate: anytype) usize {4308pub fn findFirst(comptime T: type, haystack: []align(1) const T, start: usize, predicate: anytype) usize {
4306 if (!@hasDecl(@TypeOf(predicate), "predicate"))4309 if (!@hasDecl(@TypeOf(predicate), "predicate"))
4307 @compileError("Predicate is required to define fn predicate(@This(), T) bool");4310 @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...@@ -137,7 +137,6 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
137 off + size,137 off + size,
138 });138 });
139139
140 sect.addr = segment.vmaddr + off - segment.fileoff;
141 sect.offset = @intCast(u32, off);140 sect.offset = @intCast(u32, off);
142141
143 const index = @intCast(u8, self.sections.items.len);142 const index = @intCast(u8, self.sections.items.len);
...@@ -148,6 +147,52 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme...@@ -148,6 +147,52 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
148 return index;147 return index;
149}148}
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
151fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {196fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {
152 const end = start + padToIdeal(size);197 const end = start + padToIdeal(size);
153 for (self.sections.items) |section| {198 for (self.sections.items) |section| {
...@@ -160,7 +205,7 @@ fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {...@@ -160,7 +205,7 @@ fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {
160 return null;205 return null;
161}206}
162207
163pub fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 {208fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 {
164 const segment = self.getDwarfSegmentPtr();209 const segment = self.getDwarfSegmentPtr();
165 var offset: u64 = segment.fileoff;210 var offset: u64 = segment.fileoff;
166 while (self.detectAllocCollision(offset, object_size)) |item_end| {211 while (self.detectAllocCollision(offset, object_size)) |item_end| {
...@@ -213,7 +258,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -213,7 +258,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
213 }258 }
214259
215 if (self.debug_abbrev_section_dirty) {260 if (self.debug_abbrev_section_dirty) {
216 try self.dwarf.writeDbgAbbrev(&macho_file.base);261 try self.dwarf.writeDbgAbbrev();
217 self.debug_abbrev_section_dirty = false;262 self.debug_abbrev_section_dirty = false;
218 }263 }
219264
...@@ -223,7 +268,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -223,7 +268,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
223 const text_section = macho_file.sections.items(.header)[macho_file.text_section_index.?];268 const text_section = macho_file.sections.items(.header)[macho_file.text_section_index.?];
224 const low_pc = text_section.addr;269 const low_pc = text_section.addr;
225 const high_pc = text_section.addr + text_section.size;270 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);
227 self.debug_info_header_dirty = false;272 self.debug_info_header_dirty = false;
228 }273 }
229274
...@@ -231,36 +276,21 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -231,36 +276,21 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
231 // Currently only one compilation unit is supported, so the address range is simply276 // Currently only one compilation unit is supported, so the address range is simply
232 // identical to the main program header virtual address and memory size.277 // identical to the main program header virtual address and memory size.
233 const text_section = macho_file.sections.items(.header)[macho_file.text_section_index.?];278 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);
235 self.debug_aranges_section_dirty = false;280 self.debug_aranges_section_dirty = false;
236 }281 }
237282
238 if (self.debug_line_header_dirty) {283 if (self.debug_line_header_dirty) {
239 try self.dwarf.writeDbgLineHeader(&macho_file.base, module);284 try self.dwarf.writeDbgLineHeader(module);
240 self.debug_line_header_dirty = false;285 self.debug_line_header_dirty = false;
241 }286 }
242287
243 {288 {
244 const dwarf_segment = self.getDwarfSegmentPtr();289 const sect_index = self.debug_str_section_index.?;
245 const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?];290 if (self.debug_string_table_dirty or self.dwarf.strtab.items.len != self.getSection(sect_index).size) {
246 if (self.debug_string_table_dirty or self.dwarf.strtab.items.len != debug_strtab_sect.size) {291 const needed_size = @intCast(u32, self.dwarf.strtab.items.len);
247 const allocated_size = self.allocatedSize(debug_strtab_sect.offset);292 try self.growSection(sect_index, needed_size, false);
248 const needed_size = self.dwarf.strtab.items.len;293 try self.file.pwriteAll(self.dwarf.strtab.items, self.getSection(sect_index).offset);
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);
264 self.debug_string_table_dirty = false;294 self.debug_string_table_dirty = false;
265 }295 }
266 }296 }
...@@ -424,7 +454,7 @@ fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: u32, sizeofcmds:...@@ -424,7 +454,7 @@ fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: u32, sizeofcmds:
424 try self.file.pwriteAll(mem.asBytes(&header), 0);454 try self.file.pwriteAll(mem.asBytes(&header), 0);
425}455}
426456
427pub fn allocatedSize(self: *DebugSymbols, start: u64) u64 {457fn allocatedSize(self: *DebugSymbols, start: u64) u64 {
428 const seg = self.getDwarfSegmentPtr();458 const seg = self.getDwarfSegmentPtr();
429 assert(start >= seg.fileoff);459 assert(start >= seg.fileoff);
430 var min_pos: u64 = std.math.maxInt(u64);460 var min_pos: u64 = std.math.maxInt(u64);
...@@ -556,3 +586,13 @@ fn getLinkeditSegmentPtr(self: *DebugSymbols) *macho.segment_command_64 {...@@ -556,3 +586,13 @@ fn getLinkeditSegmentPtr(self: *DebugSymbols) *macho.segment_command_64 {
556 const index = self.linkedit_segment_cmd_index.?;586 const index = self.linkedit_segment_cmd_index.?;
557 return &self.segments.items[index];587 return &self.segments.items[index];
558}588}
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...@@ -361,7 +361,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
361 }361 }
362362
363 if (!options.strip and options.module != null) {363 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);
365 try wasm_bin.initDebugSections();365 try wasm_bin.initDebugSections();
366 }366 }
367367
...@@ -910,7 +910,6 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes...@@ -910,7 +910,6 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
910910
911 if (wasm.dwarf) |*dwarf| {911 if (wasm.dwarf) |*dwarf| {
912 try dwarf.commitDeclState(912 try dwarf.commitDeclState(
913 &wasm.base,
914 mod,913 mod,
915 decl_index,914 decl_index,
916 // Actual value will be written after relocation.915 // Actual value will be written after relocation.
...@@ -990,7 +989,7 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl: *const Module.Decl)...@@ -990,7 +989,7 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl: *const Module.Decl)
990 defer wasm.base.allocator.free(decl_name);989 defer wasm.base.allocator.free(decl_name);
991990
992 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });991 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
993 try dw.updateDeclLineNumber(&wasm.base, decl);992 try dw.updateDeclLineNumber(decl);
994 }993 }
995}994}
996995
...@@ -2299,7 +2298,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2299,7 +2298,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2299 }2298 }
23002299
2301 if (wasm.dwarf) |*dwarf| {2300 if (wasm.dwarf) |*dwarf| {
2302 try dwarf.flushModule(&wasm.base, wasm.base.options.module.?);2301 try dwarf.flushModule(wasm.base.options.module.?);
2303 }2302 }
2304 }2303 }
23052304
...@@ -2668,12 +2667,12 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2668,12 +2667,12 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2668 if (!wasm.base.options.strip) {2667 if (!wasm.base.options.strip) {
2669 if (wasm.dwarf) |*dwarf| {2668 if (wasm.dwarf) |*dwarf| {
2670 const mod = wasm.base.options.module.?;2669 const mod = wasm.base.options.module.?;
2671 try dwarf.writeDbgAbbrev(&wasm.base);2670 try dwarf.writeDbgAbbrev();
2672 // for debug info and ranges, the address is always 0,2671 // for debug info and ranges, the address is always 0,
2673 // as locations are always offsets relative to 'code' section.2672 // as locations are always offsets relative to 'code' section.
2674 try dwarf.writeDbgInfoHeader(&wasm.base, mod, 0, code_section_size);2673 try dwarf.writeDbgInfoHeader(mod, 0, code_section_size);
2675 try dwarf.writeDbgAranges(&wasm.base, 0, code_section_size);2674 try dwarf.writeDbgAranges(0, code_section_size);
2676 try dwarf.writeDbgLineHeader(&wasm.base, mod);2675 try dwarf.writeDbgLineHeader(mod);
2677 }2676 }
26782677
2679 var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator);2678 var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator);