| ... | @@ -22,7 +22,7 @@ const Value = @import("../value.zig").Value; | ... | @@ -22,7 +22,7 @@ const Value = @import("../value.zig").Value; |
| 22 | const Type = @import("../type.zig").Type; | 22 | const Type = @import("../type.zig").Type; |
| 23 | | 23 | |
| 24 | allocator: Allocator, | 24 | allocator: Allocator, |
| 25 | tag: File.Tag, | 25 | bin_file: *File, |
| 26 | ptr_width: PtrWidth, | 26 | ptr_width: PtrWidth, |
| 27 | target: std.Target, | 27 | target: std.Target, |
| 28 | | 28 | |
| ... | @@ -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. |
| 45 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 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 | /// 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 make | 54 | /// 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) |
| 888 | const ideal_factor = 3; | 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 | 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); |
| 910 | | 917 | |
| 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 more | 976 | // 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); |
| 973 | | 980 | |
| 974 | // Emit a line for the begin curly with prologue_end=false. The codegen will | 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,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.data4 | 1002 | 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.ref4 | 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,7 +1020,6 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) |
| 1013 | | 1020 | |
| 1014 | pub fn commitDeclState( | 1021 | pub 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` for | 1075 | // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for |
| 1070 | // `TextBlock` and the .debug_info. If you are editing this logic, you | 1076 | // `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; |
| 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 | 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( |
| 1142 | | 1147 | |
| 1143 | // We only have support for one compilation unit so far, so the offsets are directly | 1148 | // 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 | }, |
| 1180 | | 1165 | |
| 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 | }, |
| 1215 | | 1180 | |
| 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; |
| 1249 | | 1214 | |
| 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 of | 1217 | // 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 actual | 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,7 +1239,7 @@ pub fn commitDeclState( |
| 1274 | } | 1239 | } |
| 1275 | | 1240 | |
| 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)); |
| 1278 | | 1243 | |
| 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 | } |
| 1320 | | 1285 | |
| 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 | } |
| 1340 | | 1304 | |
| 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 | } |
| 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 | const tracy = trace(@src()); | 1310 | const tracy = trace(@src()); |
| 1347 | defer tracy.end(); | 1311 | defer tracy.end(); |
| 1348 | | 1312 | |
| ... | @@ -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 | } |
| 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 | const tracy = trace(@src()); | 1378 | const tracy = trace(@src()); |
| 1416 | defer tracy.end(); | 1379 | defer tracy.end(); |
| 1417 | | 1380 | |
| ... | @@ -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 |
| 1431 | | 1394 | |
| 1432 | // We only have support for one compilation unit so far, so the offsets are directly | 1395 | // 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 | }, |
| 1470 | | 1413 | |
| 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 | }, |
| 1506 | | 1429 | |
| 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 | } |
| 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 | const tracy = trace(@src()); | 1462 | const tracy = trace(@src()); |
| 1540 | defer tracy.end(); | 1463 | defer tracy.end(); |
| 1541 | | 1464 | |
| ... | @@ -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); |
| 1551 | | 1474 | |
| 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 thing | 1523 | // 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 | } |
| 1631 | | 1553 | |
| 1632 | pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void { | 1554 | pub fn writeDbgAbbrev(self: *Dwarf) !void { |
| 1633 | // These are LEB encoded but since the values are all less than 127 | 1555 | // 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; |
| 1764 | | 1686 | |
| 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 | } |
| 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 | // 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(); |
| 1829 | | 1730 | |
| 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 | 4 | 1733 | 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 version | 1757 | 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 size | 1761 | 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); |
| 1875 | | 1777 | |
| 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_offset | 1780 | 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 | } |
| 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 | fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) void { | 1841 | fn 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 | } |
| 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 | 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 | 4 | 2066 | 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); // version | 2084 | 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 offset | 2088 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // __debug_info offset |
| 2173 | } else { | 2089 | } else { |
| 2174 | self.writeAddrAssumeCapacity(&di_buf, 0); // .debug_info offset | 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,7 +2107,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void { |
| 2191 | | 2107 | |
| 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 | } |
| 2207 | | 2123 | |
| 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 | } |
| 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 | 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 | 4 | 2158 | 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 | }; |
| 2265 | | 2163 | |
| 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); |
| 2269 | | 2171 | |
| 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(); |
| 2276 | | 2178 | |
| 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 | } |
| 2292 | | 2198 | |
| ... | @@ -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 for | 2203 | // 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; |
| 2302 | | 2213 | |
| 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 | }); |
| 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 | 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 | } |
| 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 | 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 | } |
| 2406 | | 2398 | |
| 2407 | fn dbgLineNeededHeaderBytes(self: Dwarf, module: *Module) u32 { | 2399 | fn 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 like | 2408 | 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 | } |
| 2421 | | 2426 | |
| 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 | } |
| 2450 | | 2455 | |
| 2451 | pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void { | 2456 | pub 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 { |
| 2479 | | 2484 | |
| 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); |
| 2485 | | 2490 | |
| 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 first | 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,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()); |
| 2507 | | 2511 | |
| 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 | } |
| 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 | fn addDbgInfoErrorSet( | 2595 | fn addDbgInfoErrorSet( |
| 2531 | arena: Allocator, | 2596 | arena: Allocator, |
| 2532 | module: *Module, | 2597 | module: *Module, |