| ... | @@ -811,7 +811,7 @@ fn printLineInfo( | ... | @@ -811,7 +811,7 @@ fn printLineInfo( |
| 811 | pub const OpenSelfDebugInfoError = error{ | 811 | pub const OpenSelfDebugInfoError = error{ |
| 812 | MissingDebugInfo, | 812 | MissingDebugInfo, |
| 813 | UnsupportedOperatingSystem, | 813 | UnsupportedOperatingSystem, |
| 814 | }; | 814 | } || @typeInfo(@typeInfo(@TypeOf(DebugInfo.init)).Fn.return_type.?).ErrorUnion.error_set; |
| 815 | | 815 | |
| 816 | pub fn openSelfDebugInfo(allocator: mem.Allocator) OpenSelfDebugInfoError!DebugInfo { | 816 | pub fn openSelfDebugInfo(allocator: mem.Allocator) OpenSelfDebugInfoError!DebugInfo { |
| 817 | nosuspend { | 817 | nosuspend { |
| ... | @@ -827,60 +827,56 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) OpenSelfDebugInfoError!DebugI | ... | @@ -827,60 +827,56 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) OpenSelfDebugInfoError!DebugI |
| 827 | .dragonfly, | 827 | .dragonfly, |
| 828 | .openbsd, | 828 | .openbsd, |
| 829 | .macos, | 829 | .macos, |
| 830 | .windows, | | |
| 831 | .solaris, | 830 | .solaris, |
| 832 | => return DebugInfo.init(allocator), | 831 | .windows, |
| | 832 | => return try DebugInfo.init(allocator), |
| 833 | else => return error.UnsupportedOperatingSystem, | 833 | else => return error.UnsupportedOperatingSystem, |
| 834 | } | 834 | } |
| 835 | } | 835 | } |
| 836 | } | 836 | } |
| 837 | | 837 | |
| 838 | /// This takes ownership of coff_file: users of this function should not close | 838 | fn readCoffDebugInfo(allocator: mem.Allocator, coff_bytes: []const u8) !ModuleDebugInfo { |
| 839 | /// it themselves, even on error. | | |
| 840 | /// TODO it's weird to take ownership even on error, rework this code. | | |
| 841 | fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo { | | |
| 842 | nosuspend { | 839 | nosuspend { |
| 843 | defer coff_file.close(); | | |
| 844 | | | |
| 845 | const coff_obj = try allocator.create(coff.Coff); | 840 | const coff_obj = try allocator.create(coff.Coff); |
| 846 | errdefer allocator.destroy(coff_obj); | 841 | errdefer allocator.destroy(coff_obj); |
| 847 | coff_obj.* = .{ .allocator = allocator }; | 842 | coff_obj.* = try coff.Coff.init(coff_bytes); |
| 848 | | 843 | |
| 849 | var di = ModuleDebugInfo{ | 844 | var di = ModuleDebugInfo{ |
| 850 | .base_address = undefined, | 845 | .base_address = undefined, |
| 851 | .coff = coff_obj, | 846 | .coff_image_base = coff_obj.getImageBase(), |
| | 847 | .coff_section_headers = undefined, |
| 852 | .debug_data = undefined, | 848 | .debug_data = undefined, |
| 853 | }; | 849 | }; |
| 854 | | 850 | |
| 855 | // TODO convert to Windows' memory-mapped file API | 851 | if (coff_obj.getSectionByName(".debug_info")) |sec| { |
| 856 | const file_len = math.cast(usize, try coff_file.getEndPos()) orelse math.maxInt(usize); | | |
| 857 | const data = try coff_file.readToEndAlloc(allocator, file_len); | | |
| 858 | try di.coff.parse(data); | | |
| 859 | | | |
| 860 | if (di.coff.getSectionByName(".debug_info")) |sec| { | | |
| 861 | // This coff file has embedded DWARF debug info | 852 | // This coff file has embedded DWARF debug info |
| 862 | _ = sec; | 853 | _ = sec; |
| 863 | // TODO: free the section data slices | 854 | |
| 864 | const debug_info = di.coff.getSectionDataAlloc(".debug_info", allocator) catch null; | 855 | const debug_info = coff_obj.getSectionDataAlloc(".debug_info", allocator) catch return error.MissingDebugInfo; |
| 865 | const debug_abbrev = di.coff.getSectionDataAlloc(".debug_abbrev", allocator) catch null; | 856 | errdefer allocator.free(debug_info); |
| 866 | const debug_str = di.coff.getSectionDataAlloc(".debug_str", allocator) catch null; | 857 | const debug_abbrev = coff_obj.getSectionDataAlloc(".debug_abbrev", allocator) catch return error.MissingDebugInfo; |
| 867 | const debug_str_offsets = di.coff.getSectionDataAlloc(".debug_str_offsets", allocator) catch null; | 858 | errdefer allocator.free(debug_abbrev); |
| 868 | const debug_line = di.coff.getSectionDataAlloc(".debug_line", allocator) catch null; | 859 | const debug_str = coff_obj.getSectionDataAlloc(".debug_str", allocator) catch return error.MissingDebugInfo; |
| 869 | const debug_line_str = di.coff.getSectionDataAlloc(".debug_line_str", allocator) catch null; | 860 | errdefer allocator.free(debug_str); |
| 870 | const debug_ranges = di.coff.getSectionDataAlloc(".debug_ranges", allocator) catch null; | 861 | const debug_line = coff_obj.getSectionDataAlloc(".debug_line", allocator) catch return error.MissingDebugInfo; |
| 871 | const debug_loclists = di.coff.getSectionDataAlloc(".debug_loclists", allocator) catch null; | 862 | errdefer allocator.free(debug_line); |
| 872 | const debug_rnglists = di.coff.getSectionDataAlloc(".debug_rnglists", allocator) catch null; | 863 | |
| 873 | const debug_addr = di.coff.getSectionDataAlloc(".debug_addr", allocator) catch null; | 864 | const debug_str_offsets = coff_obj.getSectionDataAlloc(".debug_str_offsets", allocator) catch null; |
| 874 | const debug_names = di.coff.getSectionDataAlloc(".debug_names", allocator) catch null; | 865 | const debug_line_str = coff_obj.getSectionDataAlloc(".debug_line_str", allocator) catch null; |
| 875 | const debug_frame = di.coff.getSectionDataAlloc(".debug_frame", allocator) catch null; | 866 | const debug_ranges = coff_obj.getSectionDataAlloc(".debug_ranges", allocator) catch null; |
| | 867 | const debug_loclists = coff_obj.getSectionDataAlloc(".debug_loclists", allocator) catch null; |
| | 868 | const debug_rnglists = coff_obj.getSectionDataAlloc(".debug_rnglists", allocator) catch null; |
| | 869 | const debug_addr = coff_obj.getSectionDataAlloc(".debug_addr", allocator) catch null; |
| | 870 | const debug_names = coff_obj.getSectionDataAlloc(".debug_names", allocator) catch null; |
| | 871 | const debug_frame = coff_obj.getSectionDataAlloc(".debug_frame", allocator) catch null; |
| 876 | | 872 | |
| 877 | var dwarf = DW.DwarfInfo{ | 873 | var dwarf = DW.DwarfInfo{ |
| 878 | .endian = native_endian, | 874 | .endian = native_endian, |
| 879 | .debug_info = debug_info orelse return error.MissingDebugInfo, | 875 | .debug_info = debug_info, |
| 880 | .debug_abbrev = debug_abbrev orelse return error.MissingDebugInfo, | 876 | .debug_abbrev = debug_abbrev, |
| 881 | .debug_str = debug_str orelse return error.MissingDebugInfo, | 877 | .debug_str = debug_str, |
| 882 | .debug_str_offsets = debug_str_offsets, | 878 | .debug_str_offsets = debug_str_offsets, |
| 883 | .debug_line = debug_line orelse return error.MissingDebugInfo, | 879 | .debug_line = debug_line, |
| 884 | .debug_line_str = debug_line_str, | 880 | .debug_line_str = debug_line_str, |
| 885 | .debug_ranges = debug_ranges, | 881 | .debug_ranges = debug_ranges, |
| 886 | .debug_loclists = debug_loclists, | 882 | .debug_loclists = debug_loclists, |
| ... | @@ -889,13 +885,28 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo | ... | @@ -889,13 +885,28 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo |
| 889 | .debug_names = debug_names, | 885 | .debug_names = debug_names, |
| 890 | .debug_frame = debug_frame, | 886 | .debug_frame = debug_frame, |
| 891 | }; | 887 | }; |
| 892 | try DW.openDwarfDebugInfo(&dwarf, allocator); | 888 | |
| | 889 | DW.openDwarfDebugInfo(&dwarf, allocator) catch |err| { |
| | 890 | if (debug_str_offsets) |d| allocator.free(d); |
| | 891 | if (debug_line_str) |d| allocator.free(d); |
| | 892 | if (debug_ranges) |d| allocator.free(d); |
| | 893 | if (debug_loclists) |d| allocator.free(d); |
| | 894 | if (debug_rnglists) |d| allocator.free(d); |
| | 895 | if (debug_addr) |d| allocator.free(d); |
| | 896 | if (debug_names) |d| allocator.free(d); |
| | 897 | if (debug_frame) |d| allocator.free(d); |
| | 898 | return err; |
| | 899 | }; |
| | 900 | |
| 893 | di.debug_data = PdbOrDwarf{ .dwarf = dwarf }; | 901 | di.debug_data = PdbOrDwarf{ .dwarf = dwarf }; |
| 894 | return di; | 902 | return di; |
| 895 | } | 903 | } |
| 896 | | 904 | |
| | 905 | // Only used by pdb path |
| | 906 | di.coff_section_headers = try coff_obj.getSectionHeadersAlloc(allocator); |
| | 907 | |
| 897 | var path_buf: [windows.MAX_PATH]u8 = undefined; | 908 | var path_buf: [windows.MAX_PATH]u8 = undefined; |
| 898 | const len = try di.coff.getPdbPath(path_buf[0..]); | 909 | const len = try coff_obj.getPdbPath(path_buf[0..]); |
| 899 | const raw_path = path_buf[0..len]; | 910 | const raw_path = path_buf[0..len]; |
| 900 | | 911 | |
| 901 | const path = try fs.path.resolve(allocator, &[_][]const u8{raw_path}); | 912 | const path = try fs.path.resolve(allocator, &[_][]const u8{raw_path}); |
| ... | @@ -909,7 +920,7 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo | ... | @@ -909,7 +920,7 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo |
| 909 | try di.debug_data.pdb.parseInfoStream(); | 920 | try di.debug_data.pdb.parseInfoStream(); |
| 910 | try di.debug_data.pdb.parseDbiStream(); | 921 | try di.debug_data.pdb.parseDbiStream(); |
| 911 | | 922 | |
| 912 | if (!mem.eql(u8, &di.coff.guid, &di.debug_data.pdb.guid) or di.coff.age != di.debug_data.pdb.age) | 923 | if (!mem.eql(u8, &coff_obj.guid, &di.debug_data.pdb.guid) or coff_obj.age != di.debug_data.pdb.age) |
| 913 | return error.InvalidDebugInfo; | 924 | return error.InvalidDebugInfo; |
| 914 | | 925 | |
| 915 | return di; | 926 | return di; |
| ... | @@ -1225,15 +1236,49 @@ fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 { | ... | @@ -1225,15 +1236,49 @@ fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 { |
| 1225 | } | 1236 | } |
| 1226 | } | 1237 | } |
| 1227 | | 1238 | |
| | 1239 | pub const ModuleInfo = struct { |
| | 1240 | base_address: usize, |
| | 1241 | size: u32, |
| | 1242 | }; |
| | 1243 | |
| 1228 | pub const DebugInfo = struct { | 1244 | pub const DebugInfo = struct { |
| 1229 | allocator: mem.Allocator, | 1245 | allocator: mem.Allocator, |
| 1230 | address_map: std.AutoHashMap(usize, *ModuleDebugInfo), | 1246 | address_map: std.AutoHashMap(usize, *ModuleDebugInfo), |
| | 1247 | modules: if (native_os == .windows) std.ArrayListUnmanaged(ModuleInfo) else void, |
| 1231 | | 1248 | |
| 1232 | pub fn init(allocator: mem.Allocator) DebugInfo { | 1249 | pub fn init(allocator: mem.Allocator) !DebugInfo { |
| 1233 | return DebugInfo{ | 1250 | var debug_info = DebugInfo{ |
| 1234 | .allocator = allocator, | 1251 | .allocator = allocator, |
| 1235 | .address_map = std.AutoHashMap(usize, *ModuleDebugInfo).init(allocator), | 1252 | .address_map = std.AutoHashMap(usize, *ModuleDebugInfo).init(allocator), |
| | 1253 | .modules = if (native_os == .windows) .{} else {}, |
| 1236 | }; | 1254 | }; |
| | 1255 | |
| | 1256 | if (native_os == .windows) { |
| | 1257 | const handle = windows.kernel32.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE | windows.TH32CS_SNAPMODULE32, 0); |
| | 1258 | if (handle == windows.INVALID_HANDLE_VALUE) { |
| | 1259 | switch (windows.kernel32.GetLastError()) { |
| | 1260 | else => |err| return windows.unexpectedError(err), |
| | 1261 | } |
| | 1262 | } |
| | 1263 | |
| | 1264 | defer windows.CloseHandle(handle); |
| | 1265 | |
| | 1266 | var module_entry: windows.MODULEENTRY32 = undefined; |
| | 1267 | module_entry.dwSize = @sizeOf(windows.MODULEENTRY32); |
| | 1268 | if (windows.kernel32.Module32First(handle, &module_entry) == 0) { |
| | 1269 | return error.MissingDebugInfo; |
| | 1270 | } |
| | 1271 | |
| | 1272 | var module_valid = true; |
| | 1273 | while (module_valid) { |
| | 1274 | const module_info = try debug_info.modules.addOne(allocator); |
| | 1275 | module_info.base_address = @ptrToInt(module_entry.modBaseAddr); |
| | 1276 | module_info.size = module_entry.modBaseSize; |
| | 1277 | module_valid = windows.kernel32.Module32Next(handle, &module_entry) == 1; |
| | 1278 | } |
| | 1279 | } |
| | 1280 | |
| | 1281 | return debug_info; |
| 1237 | } | 1282 | } |
| 1238 | | 1283 | |
| 1239 | pub fn deinit(self: *DebugInfo) void { | 1284 | pub fn deinit(self: *DebugInfo) void { |
| ... | @@ -1322,79 +1367,20 @@ pub const DebugInfo = struct { | ... | @@ -1322,79 +1367,20 @@ pub const DebugInfo = struct { |
| 1322 | } | 1367 | } |
| 1323 | | 1368 | |
| 1324 | fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ModuleDebugInfo { | 1369 | fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ModuleDebugInfo { |
| 1325 | const process_handle = windows.kernel32.GetCurrentProcess(); | 1370 | for (self.modules.items) |module| { |
| 1326 | | 1371 | if (address >= module.base_address and address < module.base_address + module.size) { |
| 1327 | // Find how many modules are actually loaded | 1372 | if (self.address_map.get(module.base_address)) |obj_di| { |
| 1328 | var dummy: windows.HMODULE = undefined; | | |
| 1329 | var bytes_needed: windows.DWORD = undefined; | | |
| 1330 | if (windows.kernel32.K32EnumProcessModules( | | |
| 1331 | process_handle, | | |
| 1332 | @ptrCast([*]windows.HMODULE, &dummy), | | |
| 1333 | 0, | | |
| 1334 | &bytes_needed, | | |
| 1335 | ) == 0) | | |
| 1336 | return error.MissingDebugInfo; | | |
| 1337 | | | |
| 1338 | const needed_modules = bytes_needed / @sizeOf(windows.HMODULE); | | |
| 1339 | | | |
| 1340 | // Fetch the complete module list | | |
| 1341 | var modules = try self.allocator.alloc(windows.HMODULE, needed_modules); | | |
| 1342 | defer self.allocator.free(modules); | | |
| 1343 | if (windows.kernel32.K32EnumProcessModules( | | |
| 1344 | process_handle, | | |
| 1345 | modules.ptr, | | |
| 1346 | math.cast(windows.DWORD, modules.len * @sizeOf(windows.HMODULE)) orelse return error.Overflow, | | |
| 1347 | &bytes_needed, | | |
| 1348 | ) == 0) | | |
| 1349 | return error.MissingDebugInfo; | | |
| 1350 | | | |
| 1351 | // There's an unavoidable TOCTOU problem here, the module list may have | | |
| 1352 | // changed between the two EnumProcessModules call. | | |
| 1353 | // Pick the smallest amount of elements to avoid processing garbage. | | |
| 1354 | const needed_modules_after = bytes_needed / @sizeOf(windows.HMODULE); | | |
| 1355 | const loaded_modules = math.min(needed_modules, needed_modules_after); | | |
| 1356 | | | |
| 1357 | for (modules[0..loaded_modules]) |module| { | | |
| 1358 | var info: windows.MODULEINFO = undefined; | | |
| 1359 | if (windows.kernel32.K32GetModuleInformation( | | |
| 1360 | process_handle, | | |
| 1361 | module, | | |
| 1362 | &info, | | |
| 1363 | @sizeOf(@TypeOf(info)), | | |
| 1364 | ) == 0) | | |
| 1365 | return error.MissingDebugInfo; | | |
| 1366 | | | |
| 1367 | const seg_start = @ptrToInt(info.lpBaseOfDll); | | |
| 1368 | const seg_end = seg_start + info.SizeOfImage; | | |
| 1369 | | | |
| 1370 | if (address >= seg_start and address < seg_end) { | | |
| 1371 | if (self.address_map.get(seg_start)) |obj_di| { | | |
| 1372 | return obj_di; | 1373 | return obj_di; |
| 1373 | } | 1374 | } |
| 1374 | | 1375 | |
| 1375 | var name_buffer: [windows.PATH_MAX_WIDE + 4:0]u16 = undefined; | 1376 | const mapped_module = @intToPtr([*]const u8, module.base_address)[0..module.size]; |
| 1376 | // openFileAbsoluteW requires the prefix to be present | | |
| 1377 | mem.copy(u16, name_buffer[0..4], &[_]u16{ '\\', '?', '?', '\\' }); | | |
| 1378 | const len = windows.kernel32.K32GetModuleFileNameExW( | | |
| 1379 | process_handle, | | |
| 1380 | module, | | |
| 1381 | @ptrCast(windows.LPWSTR, &name_buffer[4]), | | |
| 1382 | windows.PATH_MAX_WIDE, | | |
| 1383 | ); | | |
| 1384 | assert(len > 0); | | |
| 1385 | | | |
| 1386 | const obj_di = try self.allocator.create(ModuleDebugInfo); | 1377 | const obj_di = try self.allocator.create(ModuleDebugInfo); |
| 1387 | errdefer self.allocator.destroy(obj_di); | 1378 | errdefer self.allocator.destroy(obj_di); |
| 1388 | | 1379 | |
| 1389 | const coff_file = fs.openFileAbsoluteW(name_buffer[0 .. len + 4 :0], .{}) catch |err| switch (err) { | 1380 | obj_di.* = try readCoffDebugInfo(self.allocator, mapped_module); |
| 1390 | error.FileNotFound => return error.MissingDebugInfo, | 1381 | obj_di.base_address = module.base_address; |
| 1391 | else => return err, | | |
| 1392 | }; | | |
| 1393 | obj_di.* = try readCoffDebugInfo(self.allocator, coff_file); | | |
| 1394 | obj_di.base_address = seg_start; | | |
| 1395 | | | |
| 1396 | try self.address_map.putNoClobber(seg_start, obj_di); | | |
| 1397 | | 1382 | |
| | 1383 | try self.address_map.putNoClobber(module.base_address, obj_di); |
| 1398 | return obj_di; | 1384 | return obj_di; |
| 1399 | } | 1385 | } |
| 1400 | } | 1386 | } |
| ... | @@ -1727,12 +1713,31 @@ pub const ModuleDebugInfo = switch (native_os) { | ... | @@ -1727,12 +1713,31 @@ pub const ModuleDebugInfo = switch (native_os) { |
| 1727 | .uefi, .windows => struct { | 1713 | .uefi, .windows => struct { |
| 1728 | base_address: usize, | 1714 | base_address: usize, |
| 1729 | debug_data: PdbOrDwarf, | 1715 | debug_data: PdbOrDwarf, |
| 1730 | coff: *coff.Coff, | 1716 | coff_image_base: u64, |
| | 1717 | coff_section_headers: []coff.SectionHeader, |
| 1731 | | 1718 | |
| 1732 | fn deinit(self: *@This(), allocator: mem.Allocator) void { | 1719 | fn deinit(self: *@This(), allocator: mem.Allocator) void { |
| | 1720 | switch (self.debug_data) { |
| | 1721 | .dwarf => |*dwarf| { |
| | 1722 | allocator.free(dwarf.debug_info); |
| | 1723 | allocator.free(dwarf.debug_abbrev); |
| | 1724 | allocator.free(dwarf.debug_str); |
| | 1725 | allocator.free(dwarf.debug_line); |
| | 1726 | if (dwarf.debug_str_offsets) |d| allocator.free(d); |
| | 1727 | if (dwarf.debug_line_str) |d| allocator.free(d); |
| | 1728 | if (dwarf.debug_ranges) |d| allocator.free(d); |
| | 1729 | if (dwarf.debug_loclists) |d| allocator.free(d); |
| | 1730 | if (dwarf.debug_rnglists) |d| allocator.free(d); |
| | 1731 | if (dwarf.debug_addr) |d| allocator.free(d); |
| | 1732 | if (dwarf.debug_names) |d| allocator.free(d); |
| | 1733 | if (dwarf.debug_frame) |d| allocator.free(d); |
| | 1734 | }, |
| | 1735 | .pdb => { |
| | 1736 | allocator.free(self.coff_section_headers); |
| | 1737 | }, |
| | 1738 | } |
| | 1739 | |
| 1733 | self.debug_data.deinit(allocator); | 1740 | self.debug_data.deinit(allocator); |
| 1734 | self.coff.deinit(); | | |
| 1735 | allocator.destroy(self.coff); | | |
| 1736 | } | 1741 | } |
| 1737 | | 1742 | |
| 1738 | pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo { | 1743 | pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo { |
| ... | @@ -1741,7 +1746,7 @@ pub const ModuleDebugInfo = switch (native_os) { | ... | @@ -1741,7 +1746,7 @@ pub const ModuleDebugInfo = switch (native_os) { |
| 1741 | | 1746 | |
| 1742 | switch (self.debug_data) { | 1747 | switch (self.debug_data) { |
| 1743 | .dwarf => |*dwarf| { | 1748 | .dwarf => |*dwarf| { |
| 1744 | const dwarf_address = relocated_address + self.coff.getImageBase(); | 1749 | const dwarf_address = relocated_address + self.coff_image_base; |
| 1745 | return getSymbolFromDwarf(allocator, dwarf_address, dwarf); | 1750 | return getSymbolFromDwarf(allocator, dwarf_address, dwarf); |
| 1746 | }, | 1751 | }, |
| 1747 | .pdb => { | 1752 | .pdb => { |
| ... | @@ -1751,10 +1756,9 @@ pub const ModuleDebugInfo = switch (native_os) { | ... | @@ -1751,10 +1756,9 @@ pub const ModuleDebugInfo = switch (native_os) { |
| 1751 | | 1756 | |
| 1752 | var coff_section: *align(1) const coff.SectionHeader = undefined; | 1757 | var coff_section: *align(1) const coff.SectionHeader = undefined; |
| 1753 | const mod_index = for (self.debug_data.pdb.sect_contribs) |sect_contrib| { | 1758 | const mod_index = for (self.debug_data.pdb.sect_contribs) |sect_contrib| { |
| 1754 | const sections = self.coff.getSectionHeaders(); | 1759 | if (sect_contrib.Section > self.coff_section_headers.len) continue; |
| 1755 | if (sect_contrib.Section > sections.len) continue; | | |
| 1756 | // Remember that SectionContribEntry.Section is 1-based. | 1760 | // Remember that SectionContribEntry.Section is 1-based. |
| 1757 | coff_section = &sections[sect_contrib.Section - 1]; | 1761 | coff_section = &self.coff_section_headers[sect_contrib.Section - 1]; |
| 1758 | | 1762 | |
| 1759 | const vaddr_start = coff_section.virtual_address + sect_contrib.Offset; | 1763 | const vaddr_start = coff_section.virtual_address + sect_contrib.Offset; |
| 1760 | const vaddr_end = vaddr_start + sect_contrib.Size; | 1764 | const vaddr_end = vaddr_start + sect_contrib.Size; |