| ... | ... | @@ -22,7 +22,7 @@ const Value = @import("../value.zig").Value; |
| 22 | 22 | const Type = @import("../type.zig").Type; |
| 23 | 23 | |
| 24 | 24 | allocator: Allocator, |
| 25 | | tag: File.Tag, |
| 25 | bin_file: *File, |
| 26 | 26 | ptr_width: PtrWidth, |
| 27 | 27 | target: std.Target, |
| 28 | 28 | |
| ... | ... | @@ -44,6 +44,12 @@ abbrev_table_offset: ?u64 = null, |
| 44 | 44 | /// Table of debug symbol names. |
| 45 | 45 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 46 | 46 | |
| 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 |
| 51 | di_files: std.AutoArrayHashMapUnmanaged(*const Module.File, void) = .{}, |
| 52 | |
| 47 | 53 | /// List of atoms that are owned directly by the DWARF module. |
| 48 | 54 | /// TODO convert links in DebugInfoAtom into indices and make |
| 49 | 55 | /// sure every atom is owned by this module. |
| ... | ... | @@ -887,7 +893,7 @@ const min_nop_size = 2; |
| 887 | 893 | /// actual_capacity + (actual_capacity / ideal_factor) |
| 888 | 894 | const ideal_factor = 3; |
| 889 | 895 | |
| 890 | | pub fn init(allocator: Allocator, tag: File.Tag, target: std.Target) Dwarf { |
| 896 | pub fn init(allocator: Allocator, bin_file: *File, target: std.Target) Dwarf { |
| 891 | 897 | const ptr_width: PtrWidth = switch (target.cpu.arch.ptrBitWidth()) { |
| 892 | 898 | 0...32 => .p32, |
| 893 | 899 | 33...64 => .p64, |
| ... | ... | @@ -895,7 +901,7 @@ pub fn init(allocator: Allocator, tag: File.Tag, target: std.Target) Dwarf { |
| 895 | 901 | }; |
| 896 | 902 | return Dwarf{ |
| 897 | 903 | .allocator = allocator, |
| 898 | | .tag = tag, |
| 904 | .bin_file = bin_file, |
| 899 | 905 | .ptr_width = ptr_width, |
| 900 | 906 | .target = target, |
| 901 | 907 | }; |
| ... | ... | @@ -906,6 +912,7 @@ pub fn deinit(self: *Dwarf) void { |
| 906 | 912 | self.dbg_line_fn_free_list.deinit(gpa); |
| 907 | 913 | self.atom_free_list.deinit(gpa); |
| 908 | 914 | self.strtab.deinit(gpa); |
| 915 | self.di_files.deinit(gpa); |
| 909 | 916 | self.global_abbrev_relocs.deinit(gpa); |
| 910 | 917 | |
| 911 | 918 | for (self.managed_atoms.items) |atom| { |
| ... | ... | @@ -968,7 +975,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) |
| 968 | 975 | assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len); |
| 969 | 976 | // Once we support more than one source file, this will have the ability to be more |
| 970 | 977 | // than one possible value. |
| 971 | | const file_index = 1; |
| 978 | const file_index = try self.addDIFile(mod, decl_index); |
| 972 | 979 | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index); |
| 973 | 980 | |
| 974 | 981 | // 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 | 1002 | dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4 |
| 996 | 1003 | // |
| 997 | 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 | 1006 | try decl_state.addTypeRelocGlobal(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len)); |
| 1000 | 1007 | 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 | 1020 | |
| 1014 | 1021 | pub fn commitDeclState( |
| 1015 | 1022 | self: *Dwarf, |
| 1016 | | file: *File, |
| 1017 | 1023 | module: *Module, |
| 1018 | 1024 | decl_index: Module.Decl.Index, |
| 1019 | 1025 | sym_addr: u64, |
| ... | ... | @@ -1069,7 +1075,7 @@ pub fn commitDeclState( |
| 1069 | 1075 | // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for |
| 1070 | 1076 | // `TextBlock` and the .debug_info. If you are editing this logic, you |
| 1071 | 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 | 1079 | .elf => &decl.fn_link.elf, |
| 1074 | 1080 | .macho => &decl.fn_link.macho, |
| 1075 | 1081 | .wasm => &decl.fn_link.wasm.src_fn, |
| ... | ... | @@ -1090,22 +1096,21 @@ pub fn commitDeclState( |
| 1090 | 1096 | next.prev = src_fn.prev; |
| 1091 | 1097 | src_fn.next = null; |
| 1092 | 1098 | // Populate where it used to be with NOPs. |
| 1093 | | switch (self.tag) { |
| 1099 | switch (self.bin_file.tag) { |
| 1094 | 1100 | .elf => { |
| 1095 | | const elf_file = file.cast(File.Elf).?; |
| 1101 | const elf_file = self.bin_file.cast(File.Elf).?; |
| 1096 | 1102 | const debug_line_sect = &elf_file.sections.items[elf_file.debug_line_section_index.?]; |
| 1097 | 1103 | const file_pos = debug_line_sect.sh_offset + src_fn.off; |
| 1098 | 1104 | try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len); |
| 1099 | 1105 | }, |
| 1100 | 1106 | .macho => { |
| 1101 | | const macho_file = file.cast(File.MachO).?; |
| 1102 | | const d_sym = &macho_file.d_sym.?; |
| 1103 | | const debug_line_sect = &d_sym.sections.items[d_sym.debug_line_section_index.?]; |
| 1107 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 1108 | const debug_line_sect = d_sym.getSectionPtr(d_sym.debug_line_section_index.?); |
| 1104 | 1109 | const file_pos = debug_line_sect.offset + src_fn.off; |
| 1105 | 1110 | try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len); |
| 1106 | 1111 | }, |
| 1107 | 1112 | .wasm => { |
| 1108 | | const wasm_file = file.cast(File.Wasm).?; |
| 1113 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| 1109 | 1114 | const debug_line = wasm_file.debug_line_atom.?.code; |
| 1110 | 1115 | writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len); |
| 1111 | 1116 | }, |
| ... | ... | @@ -1132,7 +1137,7 @@ pub fn commitDeclState( |
| 1132 | 1137 | self.dbg_line_fn_first = src_fn; |
| 1133 | 1138 | self.dbg_line_fn_last = src_fn; |
| 1134 | 1139 | |
| 1135 | | src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(module)); |
| 1140 | src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{})); |
| 1136 | 1141 | } |
| 1137 | 1142 | |
| 1138 | 1143 | const last_src_fn = self.dbg_line_fn_last.?; |
| ... | ... | @@ -1142,32 +1147,12 @@ pub fn commitDeclState( |
| 1142 | 1147 | |
| 1143 | 1148 | // We only have support for one compilation unit so far, so the offsets are directly |
| 1144 | 1149 | // from the .debug_line section. |
| 1145 | | switch (self.tag) { |
| 1150 | switch (self.bin_file.tag) { |
| 1146 | 1151 | .elf => { |
| 1147 | | const elf_file = file.cast(File.Elf).?; |
| 1148 | | const debug_line_sect = &elf_file.sections.items[elf_file.debug_line_section_index.?]; |
| 1149 | | if (needed_size != debug_line_sect.sh_size) { |
| 1150 | | if (needed_size > elf_file.allocatedSize(debug_line_sect.sh_offset)) { |
| 1151 | | const new_offset = elf_file.findFreeSpace(needed_size, 1); |
| 1152 | | const existing_size = last_src_fn.off; |
| 1153 | | log.debug("moving .debug_line section: {d} bytes from 0x{x} to 0x{x}", .{ |
| 1154 | | existing_size, |
| 1155 | | debug_line_sect.sh_offset, |
| 1156 | | new_offset, |
| 1157 | | }); |
| 1158 | | const amt = try elf_file.base.file.?.copyRangeAll( |
| 1159 | | debug_line_sect.sh_offset, |
| 1160 | | elf_file.base.file.?, |
| 1161 | | new_offset, |
| 1162 | | existing_size, |
| 1163 | | ); |
| 1164 | | if (amt != existing_size) return error.InputOutput; |
| 1165 | | debug_line_sect.sh_offset = new_offset; |
| 1166 | | } |
| 1167 | | debug_line_sect.sh_size = needed_size; |
| 1168 | | elf_file.shdr_table_dirty = true; // TODO look into making only the one section dirty |
| 1169 | | elf_file.debug_line_header_dirty = true; |
| 1170 | | } |
| 1152 | const elf_file = self.bin_file.cast(File.Elf).?; |
| 1153 | const shdr_index = elf_file.debug_line_section_index.?; |
| 1154 | try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true); |
| 1155 | const debug_line_sect = elf_file.sections.items[shdr_index]; |
| 1171 | 1156 | const file_pos = debug_line_sect.sh_offset + src_fn.off; |
| 1172 | 1157 | try pwriteDbgLineNops( |
| 1173 | 1158 | elf_file.base.file.?, |
| ... | ... | @@ -1179,31 +1164,11 @@ pub fn commitDeclState( |
| 1179 | 1164 | }, |
| 1180 | 1165 | |
| 1181 | 1166 | .macho => { |
| 1182 | | const macho_file = file.cast(File.MachO).?; |
| 1183 | | const d_sym = &macho_file.d_sym.?; |
| 1184 | | const debug_line_sect = &d_sym.sections.items[d_sym.debug_line_section_index.?]; |
| 1185 | | if (needed_size != debug_line_sect.size) { |
| 1186 | | if (needed_size > d_sym.allocatedSize(debug_line_sect.offset)) { |
| 1187 | | const new_offset = d_sym.findFreeSpace(needed_size, 1); |
| 1188 | | const existing_size = last_src_fn.off; |
| 1189 | | std.log.scoped(.dsym).debug("moving __debug_line section: {} bytes from 0x{x} to 0x{x}", .{ |
| 1190 | | existing_size, |
| 1191 | | debug_line_sect.offset, |
| 1192 | | new_offset, |
| 1193 | | }); |
| 1194 | | const amt = try d_sym.file.copyRangeAll( |
| 1195 | | debug_line_sect.offset, |
| 1196 | | d_sym.file, |
| 1197 | | new_offset, |
| 1198 | | existing_size, |
| 1199 | | ); |
| 1200 | | if (amt != existing_size) return error.InputOutput; |
| 1201 | | debug_line_sect.offset = @intCast(u32, new_offset); |
| 1202 | | } |
| 1203 | | debug_line_sect.size = needed_size; |
| 1204 | | d_sym.debug_line_header_dirty = true; |
| 1205 | | } |
| 1206 | | const file_pos = debug_line_sect.offset + src_fn.off; |
| 1167 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 1168 | const sect_index = d_sym.debug_line_section_index.?; |
| 1169 | try d_sym.growSection(sect_index, needed_size, true); |
| 1170 | const sect = d_sym.getSection(sect_index); |
| 1171 | const file_pos = sect.offset + src_fn.off; |
| 1207 | 1172 | try pwriteDbgLineNops( |
| 1208 | 1173 | d_sym.file, |
| 1209 | 1174 | file_pos, |
| ... | ... | @@ -1214,7 +1179,7 @@ pub fn commitDeclState( |
| 1214 | 1179 | }, |
| 1215 | 1180 | |
| 1216 | 1181 | .wasm => { |
| 1217 | | const wasm_file = file.cast(File.Wasm).?; |
| 1182 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| 1218 | 1183 | const atom = wasm_file.debug_line_atom.?; |
| 1219 | 1184 | const debug_line = &atom.code; |
| 1220 | 1185 | const segment_size = debug_line.items.len; |
| ... | ... | @@ -1247,7 +1212,7 @@ pub fn commitDeclState( |
| 1247 | 1212 | if (dbg_info_buffer.items.len == 0) |
| 1248 | 1213 | return; |
| 1249 | 1214 | |
| 1250 | | const atom = getDbgInfoAtom(self.tag, module, decl_index); |
| 1215 | const atom = getDbgInfoAtom(self.bin_file.tag, module, decl_index); |
| 1251 | 1216 | if (decl_state.abbrev_table.items.len > 0) { |
| 1252 | 1217 | // Now we emit the .debug_info types of the Decl. These will count towards the size of |
| 1253 | 1218 | // 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 | 1239 | } |
| 1275 | 1240 | |
| 1276 | 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)); |
| 1278 | 1243 | |
| 1279 | 1244 | while (decl_state.abbrev_relocs.popOrNull()) |reloc| { |
| 1280 | 1245 | if (reloc.target) |target| { |
| ... | ... | @@ -1319,10 +1284,9 @@ pub fn commitDeclState( |
| 1319 | 1284 | } |
| 1320 | 1285 | |
| 1321 | 1286 | while (decl_state.exprloc_relocs.popOrNull()) |reloc| { |
| 1322 | | switch (self.tag) { |
| 1287 | switch (self.bin_file.tag) { |
| 1323 | 1288 | .macho => { |
| 1324 | | const macho_file = file.cast(File.MachO).?; |
| 1325 | | const d_sym = &macho_file.d_sym.?; |
| 1289 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 1326 | 1290 | try d_sym.relocs.append(d_sym.allocator, .{ |
| 1327 | 1291 | .type = switch (reloc.type) { |
| 1328 | 1292 | .direct_load => .direct_load, |
| ... | ... | @@ -1339,10 +1303,10 @@ pub fn commitDeclState( |
| 1339 | 1303 | } |
| 1340 | 1304 | |
| 1341 | 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 | } |
| 1344 | 1308 | |
| 1345 | | fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u32) !void { |
| 1309 | fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void { |
| 1346 | 1310 | const tracy = trace(@src()); |
| 1347 | 1311 | defer tracy.end(); |
| 1348 | 1312 | |
| ... | ... | @@ -1365,22 +1329,21 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3 |
| 1365 | 1329 | next.prev = atom.prev; |
| 1366 | 1330 | atom.next = null; |
| 1367 | 1331 | // Populate where it used to be with NOPs. |
| 1368 | | switch (self.tag) { |
| 1332 | switch (self.bin_file.tag) { |
| 1369 | 1333 | .elf => { |
| 1370 | | const elf_file = file.cast(File.Elf).?; |
| 1334 | const elf_file = self.bin_file.cast(File.Elf).?; |
| 1371 | 1335 | const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?]; |
| 1372 | 1336 | const file_pos = debug_info_sect.sh_offset + atom.off; |
| 1373 | 1337 | try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false); |
| 1374 | 1338 | }, |
| 1375 | 1339 | .macho => { |
| 1376 | | const macho_file = file.cast(File.MachO).?; |
| 1377 | | const d_sym = &macho_file.d_sym.?; |
| 1378 | | const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?]; |
| 1340 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 1341 | const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?); |
| 1379 | 1342 | const file_pos = debug_info_sect.offset + atom.off; |
| 1380 | 1343 | try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false); |
| 1381 | 1344 | }, |
| 1382 | 1345 | .wasm => { |
| 1383 | | const wasm_file = file.cast(File.Wasm).?; |
| 1346 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| 1384 | 1347 | const debug_info = &wasm_file.debug_info_atom.?.code; |
| 1385 | 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 | 1374 | } |
| 1412 | 1375 | } |
| 1413 | 1376 | |
| 1414 | | fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []const u8) !void { |
| 1377 | fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void { |
| 1415 | 1378 | const tracy = trace(@src()); |
| 1416 | 1379 | defer tracy.end(); |
| 1417 | 1380 | |
| ... | ... | @@ -1431,32 +1394,12 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co |
| 1431 | 1394 | |
| 1432 | 1395 | // We only have support for one compilation unit so far, so the offsets are directly |
| 1433 | 1396 | // from the .debug_info section. |
| 1434 | | switch (self.tag) { |
| 1397 | switch (self.bin_file.tag) { |
| 1435 | 1398 | .elf => { |
| 1436 | | const elf_file = file.cast(File.Elf).?; |
| 1437 | | const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?]; |
| 1438 | | if (needed_size != debug_info_sect.sh_size) { |
| 1439 | | if (needed_size > elf_file.allocatedSize(debug_info_sect.sh_offset)) { |
| 1440 | | const new_offset = elf_file.findFreeSpace(needed_size, 1); |
| 1441 | | const existing_size = last_decl.off; |
| 1442 | | log.debug("moving .debug_info section: {d} bytes from 0x{x} to 0x{x}", .{ |
| 1443 | | existing_size, |
| 1444 | | debug_info_sect.sh_offset, |
| 1445 | | new_offset, |
| 1446 | | }); |
| 1447 | | const amt = try elf_file.base.file.?.copyRangeAll( |
| 1448 | | debug_info_sect.sh_offset, |
| 1449 | | elf_file.base.file.?, |
| 1450 | | new_offset, |
| 1451 | | existing_size, |
| 1452 | | ); |
| 1453 | | if (amt != existing_size) return error.InputOutput; |
| 1454 | | debug_info_sect.sh_offset = new_offset; |
| 1455 | | } |
| 1456 | | debug_info_sect.sh_size = needed_size; |
| 1457 | | elf_file.shdr_table_dirty = true; // TODO look into making only the one section dirty |
| 1458 | | elf_file.debug_info_header_dirty = true; |
| 1459 | | } |
| 1399 | const elf_file = self.bin_file.cast(File.Elf).?; |
| 1400 | const shdr_index = elf_file.debug_info_section_index.?; |
| 1401 | try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true); |
| 1402 | const debug_info_sect = elf_file.sections.items[shdr_index]; |
| 1460 | 1403 | const file_pos = debug_info_sect.sh_offset + atom.off; |
| 1461 | 1404 | try pwriteDbgInfoNops( |
| 1462 | 1405 | elf_file.base.file.?, |
| ... | ... | @@ -1469,31 +1412,11 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co |
| 1469 | 1412 | }, |
| 1470 | 1413 | |
| 1471 | 1414 | .macho => { |
| 1472 | | const macho_file = file.cast(File.MachO).?; |
| 1473 | | const d_sym = &macho_file.d_sym.?; |
| 1474 | | const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?]; |
| 1475 | | if (needed_size != debug_info_sect.size) { |
| 1476 | | if (needed_size > d_sym.allocatedSize(debug_info_sect.offset)) { |
| 1477 | | const new_offset = d_sym.findFreeSpace(needed_size, 1); |
| 1478 | | const existing_size = last_decl.off; |
| 1479 | | std.log.scoped(.dsym).debug("moving __debug_info section: {} bytes from 0x{x} to 0x{x}", .{ |
| 1480 | | existing_size, |
| 1481 | | debug_info_sect.offset, |
| 1482 | | new_offset, |
| 1483 | | }); |
| 1484 | | const amt = try d_sym.file.copyRangeAll( |
| 1485 | | debug_info_sect.offset, |
| 1486 | | d_sym.file, |
| 1487 | | new_offset, |
| 1488 | | existing_size, |
| 1489 | | ); |
| 1490 | | if (amt != existing_size) return error.InputOutput; |
| 1491 | | debug_info_sect.offset = @intCast(u32, new_offset); |
| 1492 | | } |
| 1493 | | debug_info_sect.size = needed_size; |
| 1494 | | d_sym.debug_info_header_dirty = true; |
| 1495 | | } |
| 1496 | | const file_pos = debug_info_sect.offset + atom.off; |
| 1415 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 1416 | const sect_index = d_sym.debug_info_section_index.?; |
| 1417 | try d_sym.growSection(sect_index, needed_size, true); |
| 1418 | const sect = d_sym.getSection(sect_index); |
| 1419 | const file_pos = sect.offset + atom.off; |
| 1497 | 1420 | try pwriteDbgInfoNops( |
| 1498 | 1421 | d_sym.file, |
| 1499 | 1422 | file_pos, |
| ... | ... | @@ -1505,7 +1428,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co |
| 1505 | 1428 | }, |
| 1506 | 1429 | |
| 1507 | 1430 | .wasm => { |
| 1508 | | const wasm_file = file.cast(File.Wasm).?; |
| 1431 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| 1509 | 1432 | const info_atom = wasm_file.debug_info_atom.?; |
| 1510 | 1433 | const debug_info = &info_atom.code; |
| 1511 | 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 | 1458 | } |
| 1536 | 1459 | } |
| 1537 | 1460 | |
| 1538 | | pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl) !void { |
| 1461 | pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void { |
| 1539 | 1462 | const tracy = trace(@src()); |
| 1540 | 1463 | defer tracy.end(); |
| 1541 | 1464 | |
| ... | ... | @@ -1549,22 +1472,21 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl) |
| 1549 | 1472 | var data: [4]u8 = undefined; |
| 1550 | 1473 | leb128.writeUnsignedFixed(4, &data, line); |
| 1551 | 1474 | |
| 1552 | | switch (self.tag) { |
| 1475 | switch (self.bin_file.tag) { |
| 1553 | 1476 | .elf => { |
| 1554 | | const elf_file = file.cast(File.Elf).?; |
| 1477 | const elf_file = self.bin_file.cast(File.Elf).?; |
| 1555 | 1478 | const shdr = elf_file.sections.items[elf_file.debug_line_section_index.?]; |
| 1556 | 1479 | const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff(); |
| 1557 | 1480 | try elf_file.base.file.?.pwriteAll(&data, file_pos); |
| 1558 | 1481 | }, |
| 1559 | 1482 | .macho => { |
| 1560 | | const macho_file = file.cast(File.MachO).?; |
| 1561 | | const d_sym = macho_file.d_sym.?; |
| 1562 | | const sect = d_sym.sections.items[d_sym.debug_line_section_index.?]; |
| 1483 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 1484 | const sect = d_sym.getSection(d_sym.debug_line_section_index.?); |
| 1563 | 1485 | const file_pos = sect.offset + decl.fn_link.macho.off + self.getRelocDbgLineOff(); |
| 1564 | 1486 | try d_sym.file.pwriteAll(&data, file_pos); |
| 1565 | 1487 | }, |
| 1566 | 1488 | .wasm => { |
| 1567 | | const wasm_file = file.cast(File.Wasm).?; |
| 1489 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| 1568 | 1490 | const offset = decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff(); |
| 1569 | 1491 | const atom = wasm_file.debug_line_atom.?; |
| 1570 | 1492 | mem.copy(u8, atom.code.items[offset..], &data); |
| ... | ... | @@ -1601,7 +1523,7 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void { |
| 1601 | 1523 | // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing |
| 1602 | 1524 | // is desired for both. |
| 1603 | 1525 | const gpa = self.allocator; |
| 1604 | | const fn_link = switch (self.tag) { |
| 1526 | const fn_link = switch (self.bin_file.tag) { |
| 1605 | 1527 | .elf => &decl.fn_link.elf, |
| 1606 | 1528 | .macho => &decl.fn_link.macho, |
| 1607 | 1529 | .wasm => &decl.fn_link.wasm.src_fn, |
| ... | ... | @@ -1629,7 +1551,7 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void { |
| 1629 | 1551 | } |
| 1630 | 1552 | } |
| 1631 | 1553 | |
| 1632 | | pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void { |
| 1554 | pub fn writeDbgAbbrev(self: *Dwarf) !void { |
| 1633 | 1555 | // These are LEB encoded but since the values are all less than 127 |
| 1634 | 1556 | // we can simply append these bytes. |
| 1635 | 1557 | const abbrev_buf = [_]u8{ |
| ... | ... | @@ -1763,46 +1685,25 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void { |
| 1763 | 1685 | self.abbrev_table_offset = abbrev_offset; |
| 1764 | 1686 | |
| 1765 | 1687 | const needed_size = abbrev_buf.len; |
| 1766 | | switch (self.tag) { |
| 1688 | switch (self.bin_file.tag) { |
| 1767 | 1689 | .elf => { |
| 1768 | | const elf_file = file.cast(File.Elf).?; |
| 1769 | | const debug_abbrev_sect = &elf_file.sections.items[elf_file.debug_abbrev_section_index.?]; |
| 1770 | | const allocated_size = elf_file.allocatedSize(debug_abbrev_sect.sh_offset); |
| 1771 | | if (needed_size > allocated_size) { |
| 1772 | | debug_abbrev_sect.sh_size = 0; // free the space |
| 1773 | | debug_abbrev_sect.sh_offset = elf_file.findFreeSpace(needed_size, 1); |
| 1774 | | } |
| 1775 | | debug_abbrev_sect.sh_size = needed_size; |
| 1776 | | log.debug(".debug_abbrev start=0x{x} end=0x{x}", .{ |
| 1777 | | debug_abbrev_sect.sh_offset, |
| 1778 | | debug_abbrev_sect.sh_offset + needed_size, |
| 1779 | | }); |
| 1780 | | |
| 1690 | const elf_file = self.bin_file.cast(File.Elf).?; |
| 1691 | const shdr_index = elf_file.debug_abbrev_section_index.?; |
| 1692 | try elf_file.growNonAllocSection(shdr_index, needed_size, 1, false); |
| 1693 | const debug_abbrev_sect = elf_file.sections.items[shdr_index]; |
| 1781 | 1694 | const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset; |
| 1782 | 1695 | try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos); |
| 1783 | 1696 | }, |
| 1784 | 1697 | .macho => { |
| 1785 | | const macho_file = file.cast(File.MachO).?; |
| 1786 | | const d_sym = &macho_file.d_sym.?; |
| 1787 | | const dwarf_segment = d_sym.segments.items[d_sym.dwarf_segment_cmd_index.?]; |
| 1788 | | const debug_abbrev_sect = &d_sym.sections.items[d_sym.debug_abbrev_section_index.?]; |
| 1789 | | const allocated_size = d_sym.allocatedSize(debug_abbrev_sect.offset); |
| 1790 | | if (needed_size > allocated_size) { |
| 1791 | | debug_abbrev_sect.size = 0; // free the space |
| 1792 | | const offset = d_sym.findFreeSpace(needed_size, 1); |
| 1793 | | debug_abbrev_sect.offset = @intCast(u32, offset); |
| 1794 | | debug_abbrev_sect.addr = dwarf_segment.vmaddr + offset - dwarf_segment.fileoff; |
| 1795 | | } |
| 1796 | | debug_abbrev_sect.size = needed_size; |
| 1797 | | log.debug("__debug_abbrev start=0x{x} end=0x{x}", .{ |
| 1798 | | debug_abbrev_sect.offset, |
| 1799 | | debug_abbrev_sect.offset + needed_size, |
| 1800 | | }); |
| 1801 | | const file_pos = debug_abbrev_sect.offset + abbrev_offset; |
| 1698 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 1699 | const sect_index = d_sym.debug_abbrev_section_index.?; |
| 1700 | try d_sym.growSection(sect_index, needed_size, false); |
| 1701 | const sect = d_sym.getSection(sect_index); |
| 1702 | const file_pos = sect.offset + abbrev_offset; |
| 1802 | 1703 | try d_sym.file.pwriteAll(&abbrev_buf, file_pos); |
| 1803 | 1704 | }, |
| 1804 | 1705 | .wasm => { |
| 1805 | | const wasm_file = file.cast(File.Wasm).?; |
| 1706 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| 1806 | 1707 | const debug_abbrev = &wasm_file.debug_abbrev_atom.?.code; |
| 1807 | 1708 | try debug_abbrev.resize(wasm_file.base.allocator, needed_size); |
| 1808 | 1709 | mem.copy(u8, debug_abbrev.items, &abbrev_buf); |
| ... | ... | @@ -1816,7 +1717,7 @@ fn dbgInfoHeaderBytes(self: *Dwarf) usize { |
| 1816 | 1717 | return 120; |
| 1817 | 1718 | } |
| 1818 | 1719 | |
| 1819 | | pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u64, high_pc: u64) !void { |
| 1720 | pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u64) !void { |
| 1820 | 1721 | // If this value is null it means there is an error in the module; |
| 1821 | 1722 | // leave debug_info_header_dirty=true. |
| 1822 | 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 | 1729 | defer di_buf.deinit(); |
| 1829 | 1730 | |
| 1830 | 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 | 1733 | 4 |
| 1833 | 1734 | else switch (self.ptr_width) { |
| 1834 | 1735 | .p32 => @as(usize, 4), |
| ... | ... | @@ -1842,7 +1743,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6 |
| 1842 | 1743 | // +1 for the final 0 that ends the compilation unit children. |
| 1843 | 1744 | const dbg_info_end = self.getDebugInfoEnd().? + 1; |
| 1844 | 1745 | const init_len = dbg_info_end - after_init_len; |
| 1845 | | if (self.tag == .macho) { |
| 1746 | if (self.bin_file.tag == .macho) { |
| 1846 | 1747 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len)); |
| 1847 | 1748 | } else switch (self.ptr_width) { |
| 1848 | 1749 | .p32 => { |
| ... | ... | @@ -1855,7 +1756,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6 |
| 1855 | 1756 | } |
| 1856 | 1757 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version |
| 1857 | 1758 | const abbrev_offset = self.abbrev_table_offset.?; |
| 1858 | | if (self.tag == .macho) { |
| 1759 | if (self.bin_file.tag == .macho) { |
| 1859 | 1760 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, abbrev_offset)); |
| 1860 | 1761 | di_buf.appendAssumeCapacity(8); // address size |
| 1861 | 1762 | } else switch (self.ptr_width) { |
| ... | ... | @@ -1870,11 +1771,12 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6 |
| 1870 | 1771 | } |
| 1871 | 1772 | // Write the form for the compile unit, which must match the abbrev table above. |
| 1872 | 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 | 1776 | const producer_strp = try self.makeString(link.producer_string); |
| 1875 | 1777 | |
| 1876 | 1778 | di_buf.appendAssumeCapacity(@enumToInt(AbbrevKind.compile_unit)); |
| 1877 | | if (self.tag == .macho) { |
| 1779 | if (self.bin_file.tag == .macho) { |
| 1878 | 1780 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // DW.AT.stmt_list, DW.FORM.sec_offset |
| 1879 | 1781 | mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), low_pc); |
| 1880 | 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 | 1801 | @panic("TODO: handle .debug_info header exceeding its padding"); |
| 1900 | 1802 | } |
| 1901 | 1803 | const jmp_amt = first_dbg_info_off - di_buf.items.len; |
| 1902 | | switch (self.tag) { |
| 1804 | switch (self.bin_file.tag) { |
| 1903 | 1805 | .elf => { |
| 1904 | | const elf_file = file.cast(File.Elf).?; |
| 1806 | const elf_file = self.bin_file.cast(File.Elf).?; |
| 1905 | 1807 | const debug_info_sect = elf_file.sections.items[elf_file.debug_info_section_index.?]; |
| 1906 | 1808 | const file_pos = debug_info_sect.sh_offset; |
| 1907 | 1809 | try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false); |
| 1908 | 1810 | }, |
| 1909 | 1811 | .macho => { |
| 1910 | | const macho_file = file.cast(File.MachO).?; |
| 1911 | | const d_sym = &macho_file.d_sym.?; |
| 1912 | | const debug_info_sect = d_sym.sections.items[d_sym.debug_info_section_index.?]; |
| 1812 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 1813 | const debug_info_sect = d_sym.getSection(d_sym.debug_info_section_index.?); |
| 1913 | 1814 | const file_pos = debug_info_sect.offset; |
| 1914 | 1815 | try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false); |
| 1915 | 1816 | }, |
| 1916 | 1817 | .wasm => { |
| 1917 | | const wasm_file = file.cast(File.Wasm).?; |
| 1818 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| 1918 | 1819 | const debug_info = &wasm_file.debug_info_atom.?.code; |
| 1919 | 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 | 1823 | } |
| 1923 | 1824 | } |
| 1924 | 1825 | |
| 1826 | fn 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 | |
| 1925 | 1841 | fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) void { |
| 1926 | 1842 | const target_endian = self.target.cpu.arch.endian(); |
| 1927 | 1843 | switch (self.ptr_width) { |
| ... | ... | @@ -2144,9 +2060,9 @@ fn writeDbgInfoNopsToArrayList( |
| 2144 | 2060 | } |
| 2145 | 2061 | } |
| 2146 | 2062 | |
| 2147 | | pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void { |
| 2063 | pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { |
| 2148 | 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 | 2066 | 4 |
| 2151 | 2067 | else switch (self.ptr_width) { |
| 2152 | 2068 | .p32 => @as(usize, 4), |
| ... | ... | @@ -2168,7 +2084,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void { |
| 2168 | 2084 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version |
| 2169 | 2085 | // When more than one compilation unit is supported, this will be the offset to it. |
| 2170 | 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 | 2088 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // __debug_info offset |
| 2173 | 2089 | } else { |
| 2174 | 2090 | 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 | 2107 | |
| 2192 | 2108 | // Go back and populate the initial length. |
| 2193 | 2109 | const init_len = di_buf.items.len - after_init_len; |
| 2194 | | if (self.tag == .macho) { |
| 2110 | if (self.bin_file.tag == .macho) { |
| 2195 | 2111 | mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len)); |
| 2196 | 2112 | } else switch (self.ptr_width) { |
| 2197 | 2113 | .p32 => { |
| ... | ... | @@ -2205,46 +2121,26 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void { |
| 2205 | 2121 | }, |
| 2206 | 2122 | } |
| 2207 | 2123 | |
| 2208 | | const needed_size = di_buf.items.len; |
| 2209 | | switch (self.tag) { |
| 2124 | const needed_size = @intCast(u32, di_buf.items.len); |
| 2125 | switch (self.bin_file.tag) { |
| 2210 | 2126 | .elf => { |
| 2211 | | const elf_file = file.cast(File.Elf).?; |
| 2212 | | const debug_aranges_sect = &elf_file.sections.items[elf_file.debug_aranges_section_index.?]; |
| 2213 | | const allocated_size = elf_file.allocatedSize(debug_aranges_sect.sh_offset); |
| 2214 | | if (needed_size > allocated_size) { |
| 2215 | | debug_aranges_sect.sh_size = 0; // free the space |
| 2216 | | debug_aranges_sect.sh_offset = elf_file.findFreeSpace(needed_size, 16); |
| 2217 | | } |
| 2218 | | debug_aranges_sect.sh_size = needed_size; |
| 2219 | | log.debug(".debug_aranges start=0x{x} end=0x{x}", .{ |
| 2220 | | debug_aranges_sect.sh_offset, |
| 2221 | | debug_aranges_sect.sh_offset + needed_size, |
| 2222 | | }); |
| 2127 | const elf_file = self.bin_file.cast(File.Elf).?; |
| 2128 | const shdr_index = elf_file.debug_aranges_section_index.?; |
| 2129 | try elf_file.growNonAllocSection(shdr_index, needed_size, 16, false); |
| 2130 | const debug_aranges_sect = elf_file.sections.items[shdr_index]; |
| 2223 | 2131 | const file_pos = debug_aranges_sect.sh_offset; |
| 2224 | 2132 | try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos); |
| 2225 | 2133 | }, |
| 2226 | 2134 | .macho => { |
| 2227 | | const macho_file = file.cast(File.MachO).?; |
| 2228 | | const d_sym = &macho_file.d_sym.?; |
| 2229 | | const dwarf_seg = d_sym.segments.items[d_sym.dwarf_segment_cmd_index.?]; |
| 2230 | | const debug_aranges_sect = &d_sym.sections.items[d_sym.debug_aranges_section_index.?]; |
| 2231 | | const allocated_size = d_sym.allocatedSize(debug_aranges_sect.offset); |
| 2232 | | if (needed_size > allocated_size) { |
| 2233 | | debug_aranges_sect.size = 0; // free the space |
| 2234 | | const new_offset = d_sym.findFreeSpace(needed_size, 16); |
| 2235 | | debug_aranges_sect.addr = dwarf_seg.vmaddr + new_offset - dwarf_seg.fileoff; |
| 2236 | | debug_aranges_sect.offset = @intCast(u32, new_offset); |
| 2237 | | } |
| 2238 | | debug_aranges_sect.size = needed_size; |
| 2239 | | log.debug("__debug_aranges start=0x{x} end=0x{x}", .{ |
| 2240 | | debug_aranges_sect.offset, |
| 2241 | | debug_aranges_sect.offset + needed_size, |
| 2242 | | }); |
| 2243 | | const file_pos = debug_aranges_sect.offset; |
| 2135 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 2136 | const sect_index = d_sym.debug_aranges_section_index.?; |
| 2137 | try d_sym.growSection(sect_index, needed_size, false); |
| 2138 | const sect = d_sym.getSection(sect_index); |
| 2139 | const file_pos = sect.offset; |
| 2244 | 2140 | try d_sym.file.pwriteAll(di_buf.items, file_pos); |
| 2245 | 2141 | }, |
| 2246 | 2142 | .wasm => { |
| 2247 | | const wasm_file = file.cast(File.Wasm).?; |
| 2143 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| 2248 | 2144 | const debug_ranges = &wasm_file.debug_ranges_atom.?.code; |
| 2249 | 2145 | try debug_ranges.resize(wasm_file.base.allocator, needed_size); |
| 2250 | 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 | 2149 | } |
| 2254 | 2150 | } |
| 2255 | 2151 | |
| 2256 | | pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void { |
| 2152 | pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void { |
| 2153 | const gpa = self.allocator; |
| 2154 | |
| 2257 | 2155 | const ptr_width_bytes: u8 = self.ptrWidthBytes(); |
| 2258 | 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 | 2158 | 4 |
| 2261 | 2159 | else switch (self.ptr_width) { |
| 2262 | 2160 | .p32 => @as(usize, 4), |
| ... | ... | @@ -2264,29 +2162,37 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void { |
| 2264 | 2162 | }; |
| 2265 | 2163 | |
| 2266 | 2164 | const dbg_line_prg_off = self.getDebugLineProgramOff() orelse return; |
| 2267 | | const dbg_line_prg_end = self.getDebugLineProgramEnd().?; |
| 2268 | | assert(dbg_line_prg_end != 0); |
| 2165 | assert(self.getDebugLineProgramEnd().? != 0); |
| 2166 | |
| 2167 | // Convert all input DI files into a set of include dirs and file names. |
| 2168 | var arena = std.heap.ArenaAllocator.init(gpa); |
| 2169 | defer arena.deinit(); |
| 2170 | const paths = try self.genIncludeDirsAndFileNames(arena.allocator(), module); |
| 2269 | 2171 | |
| 2270 | 2172 | // The size of this header is variable, depending on the number of directories, |
| 2271 | 2173 | // files, and padding. We have a function to compute the upper bound size, however, |
| 2272 | 2174 | // because it's needed for determining where to put the offset of the first `SrcFn`. |
| 2273 | | const needed_bytes = self.dbgLineNeededHeaderBytes(module); |
| 2274 | | var di_buf = try std.ArrayList(u8).initCapacity(self.allocator, needed_bytes); |
| 2175 | const needed_bytes = self.dbgLineNeededHeaderBytes(paths.dirs, paths.files); |
| 2176 | var di_buf = try std.ArrayList(u8).initCapacity(gpa, needed_bytes); |
| 2275 | 2177 | defer di_buf.deinit(); |
| 2276 | 2178 | |
| 2277 | 2179 | // initial length - length of the .debug_line contribution for this compilation unit, |
| 2278 | 2180 | // not including the initial length itself. |
| 2279 | | const after_init_len = di_buf.items.len + init_len_size; |
| 2280 | | const init_len = dbg_line_prg_end - after_init_len; |
| 2281 | | if (self.tag == .macho) { |
| 2282 | | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len)); |
| 2283 | | } else switch (self.ptr_width) { |
| 2284 | | .p32 => { |
| 2285 | | mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian); |
| 2181 | // We will backpatch this value later so just remember where we need to write it. |
| 2182 | const before_init_len = di_buf.items.len; |
| 2183 | |
| 2184 | switch (self.bin_file.tag) { |
| 2185 | .macho => { |
| 2186 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, 0)); |
| 2286 | 2187 | }, |
| 2287 | | .p64 => { |
| 2288 | | di_buf.appendNTimesAssumeCapacity(0xff, 4); |
| 2289 | | mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian); |
| 2188 | else => switch (self.ptr_width) { |
| 2189 | .p32 => { |
| 2190 | mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, 0), target_endian); |
| 2191 | }, |
| 2192 | .p64 => { |
| 2193 | di_buf.appendNTimesAssumeCapacity(0xff, 4); |
| 2194 | mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), @as(u64, 0), target_endian); |
| 2195 | }, |
| 2290 | 2196 | }, |
| 2291 | 2197 | } |
| 2292 | 2198 | |
| ... | ... | @@ -2297,7 +2203,12 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void { |
| 2297 | 2203 | // Therefore we rely on the NOP jump at the beginning of the Line Number Program for |
| 2298 | 2204 | // padding rather than this field. |
| 2299 | 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 | 2212 | const after_header_len = di_buf.items.len; |
| 2302 | 2213 | |
| 2303 | 2214 | const opcode_base = DW.LNS.set_isa + 1; |
| ... | ... | @@ -2323,52 +2234,133 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void { |
| 2323 | 2234 | 0, // `DW.LNS.set_prologue_end` |
| 2324 | 2235 | 0, // `DW.LNS.set_epilogue_begin` |
| 2325 | 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 | }); |
| 2337 | 2238 | |
| 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 | 2259 | const header_len = di_buf.items.len - after_header_len; |
| 2339 | | if (self.tag == .macho) { |
| 2340 | | mem.writeIntLittle(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len)); |
| 2341 | | } else switch (self.ptr_width) { |
| 2342 | | .p32 => { |
| 2343 | | mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len), target_endian); |
| 2260 | |
| 2261 | switch (self.bin_file.tag) { |
| 2262 | .macho => { |
| 2263 | mem.writeIntLittle(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len)); |
| 2344 | 2264 | }, |
| 2345 | | .p64 => { |
| 2346 | | mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian); |
| 2265 | else => switch (self.ptr_width) { |
| 2266 | .p32 => { |
| 2267 | mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len), target_endian); |
| 2268 | }, |
| 2269 | .p64 => { |
| 2270 | mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian); |
| 2271 | }, |
| 2347 | 2272 | }, |
| 2348 | 2273 | } |
| 2349 | 2274 | |
| 2350 | | // We use NOPs because consumers empirically do not respect the header length field. |
| 2275 | assert(needed_bytes == di_buf.items.len); |
| 2276 | |
| 2351 | 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. |
| 2353 | | @panic("TODO: handle .debug_line header exceeding its padding"); |
| 2278 | const needed_with_padding = padToIdeal(needed_bytes); |
| 2279 | const delta = needed_with_padding - dbg_line_prg_off; |
| 2280 | |
| 2281 | var src_fn = self.dbg_line_fn_first.?; |
| 2282 | const last_fn = self.dbg_line_fn_last.?; |
| 2283 | |
| 2284 | var buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - src_fn.off); |
| 2285 | defer gpa.free(buffer); |
| 2286 | |
| 2287 | switch (self.bin_file.tag) { |
| 2288 | .elf => { |
| 2289 | const elf_file = self.bin_file.cast(File.Elf).?; |
| 2290 | const shdr_index = elf_file.debug_line_section_index.?; |
| 2291 | const needed_size = elf_file.sections.items[shdr_index].sh_size + delta; |
| 2292 | try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true); |
| 2293 | const file_pos = elf_file.sections.items[shdr_index].sh_offset + src_fn.off; |
| 2294 | |
| 2295 | const amt = try elf_file.base.file.?.preadAll(buffer, file_pos); |
| 2296 | if (amt != buffer.len) return error.InputOutput; |
| 2297 | |
| 2298 | try elf_file.base.file.?.pwriteAll(buffer, file_pos + delta); |
| 2299 | }, |
| 2300 | .macho => { |
| 2301 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 2302 | const sect_index = d_sym.debug_line_section_index.?; |
| 2303 | const needed_size = @intCast(u32, d_sym.getSection(sect_index).size + delta); |
| 2304 | try d_sym.growSection(sect_index, needed_size, true); |
| 2305 | const file_pos = d_sym.getSection(sect_index).offset + src_fn.off; |
| 2306 | |
| 2307 | const amt = try d_sym.file.preadAll(buffer, file_pos); |
| 2308 | if (amt != buffer.len) return error.InputOutput; |
| 2309 | |
| 2310 | try d_sym.file.pwriteAll(buffer, file_pos + delta); |
| 2311 | }, |
| 2312 | .wasm => { |
| 2313 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| 2314 | const debug_line = &wasm_file.debug_line_atom.?.code; |
| 2315 | mem.copy(u8, buffer, debug_line.items[src_fn.off..]); |
| 2316 | try debug_line.resize(self.allocator, debug_line.items.len + delta); |
| 2317 | mem.copy(u8, debug_line.items[src_fn.off + delta ..], buffer); |
| 2318 | }, |
| 2319 | else => unreachable, |
| 2320 | } |
| 2321 | |
| 2322 | while (true) { |
| 2323 | src_fn.off += delta; |
| 2324 | |
| 2325 | if (src_fn.next) |next| { |
| 2326 | src_fn = next; |
| 2327 | } else break; |
| 2328 | } |
| 2329 | } |
| 2330 | |
| 2331 | // Backpatch actual length of the debug line program |
| 2332 | const init_len = self.getDebugLineProgramEnd().? - before_init_len - init_len_size; |
| 2333 | switch (self.bin_file.tag) { |
| 2334 | .macho => { |
| 2335 | mem.writeIntLittle(u32, di_buf.items[before_init_len..][0..4], @intCast(u32, init_len)); |
| 2336 | }, |
| 2337 | else => switch (self.ptr_width) { |
| 2338 | .p32 => { |
| 2339 | mem.writeInt(u32, di_buf.items[before_init_len..][0..4], @intCast(u32, init_len), target_endian); |
| 2340 | }, |
| 2341 | .p64 => { |
| 2342 | mem.writeInt(u64, di_buf.items[before_init_len + 4 ..][0..8], init_len, target_endian); |
| 2343 | }, |
| 2344 | }, |
| 2354 | 2345 | } |
| 2355 | | const jmp_amt = dbg_line_prg_off - di_buf.items.len; |
| 2356 | | switch (self.tag) { |
| 2346 | |
| 2347 | // We use NOPs because consumers empirically do not respect the header length field. |
| 2348 | const jmp_amt = self.getDebugLineProgramOff().? - di_buf.items.len; |
| 2349 | switch (self.bin_file.tag) { |
| 2357 | 2350 | .elf => { |
| 2358 | | const elf_file = file.cast(File.Elf).?; |
| 2351 | const elf_file = self.bin_file.cast(File.Elf).?; |
| 2359 | 2352 | const debug_line_sect = elf_file.sections.items[elf_file.debug_line_section_index.?]; |
| 2360 | 2353 | const file_pos = debug_line_sect.sh_offset; |
| 2361 | 2354 | try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt); |
| 2362 | 2355 | }, |
| 2363 | 2356 | .macho => { |
| 2364 | | const macho_file = file.cast(File.MachO).?; |
| 2365 | | const d_sym = &macho_file.d_sym.?; |
| 2366 | | const debug_line_sect = d_sym.sections.items[d_sym.debug_line_section_index.?]; |
| 2357 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 2358 | const debug_line_sect = d_sym.getSection(d_sym.debug_line_section_index.?); |
| 2367 | 2359 | const file_pos = debug_line_sect.offset; |
| 2368 | 2360 | try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt); |
| 2369 | 2361 | }, |
| 2370 | 2362 | .wasm => { |
| 2371 | | const wasm_file = file.cast(File.Wasm).?; |
| 2363 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| 2372 | 2364 | const debug_line = wasm_file.debug_line_atom.?.code; |
| 2373 | 2365 | writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt); |
| 2374 | 2366 | }, |
| ... | ... | @@ -2404,19 +2396,32 @@ fn ptrWidthBytes(self: Dwarf) u8 { |
| 2404 | 2396 | }; |
| 2405 | 2397 | } |
| 2406 | 2398 | |
| 2407 | | fn dbgLineNeededHeaderBytes(self: Dwarf, module: *Module) u32 { |
| 2408 | | _ = self; |
| 2409 | | const directory_entry_format_count = 1; |
| 2410 | | const file_name_entry_format_count = 1; |
| 2411 | | const directory_count = 1; |
| 2412 | | const file_name_count = 1; |
| 2413 | | const root_src_dir_path_len = if (module.root_pkg.root_src_directory.path) |p| p.len else 1; // "." |
| 2414 | | return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 + |
| 2415 | | directory_count * 8 + file_name_count * 8 + |
| 2416 | | // These are encoded as DW.FORM.string rather than DW.FORM.strp as we would like |
| 2417 | | // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly. |
| 2418 | | root_src_dir_path_len + |
| 2419 | | module.root_pkg.root_src_path.len); |
| 2399 | fn dbgLineNeededHeaderBytes(self: Dwarf, dirs: []const []const u8, files: []const []const u8) u32 { |
| 2400 | var size = switch (self.bin_file.tag) { // length field |
| 2401 | .macho => @sizeOf(u32), |
| 2402 | else => switch (self.ptr_width) { |
| 2403 | .p32 => @as(usize, @sizeOf(u32)), |
| 2404 | .p64 => @sizeOf(u32) + @sizeOf(u64), |
| 2405 | }, |
| 2406 | }; |
| 2407 | size += @sizeOf(u16); // version field |
| 2408 | size += switch (self.bin_file.tag) { // offset to end-of-header |
| 2409 | .macho => @sizeOf(u32), |
| 2410 | else => self.ptrWidthBytes(), |
| 2411 | }; |
| 2412 | size += 18; // opcodes |
| 2413 | |
| 2414 | for (dirs) |dir| { // include dirs |
| 2415 | size += dir.len + 1; |
| 2416 | } |
| 2417 | size += 1; // include dirs sentinel |
| 2418 | |
| 2419 | for (files) |file| { // file names |
| 2420 | size += file.len + 1 + 1 + 1 + 1; |
| 2421 | } |
| 2422 | size += 1; // file names sentinel |
| 2423 | |
| 2424 | return @intCast(u32, size); |
| 2420 | 2425 | } |
| 2421 | 2426 | |
| 2422 | 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 | 2453 | std.math.maxInt(@TypeOf(actual_size)); |
| 2449 | 2454 | } |
| 2450 | 2455 | |
| 2451 | | pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void { |
| 2456 | pub fn flushModule(self: *Dwarf, module: *Module) !void { |
| 2452 | 2457 | if (self.global_abbrev_relocs.items.len > 0) { |
| 2453 | 2458 | const gpa = self.allocator; |
| 2454 | 2459 | var arena_alloc = std.heap.ArenaAllocator.init(gpa); |
| ... | ... | @@ -2479,21 +2484,20 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void { |
| 2479 | 2484 | |
| 2480 | 2485 | try self.managed_atoms.append(gpa, atom); |
| 2481 | 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 | 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); |
| 2485 | 2490 | |
| 2486 | 2491 | const file_pos = blk: { |
| 2487 | | switch (self.tag) { |
| 2492 | switch (self.bin_file.tag) { |
| 2488 | 2493 | .elf => { |
| 2489 | | const elf_file = file.cast(File.Elf).?; |
| 2494 | const elf_file = self.bin_file.cast(File.Elf).?; |
| 2490 | 2495 | const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?]; |
| 2491 | 2496 | break :blk debug_info_sect.sh_offset; |
| 2492 | 2497 | }, |
| 2493 | 2498 | .macho => { |
| 2494 | | const macho_file = file.cast(File.MachO).?; |
| 2495 | | const d_sym = &macho_file.d_sym.?; |
| 2496 | | const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?]; |
| 2499 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 2500 | const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?); |
| 2497 | 2501 | break :blk debug_info_sect.offset; |
| 2498 | 2502 | }, |
| 2499 | 2503 | // 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 | 2510 | mem.writeInt(u32, &buf, atom.off, self.target.cpu.arch.endian()); |
| 2507 | 2511 | |
| 2508 | 2512 | while (self.global_abbrev_relocs.popOrNull()) |reloc| { |
| 2509 | | switch (self.tag) { |
| 2513 | switch (self.bin_file.tag) { |
| 2510 | 2514 | .elf => { |
| 2511 | | const elf_file = file.cast(File.Elf).?; |
| 2515 | const elf_file = self.bin_file.cast(File.Elf).?; |
| 2512 | 2516 | try elf_file.base.file.?.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset); |
| 2513 | 2517 | }, |
| 2514 | 2518 | .macho => { |
| 2515 | | const macho_file = file.cast(File.MachO).?; |
| 2516 | | const d_sym = &macho_file.d_sym.?; |
| 2519 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; |
| 2517 | 2520 | try d_sym.file.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset); |
| 2518 | 2521 | }, |
| 2519 | 2522 | .wasm => { |
| 2520 | | const wasm_file = file.cast(File.Wasm).?; |
| 2523 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| 2521 | 2524 | const debug_info = wasm_file.debug_info_atom.?.code; |
| 2522 | 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 | 2530 | } |
| 2528 | 2531 | } |
| 2529 | 2532 | |
| 2533 | fn 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 | |
| 2554 | fn 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 | |
| 2530 | 2595 | fn addDbgInfoErrorSet( |
| 2531 | 2596 | arena: Allocator, |
| 2532 | 2597 | module: *Module, |