| ... | ... | @@ -396,9 +396,6 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: us |
| 396 | 396 | if (builtin.os == .windows) { |
| 397 | 397 | return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_config); |
| 398 | 398 | } |
| 399 | | if (comptime std.Target.current.isDarwin()) { |
| 400 | | return noasync printSourceAtAddressMacOs(debug_info, out_stream, address, tty_config); |
| 401 | | } |
| 402 | 399 | return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_config); |
| 403 | 400 | } |
| 404 | 401 | |
| ... | ... | @@ -411,7 +408,7 @@ fn printSourceAtAddressWindows( |
| 411 | 408 | ) !void { |
| 412 | 409 | const allocator = debug_info.allocator; |
| 413 | 410 | |
| 414 | | const module = debug_info.lookupByAddress(address) catch |err| switch (err) { |
| 411 | const module = debug_info.getModuleForAddress(address) catch |err| switch (err) { |
| 415 | 412 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 416 | 413 | return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs); |
| 417 | 414 | }, |
| ... | ... | @@ -637,7 +634,7 @@ pub const TTY = struct { |
| 637 | 634 | }; |
| 638 | 635 | |
| 639 | 636 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 640 | | fn populateModule(di: *ObjectDebugInfo, mod: *Module) !void { |
| 637 | fn populateModule(di: *ModuleDebugInfo, mod: *Module) !void { |
| 641 | 638 | if (mod.populated) |
| 642 | 639 | return; |
| 643 | 640 | const allocator = getDebugInfoAllocator(); |
| ... | ... | @@ -701,46 +698,8 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach |
| 701 | 698 | return null; |
| 702 | 699 | } |
| 703 | 700 | |
| 704 | | fn printSourceAtAddressMacOs(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void { |
| 705 | | const module = debug_info.lookupByAddress(address) catch |err| switch (err) { |
| 706 | | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 707 | | return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs); |
| 708 | | }, |
| 709 | | else => return err, |
| 710 | | }; |
| 711 | | |
| 712 | | const relocated_address = address - module.base_address; |
| 713 | | assert(relocated_address >= 0x100000000); |
| 714 | | |
| 715 | | const symbol = machoSearchSymbols(module.symbols, relocated_address) orelse { |
| 716 | | return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs); |
| 717 | | }; |
| 718 | | |
| 719 | | const symbol_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, module.strings.ptr + symbol.nlist.n_strx)); |
| 720 | | const compile_unit_name = if (symbol.ofile) |ofile| blk: { |
| 721 | | const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, module.strings.ptr + ofile.n_strx)); |
| 722 | | break :blk fs.path.basename(ofile_path); |
| 723 | | } else "???"; |
| 724 | | |
| 725 | | const line_info = getLineNumberInfoMacOs(module, symbol.*, relocated_address) catch |err| switch (err) { |
| 726 | | error.MissingDebugInfo, error.InvalidDebugInfo => null, |
| 727 | | else => return err, |
| 728 | | }; |
| 729 | | defer if (line_info) |li| li.deinit(); |
| 730 | | |
| 731 | | try printLineInfo( |
| 732 | | out_stream, |
| 733 | | line_info, |
| 734 | | address, |
| 735 | | symbol_name, |
| 736 | | compile_unit_name, |
| 737 | | tty_config, |
| 738 | | printLineFromFileAnyOs, |
| 739 | | ); |
| 740 | | } |
| 741 | | |
| 742 | 701 | pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void { |
| 743 | | const module = debug_info.lookupByAddress(address) catch |err| switch (err) { |
| 702 | const module = debug_info.getModuleForAddress(address) catch |err| switch (err) { |
| 744 | 703 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 745 | 704 | return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs); |
| 746 | 705 | }, |
| ... | ... | @@ -748,7 +707,7 @@ pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, addres |
| 748 | 707 | }; |
| 749 | 708 | |
| 750 | 709 | const info = try module.getSymbolAtAddress(address); |
| 751 | | defer if (info.line_info) |li| li.deinit(); |
| 710 | defer info.deinit(); |
| 752 | 711 | |
| 753 | 712 | return printLineInfo( |
| 754 | 713 | out_stream, |
| ... | ... | @@ -833,14 +792,14 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { |
| 833 | 792 | } |
| 834 | 793 | |
| 835 | 794 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 836 | | fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !ObjectDebugInfo { |
| 795 | fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !ModuleDebugInfo { |
| 837 | 796 | const coff_file = try std.fs.openFileAbsoluteW(coff_file_path.ptr, .{}); |
| 838 | 797 | errdefer coff_file.close(); |
| 839 | 798 | |
| 840 | 799 | const coff_obj = try allocator.create(coff.Coff); |
| 841 | 800 | coff_obj.* = coff.Coff.init(allocator, coff_file); |
| 842 | 801 | |
| 843 | | var di = ObjectDebugInfo{ |
| 802 | var di = ModuleDebugInfo{ |
| 844 | 803 | .base_address = undefined, |
| 845 | 804 | .coff = coff_obj, |
| 846 | 805 | .pdb = undefined, |
| ... | ... | @@ -1012,7 +971,7 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 { |
| 1012 | 971 | } |
| 1013 | 972 | |
| 1014 | 973 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 1015 | | pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ObjectDebugInfo { |
| 974 | pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ModuleDebugInfo { |
| 1016 | 975 | const mapped_mem = mapWholeFile(elf_file_path) catch |_| return error.InvalidDebugInfo; |
| 1017 | 976 | |
| 1018 | 977 | var seekable_stream = io.SliceSeekableInStream.init(mapped_mem); |
| ... | ... | @@ -1047,7 +1006,7 @@ pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !O |
| 1047 | 1006 | |
| 1048 | 1007 | try DW.openDwarfDebugInfo(&di, allocator); |
| 1049 | 1008 | |
| 1050 | | return ObjectDebugInfo{ |
| 1009 | return ModuleDebugInfo{ |
| 1051 | 1010 | .base_address = undefined, |
| 1052 | 1011 | .dwarf = di, |
| 1053 | 1012 | .mapped_memory = mapped_mem, |
| ... | ... | @@ -1055,14 +1014,15 @@ pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !O |
| 1055 | 1014 | } |
| 1056 | 1015 | |
| 1057 | 1016 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 1058 | | fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !ObjectDebugInfo { |
| 1017 | fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !ModuleDebugInfo { |
| 1059 | 1018 | const mapped_mem = mapWholeFile(macho_file_path) catch |_| return error.InvalidDebugInfo; |
| 1060 | 1019 | |
| 1061 | 1020 | const hdr = @ptrCast( |
| 1062 | 1021 | *const macho.mach_header_64, |
| 1063 | 1022 | @alignCast(@alignOf(macho.mach_header_64), mapped_mem.ptr), |
| 1064 | 1023 | ); |
| 1065 | | assert(hdr.magic == std.macho.MH_MAGIC_64); |
| 1024 | if (hdr.magic != macho.MH_MAGIC_64) |
| 1025 | return error.InvalidDebugInfo; |
| 1066 | 1026 | |
| 1067 | 1027 | const hdr_base = @ptrCast([*]const u8, hdr); |
| 1068 | 1028 | var ptr = hdr_base + @sizeOf(macho.mach_header_64); |
| ... | ... | @@ -1078,7 +1038,7 @@ fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !O |
| 1078 | 1038 | return error.MissingDebugInfo; |
| 1079 | 1039 | }; |
| 1080 | 1040 | const syms = @ptrCast([*]const macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms]; |
| 1081 | | const strings = @ptrCast([*]const u8, hdr_base + symtab.stroff)[0..symtab.strsize]; |
| 1041 | const strings = @ptrCast([*]const u8, hdr_base + symtab.stroff)[0..symtab.strsize :0]; |
| 1082 | 1042 | |
| 1083 | 1043 | const symbols_buf = try allocator.alloc(MachoSymbol, syms.len); |
| 1084 | 1044 | |
| ... | ... | @@ -1130,10 +1090,10 @@ fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !O |
| 1130 | 1090 | // This sort is so that we can binary search later. |
| 1131 | 1091 | std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan); |
| 1132 | 1092 | |
| 1133 | | return ObjectDebugInfo{ |
| 1093 | return ModuleDebugInfo{ |
| 1134 | 1094 | .base_address = undefined, |
| 1135 | 1095 | .mapped_memory = mapped_mem, |
| 1136 | | .ofiles = ObjectDebugInfo.OFileTable.init(allocator), |
| 1096 | .ofiles = ModuleDebugInfo.OFileTable.init(allocator), |
| 1137 | 1097 | .symbols = symbols, |
| 1138 | 1098 | .strings = strings, |
| 1139 | 1099 | }; |
| ... | ... | @@ -1206,12 +1166,12 @@ fn mapWholeFile(path: []const u8) ![]const u8 { |
| 1206 | 1166 | |
| 1207 | 1167 | pub const DebugInfo = struct { |
| 1208 | 1168 | allocator: *mem.Allocator, |
| 1209 | | address_map: std.AutoHashMap(usize, *ObjectDebugInfo), |
| 1169 | address_map: std.AutoHashMap(usize, *ModuleDebugInfo), |
| 1210 | 1170 | |
| 1211 | 1171 | pub fn init(allocator: *mem.Allocator) DebugInfo { |
| 1212 | 1172 | return DebugInfo{ |
| 1213 | 1173 | .allocator = allocator, |
| 1214 | | .address_map = std.AutoHashMap(usize, *ObjectDebugInfo).init(allocator), |
| 1174 | .address_map = std.AutoHashMap(usize, *ModuleDebugInfo).init(allocator), |
| 1215 | 1175 | }; |
| 1216 | 1176 | } |
| 1217 | 1177 | |
| ... | ... | @@ -1220,17 +1180,16 @@ pub const DebugInfo = struct { |
| 1220 | 1180 | self.address_map.deinit(); |
| 1221 | 1181 | } |
| 1222 | 1182 | |
| 1223 | | pub fn lookupByAddress(self: *DebugInfo, address: usize) !*ObjectDebugInfo { |
| 1224 | | const obj_di = if (comptime std.Target.current.isDarwin()) |
| 1225 | | try self.lookupModuleDyld(address) |
| 1183 | pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo { |
| 1184 | if (comptime std.Target.current.isDarwin()) |
| 1185 | return self.lookupModuleDyld(address) |
| 1226 | 1186 | else if (builtin.os == .windows) |
| 1227 | | try self.lookupModuleWin32(address) |
| 1187 | return self.lookupModuleWin32(address) |
| 1228 | 1188 | else |
| 1229 | | try self.lookupModuleDl(address); |
| 1230 | | return obj_di; |
| 1189 | return self.lookupModuleDl(address); |
| 1231 | 1190 | } |
| 1232 | 1191 | |
| 1233 | | fn lookupModuleDyld(self: *DebugInfo, address: usize) !*ObjectDebugInfo { |
| 1192 | fn lookupModuleDyld(self: *DebugInfo, address: usize) !*ModuleDebugInfo { |
| 1234 | 1193 | const image_count = std.c._dyld_image_count(); |
| 1235 | 1194 | |
| 1236 | 1195 | var i: u32 = 0; |
| ... | ... | @@ -1266,7 +1225,7 @@ pub const DebugInfo = struct { |
| 1266 | 1225 | return obj_di; |
| 1267 | 1226 | } |
| 1268 | 1227 | |
| 1269 | | const obj_di = try self.allocator.create(ObjectDebugInfo); |
| 1228 | const obj_di = try self.allocator.create(ModuleDebugInfo); |
| 1270 | 1229 | errdefer self.allocator.destroy(obj_di); |
| 1271 | 1230 | |
| 1272 | 1231 | try self.address_map.putNoClobber(base_address, obj_di); |
| ... | ... | @@ -1283,7 +1242,7 @@ pub const DebugInfo = struct { |
| 1283 | 1242 | return error.MissingDebugInfo; |
| 1284 | 1243 | } |
| 1285 | 1244 | |
| 1286 | | fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ObjectDebugInfo { |
| 1245 | fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ModuleDebugInfo { |
| 1287 | 1246 | const process_handle = windows.kernel32.GetCurrentProcess(); |
| 1288 | 1247 | |
| 1289 | 1248 | // Find how many modules are actually loaded |
| ... | ... | @@ -1345,7 +1304,7 @@ pub const DebugInfo = struct { |
| 1345 | 1304 | ); |
| 1346 | 1305 | assert(len > 0); |
| 1347 | 1306 | |
| 1348 | | const obj_di = try self.allocator.create(ObjectDebugInfo); |
| 1307 | const obj_di = try self.allocator.create(ModuleDebugInfo); |
| 1349 | 1308 | errdefer self.allocator.destroy(obj_di); |
| 1350 | 1309 | |
| 1351 | 1310 | try self.address_map.putNoClobber(seg_start, obj_di); |
| ... | ... | @@ -1360,7 +1319,7 @@ pub const DebugInfo = struct { |
| 1360 | 1319 | return error.MissingDebugInfo; |
| 1361 | 1320 | } |
| 1362 | 1321 | |
| 1363 | | fn lookupModuleDl(self: *DebugInfo, address: usize) !*ObjectDebugInfo { |
| 1322 | fn lookupModuleDl(self: *DebugInfo, address: usize) !*ModuleDebugInfo { |
| 1364 | 1323 | var ctx: struct { |
| 1365 | 1324 | // Input |
| 1366 | 1325 | address: usize, |
| ... | ... | @@ -1414,7 +1373,7 @@ pub const DebugInfo = struct { |
| 1414 | 1373 | break :blk try fs.selfExePath(&buf); |
| 1415 | 1374 | }; |
| 1416 | 1375 | |
| 1417 | | const obj_di = try self.allocator.create(ObjectDebugInfo); |
| 1376 | const obj_di = try self.allocator.create(ModuleDebugInfo); |
| 1418 | 1377 | errdefer self.allocator.destroy(obj_di); |
| 1419 | 1378 | |
| 1420 | 1379 | try self.address_map.putNoClobber(ctx.base_address, obj_di); |
| ... | ... | @@ -1427,29 +1386,173 @@ pub const DebugInfo = struct { |
| 1427 | 1386 | }; |
| 1428 | 1387 | |
| 1429 | 1388 | const SymbolInfo = struct { |
| 1430 | | symbol_name: []const u8, |
| 1431 | | compile_unit_name: []const u8, |
| 1432 | | line_info: ?LineInfo, |
| 1389 | symbol_name: []const u8 = "???", |
| 1390 | compile_unit_name: []const u8 = "???", |
| 1391 | line_info: ?LineInfo = null, |
| 1392 | |
| 1393 | fn deinit(self: @This()) void { |
| 1394 | if (self.line_info) |li| { |
| 1395 | li.deinit(); |
| 1396 | } |
| 1397 | } |
| 1433 | 1398 | }; |
| 1434 | 1399 | |
| 1435 | | pub const ObjectDebugInfo = switch (builtin.os) { |
| 1400 | pub const ModuleDebugInfo = switch (builtin.os) { |
| 1436 | 1401 | .macosx, .ios, .watchos, .tvos => struct { |
| 1437 | 1402 | base_address: usize, |
| 1438 | 1403 | mapped_memory: []const u8, |
| 1439 | 1404 | symbols: []const MachoSymbol, |
| 1440 | | strings: []const u8, |
| 1405 | strings: [:0]const u8, |
| 1441 | 1406 | ofiles: OFileTable, |
| 1442 | 1407 | |
| 1443 | | const OFileTable = std.HashMap( |
| 1444 | | *const macho.nlist_64, |
| 1445 | | DW.DwarfInfo, |
| 1446 | | std.hash_map.getHashPtrAddrFn(*const macho.nlist_64), |
| 1447 | | std.hash_map.getTrivialEqlFn(*const macho.nlist_64), |
| 1448 | | ); |
| 1408 | const OFileTable = std.StringHashMap(DW.DwarfInfo); |
| 1449 | 1409 | |
| 1450 | 1410 | pub fn allocator(self: @This()) *mem.Allocator { |
| 1451 | 1411 | return self.ofiles.allocator; |
| 1452 | 1412 | } |
| 1413 | |
| 1414 | fn loadOFile(self: *@This(), o_file_path: []const u8) !DW.DwarfInfo { |
| 1415 | const mapped_mem = mapWholeFile(o_file_path) catch |_| return error.InvalidDebugInfo; |
| 1416 | |
| 1417 | const hdr = @ptrCast( |
| 1418 | *const macho.mach_header_64, |
| 1419 | @alignCast(@alignOf(macho.mach_header_64), mapped_mem.ptr), |
| 1420 | ); |
| 1421 | if (hdr.magic != std.macho.MH_MAGIC_64) |
| 1422 | return error.InvalidDebugInfo; |
| 1423 | |
| 1424 | const hdr_base = @ptrCast([*]const u8, hdr); |
| 1425 | var ptr = hdr_base + @sizeOf(macho.mach_header_64); |
| 1426 | var ncmd: u32 = hdr.ncmds; |
| 1427 | const segcmd = while (ncmd != 0) : (ncmd -= 1) { |
| 1428 | const lc = @ptrCast(*const std.macho.load_command, ptr); |
| 1429 | switch (lc.cmd) { |
| 1430 | std.macho.LC_SEGMENT_64 => { |
| 1431 | break @ptrCast( |
| 1432 | *const std.macho.segment_command_64, |
| 1433 | @alignCast(@alignOf(std.macho.segment_command_64), ptr), |
| 1434 | ); |
| 1435 | }, |
| 1436 | else => {}, |
| 1437 | } |
| 1438 | ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize); |
| 1439 | } else { |
| 1440 | return error.MissingDebugInfo; |
| 1441 | }; |
| 1442 | |
| 1443 | var opt_debug_line: ?*const macho.section_64 = null; |
| 1444 | var opt_debug_info: ?*const macho.section_64 = null; |
| 1445 | var opt_debug_abbrev: ?*const macho.section_64 = null; |
| 1446 | var opt_debug_str: ?*const macho.section_64 = null; |
| 1447 | var opt_debug_ranges: ?*const macho.section_64 = null; |
| 1448 | |
| 1449 | const sections = @ptrCast( |
| 1450 | [*]const macho.section_64, |
| 1451 | @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)), |
| 1452 | )[0..segcmd.nsects]; |
| 1453 | for (sections) |*sect| { |
| 1454 | // The section name may not exceed 16 chars and a trailing null may |
| 1455 | // not be present |
| 1456 | const name = if (mem.indexOfScalar(u8, sect.sectname[0..], 0)) |last| |
| 1457 | sect.sectname[0..last] |
| 1458 | else |
| 1459 | sect.sectname[0..]; |
| 1460 | |
| 1461 | if (mem.eql(u8, name, "__debug_line")) { |
| 1462 | opt_debug_line = sect; |
| 1463 | } else if (mem.eql(u8, name, "__debug_info")) { |
| 1464 | opt_debug_info = sect; |
| 1465 | } else if (mem.eql(u8, name, "__debug_abbrev")) { |
| 1466 | opt_debug_abbrev = sect; |
| 1467 | } else if (mem.eql(u8, name, "__debug_str")) { |
| 1468 | opt_debug_str = sect; |
| 1469 | } else if (mem.eql(u8, name, "__debug_ranges")) { |
| 1470 | opt_debug_ranges = sect; |
| 1471 | } |
| 1472 | } |
| 1473 | |
| 1474 | const debug_line = opt_debug_line orelse |
| 1475 | return error.MissingDebugInfo; |
| 1476 | const debug_info = opt_debug_info orelse |
| 1477 | return error.MissingDebugInfo; |
| 1478 | const debug_str = opt_debug_str orelse |
| 1479 | return error.MissingDebugInfo; |
| 1480 | const debug_abbrev = opt_debug_abbrev orelse |
| 1481 | return error.MissingDebugInfo; |
| 1482 | |
| 1483 | var di = DW.DwarfInfo{ |
| 1484 | .endian = .Little, |
| 1485 | .debug_info = try chopSlice(mapped_mem, debug_info.offset, debug_info.size), |
| 1486 | .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size), |
| 1487 | .debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size), |
| 1488 | .debug_line = try chopSlice(mapped_mem, debug_line.offset, debug_line.size), |
| 1489 | .debug_ranges = if (opt_debug_ranges) |debug_ranges| |
| 1490 | try chopSlice(mapped_mem, debug_ranges.offset, debug_ranges.size) |
| 1491 | else |
| 1492 | null, |
| 1493 | }; |
| 1494 | |
| 1495 | try DW.openDwarfDebugInfo(&di, self.allocator()); |
| 1496 | |
| 1497 | // Add the debug info to the cache |
| 1498 | try self.ofiles.putNoClobber(o_file_path, di); |
| 1499 | |
| 1500 | return di; |
| 1501 | } |
| 1502 | |
| 1503 | fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo { |
| 1504 | // Translate the VA into an address into this object |
| 1505 | const relocated_address = address - self.base_address; |
| 1506 | assert(relocated_address >= 0x100000000); |
| 1507 | |
| 1508 | // Find the .o file where this symbol is defined |
| 1509 | const symbol = machoSearchSymbols(self.symbols, relocated_address) orelse |
| 1510 | return SymbolInfo{}; |
| 1511 | |
| 1512 | // XXX: Return the symbol name |
| 1513 | if (symbol.ofile == null) |
| 1514 | return SymbolInfo{}; |
| 1515 | |
| 1516 | assert(symbol.ofile.?.n_strx < self.strings.len); |
| 1517 | const o_file_path = mem.toSliceConst(u8, self.strings.ptr + symbol.ofile.?.n_strx); |
| 1518 | |
| 1519 | warn("Loading .o file: {s}\n", .{o_file_path}); |
| 1520 | |
| 1521 | // Check if its debug infos are already in the cache |
| 1522 | var o_file_di = self.ofiles.getValue(o_file_path) orelse |
| 1523 | (self.loadOFile(o_file_path) catch |err| switch (err) { |
| 1524 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 1525 | // XXX: Return the symbol name |
| 1526 | return SymbolInfo{}; |
| 1527 | }, |
| 1528 | else => return err, |
| 1529 | }); |
| 1530 | |
| 1531 | // Translate again the address, this time into an address inside the |
| 1532 | // .o file |
| 1533 | const relocated_address_o = relocated_address - symbol.reloc; |
| 1534 | |
| 1535 | if (o_file_di.findCompileUnit(relocated_address_o)) |compile_unit| { |
| 1536 | return SymbolInfo{ |
| 1537 | .symbol_name = o_file_di.getSymbolName(relocated_address_o) orelse "???", |
| 1538 | .compile_unit_name = compile_unit.die.getAttrString(&o_file_di, DW.AT_name) catch |err| switch (err) { |
| 1539 | error.MissingDebugInfo, error.InvalidDebugInfo => "???", |
| 1540 | else => return err, |
| 1541 | }, |
| 1542 | .line_info = o_file_di.getLineNumberInfo(compile_unit.*, relocated_address_o) catch |err| switch (err) { |
| 1543 | error.MissingDebugInfo, error.InvalidDebugInfo => null, |
| 1544 | else => return err, |
| 1545 | }, |
| 1546 | }; |
| 1547 | } else |err| switch (err) { |
| 1548 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 1549 | return SymbolInfo{}; |
| 1550 | }, |
| 1551 | else => return err, |
| 1552 | } |
| 1553 | |
| 1554 | unreachable; |
| 1555 | } |
| 1453 | 1556 | }, |
| 1454 | 1557 | .uefi, .windows => struct { |
| 1455 | 1558 | base_address: usize, |
| ... | ... | @@ -1481,11 +1584,7 @@ pub const ObjectDebugInfo = switch (builtin.os) { |
| 1481 | 1584 | }; |
| 1482 | 1585 | } else |err| switch (err) { |
| 1483 | 1586 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 1484 | | return SymbolInfo{ |
| 1485 | | .symbol_name = "???", |
| 1486 | | .compile_unit_name = "???", |
| 1487 | | .line_info = null, |
| 1488 | | }; |
| 1587 | return SymbolInfo{}; |
| 1489 | 1588 | }, |
| 1490 | 1589 | else => return err, |
| 1491 | 1590 | } |
| ... | ... | @@ -1496,115 +1595,6 @@ pub const ObjectDebugInfo = switch (builtin.os) { |
| 1496 | 1595 | else => DW.DwarfInfo, |
| 1497 | 1596 | }; |
| 1498 | 1597 | |
| 1499 | | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 1500 | | fn getLineNumberInfoMacOs(di: *ObjectDebugInfo, symbol: MachoSymbol, address: usize) !LineInfo { |
| 1501 | | const ofile = symbol.ofile orelse return error.MissingDebugInfo; |
| 1502 | | const gop = try di.ofiles.getOrPut(ofile); |
| 1503 | | const dwarf_info = if (gop.found_existing) &gop.kv.value else blk: { |
| 1504 | | errdefer _ = di.ofiles.remove(ofile); |
| 1505 | | const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx)); |
| 1506 | | |
| 1507 | | var exe_file = try std.fs.openFileAbsoluteC(ofile_path, .{}); |
| 1508 | | errdefer exe_file.close(); |
| 1509 | | |
| 1510 | | const exe_len = math.cast(usize, try exe_file.getEndPos()) catch |
| 1511 | | return error.DebugInfoTooLarge; |
| 1512 | | const exe_mmap = try os.mmap( |
| 1513 | | null, |
| 1514 | | exe_len, |
| 1515 | | os.PROT_READ, |
| 1516 | | os.MAP_SHARED, |
| 1517 | | exe_file.handle, |
| 1518 | | 0, |
| 1519 | | ); |
| 1520 | | errdefer os.munmap(exe_mmap); |
| 1521 | | |
| 1522 | | const hdr = @ptrCast( |
| 1523 | | *const macho.mach_header_64, |
| 1524 | | @alignCast(@alignOf(macho.mach_header_64), exe_mmap.ptr), |
| 1525 | | ); |
| 1526 | | if (hdr.magic != std.macho.MH_MAGIC_64) return error.InvalidDebugInfo; |
| 1527 | | |
| 1528 | | const hdr_base = @ptrCast([*]const u8, hdr); |
| 1529 | | var ptr = hdr_base + @sizeOf(macho.mach_header_64); |
| 1530 | | var ncmd: u32 = hdr.ncmds; |
| 1531 | | const segcmd = while (ncmd != 0) : (ncmd -= 1) { |
| 1532 | | const lc = @ptrCast(*const std.macho.load_command, ptr); |
| 1533 | | switch (lc.cmd) { |
| 1534 | | std.macho.LC_SEGMENT_64 => { |
| 1535 | | break @ptrCast( |
| 1536 | | *const std.macho.segment_command_64, |
| 1537 | | @alignCast(@alignOf(std.macho.segment_command_64), ptr), |
| 1538 | | ); |
| 1539 | | }, |
| 1540 | | else => {}, |
| 1541 | | } |
| 1542 | | ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize); |
| 1543 | | } else { |
| 1544 | | return error.MissingDebugInfo; |
| 1545 | | }; |
| 1546 | | |
| 1547 | | var opt_debug_line: ?*const macho.section_64 = null; |
| 1548 | | var opt_debug_info: ?*const macho.section_64 = null; |
| 1549 | | var opt_debug_abbrev: ?*const macho.section_64 = null; |
| 1550 | | var opt_debug_str: ?*const macho.section_64 = null; |
| 1551 | | var opt_debug_ranges: ?*const macho.section_64 = null; |
| 1552 | | |
| 1553 | | const sections = @ptrCast( |
| 1554 | | [*]const macho.section_64, |
| 1555 | | @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)), |
| 1556 | | )[0..segcmd.nsects]; |
| 1557 | | for (sections) |*sect| { |
| 1558 | | // The section name may not exceed 16 chars and a trailing null may |
| 1559 | | // not be present |
| 1560 | | const name = if (mem.indexOfScalar(u8, sect.sectname[0..], 0)) |last| |
| 1561 | | sect.sectname[0..last] |
| 1562 | | else |
| 1563 | | sect.sectname[0..]; |
| 1564 | | |
| 1565 | | if (mem.eql(u8, name, "__debug_line")) { |
| 1566 | | opt_debug_line = sect; |
| 1567 | | } else if (mem.eql(u8, name, "__debug_info")) { |
| 1568 | | opt_debug_info = sect; |
| 1569 | | } else if (mem.eql(u8, name, "__debug_abbrev")) { |
| 1570 | | opt_debug_abbrev = sect; |
| 1571 | | } else if (mem.eql(u8, name, "__debug_str")) { |
| 1572 | | opt_debug_str = sect; |
| 1573 | | } else if (mem.eql(u8, name, "__debug_ranges")) { |
| 1574 | | opt_debug_ranges = sect; |
| 1575 | | } |
| 1576 | | } |
| 1577 | | |
| 1578 | | var debug_line = opt_debug_line orelse |
| 1579 | | return error.MissingDebugInfo; |
| 1580 | | var debug_info = opt_debug_info orelse |
| 1581 | | return error.MissingDebugInfo; |
| 1582 | | var debug_str = opt_debug_str orelse |
| 1583 | | return error.MissingDebugInfo; |
| 1584 | | var debug_abbrev = opt_debug_abbrev orelse |
| 1585 | | return error.MissingDebugInfo; |
| 1586 | | |
| 1587 | | gop.kv.value = DW.DwarfInfo{ |
| 1588 | | .endian = .Little, |
| 1589 | | .debug_info = try chopSlice(exe_mmap, debug_info.offset, debug_info.size), |
| 1590 | | .debug_abbrev = try chopSlice(exe_mmap, debug_abbrev.offset, debug_abbrev.size), |
| 1591 | | .debug_str = try chopSlice(exe_mmap, debug_str.offset, debug_str.size), |
| 1592 | | .debug_line = try chopSlice(exe_mmap, debug_line.offset, debug_line.size), |
| 1593 | | .debug_ranges = if (opt_debug_ranges) |debug_ranges| |
| 1594 | | try chopSlice(exe_mmap, debug_ranges.offset, debug_ranges.size) |
| 1595 | | else |
| 1596 | | null, |
| 1597 | | }; |
| 1598 | | try DW.openDwarfDebugInfo(&gop.kv.value, di.allocator()); |
| 1599 | | |
| 1600 | | break :blk &gop.kv.value; |
| 1601 | | }; |
| 1602 | | |
| 1603 | | const o_file_address = address - symbol.reloc; |
| 1604 | | const compile_unit = try dwarf_info.findCompileUnit(o_file_address); |
| 1605 | | return dwarf_info.getLineNumberInfo(compile_unit.*, o_file_address); |
| 1606 | | } |
| 1607 | | |
| 1608 | 1598 | /// TODO multithreaded awareness |
| 1609 | 1599 | var debug_info_allocator: ?*mem.Allocator = null; |
| 1610 | 1600 | var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined; |