| ... | @@ -396,9 +396,6 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: us | ... | @@ -396,9 +396,6 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: us |
| 396 | if (builtin.os == .windows) { | 396 | if (builtin.os == .windows) { |
| 397 | return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_config); | 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 | return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_config); | 399 | return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_config); |
| 403 | } | 400 | } |
| 404 | | 401 | |
| ... | @@ -411,7 +408,7 @@ fn printSourceAtAddressWindows( | ... | @@ -411,7 +408,7 @@ fn printSourceAtAddressWindows( |
| 411 | ) !void { | 408 | ) !void { |
| 412 | const allocator = debug_info.allocator; | 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 | error.MissingDebugInfo, error.InvalidDebugInfo => { | 412 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 416 | return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs); | 413 | return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs); |
| 417 | }, | 414 | }, |
| ... | @@ -637,7 +634,7 @@ pub const TTY = struct { | ... | @@ -637,7 +634,7 @@ pub const TTY = struct { |
| 637 | }; | 634 | }; |
| 638 | | 635 | |
| 639 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 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 | if (mod.populated) | 638 | if (mod.populated) |
| 642 | return; | 639 | return; |
| 643 | const allocator = getDebugInfoAllocator(); | 640 | const allocator = getDebugInfoAllocator(); |
| ... | @@ -701,46 +698,8 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach | ... | @@ -701,46 +698,8 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach |
| 701 | return null; | 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 | pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void { | 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 | error.MissingDebugInfo, error.InvalidDebugInfo => { | 703 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 745 | return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs); | 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,7 +707,7 @@ pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, addres |
| 748 | }; | 707 | }; |
| 749 | | 708 | |
| 750 | const info = try module.getSymbolAtAddress(address); | 709 | const info = try module.getSymbolAtAddress(address); |
| 751 | defer if (info.line_info) |li| li.deinit(); | 710 | defer info.deinit(); |
| 752 | | 711 | |
| 753 | return printLineInfo( | 712 | return printLineInfo( |
| 754 | out_stream, | 713 | out_stream, |
| ... | @@ -833,14 +792,14 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { | ... | @@ -833,14 +792,14 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { |
| 833 | } | 792 | } |
| 834 | | 793 | |
| 835 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 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 | const coff_file = try std.fs.openFileAbsoluteW(coff_file_path.ptr, .{}); | 796 | const coff_file = try std.fs.openFileAbsoluteW(coff_file_path.ptr, .{}); |
| 838 | errdefer coff_file.close(); | 797 | errdefer coff_file.close(); |
| 839 | | 798 | |
| 840 | const coff_obj = try allocator.create(coff.Coff); | 799 | const coff_obj = try allocator.create(coff.Coff); |
| 841 | coff_obj.* = coff.Coff.init(allocator, coff_file); | 800 | coff_obj.* = coff.Coff.init(allocator, coff_file); |
| 842 | | 801 | |
| 843 | var di = ObjectDebugInfo{ | 802 | var di = ModuleDebugInfo{ |
| 844 | .base_address = undefined, | 803 | .base_address = undefined, |
| 845 | .coff = coff_obj, | 804 | .coff = coff_obj, |
| 846 | .pdb = undefined, | 805 | .pdb = undefined, |
| ... | @@ -1012,7 +971,7 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 { | ... | @@ -1012,7 +971,7 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 { |
| 1012 | } | 971 | } |
| 1013 | | 972 | |
| 1014 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 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 | const mapped_mem = mapWholeFile(elf_file_path) catch |_| return error.InvalidDebugInfo; | 975 | const mapped_mem = mapWholeFile(elf_file_path) catch |_| return error.InvalidDebugInfo; |
| 1017 | | 976 | |
| 1018 | var seekable_stream = io.SliceSeekableInStream.init(mapped_mem); | 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,7 +1006,7 @@ pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !O |
| 1047 | | 1006 | |
| 1048 | try DW.openDwarfDebugInfo(&di, allocator); | 1007 | try DW.openDwarfDebugInfo(&di, allocator); |
| 1049 | | 1008 | |
| 1050 | return ObjectDebugInfo{ | 1009 | return ModuleDebugInfo{ |
| 1051 | .base_address = undefined, | 1010 | .base_address = undefined, |
| 1052 | .dwarf = di, | 1011 | .dwarf = di, |
| 1053 | .mapped_memory = mapped_mem, | 1012 | .mapped_memory = mapped_mem, |
| ... | @@ -1055,14 +1014,15 @@ pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !O | ... | @@ -1055,14 +1014,15 @@ pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !O |
| 1055 | } | 1014 | } |
| 1056 | | 1015 | |
| 1057 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 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 | const mapped_mem = mapWholeFile(macho_file_path) catch |_| return error.InvalidDebugInfo; | 1018 | const mapped_mem = mapWholeFile(macho_file_path) catch |_| return error.InvalidDebugInfo; |
| 1060 | | 1019 | |
| 1061 | const hdr = @ptrCast( | 1020 | const hdr = @ptrCast( |
| 1062 | *const macho.mach_header_64, | 1021 | *const macho.mach_header_64, |
| 1063 | @alignCast(@alignOf(macho.mach_header_64), mapped_mem.ptr), | 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 | const hdr_base = @ptrCast([*]const u8, hdr); | 1027 | const hdr_base = @ptrCast([*]const u8, hdr); |
| 1068 | var ptr = hdr_base + @sizeOf(macho.mach_header_64); | 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,7 +1038,7 @@ fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !O |
| 1078 | return error.MissingDebugInfo; | 1038 | return error.MissingDebugInfo; |
| 1079 | }; | 1039 | }; |
| 1080 | const syms = @ptrCast([*]const macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms]; | 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 | const symbols_buf = try allocator.alloc(MachoSymbol, syms.len); | 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,10 +1090,10 @@ fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !O |
| 1130 | // This sort is so that we can binary search later. | 1090 | // This sort is so that we can binary search later. |
| 1131 | std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan); | 1091 | std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan); |
| 1132 | | 1092 | |
| 1133 | return ObjectDebugInfo{ | 1093 | return ModuleDebugInfo{ |
| 1134 | .base_address = undefined, | 1094 | .base_address = undefined, |
| 1135 | .mapped_memory = mapped_mem, | 1095 | .mapped_memory = mapped_mem, |
| 1136 | .ofiles = ObjectDebugInfo.OFileTable.init(allocator), | 1096 | .ofiles = ModuleDebugInfo.OFileTable.init(allocator), |
| 1137 | .symbols = symbols, | 1097 | .symbols = symbols, |
| 1138 | .strings = strings, | 1098 | .strings = strings, |
| 1139 | }; | 1099 | }; |
| ... | @@ -1206,12 +1166,12 @@ fn mapWholeFile(path: []const u8) ![]const u8 { | ... | @@ -1206,12 +1166,12 @@ fn mapWholeFile(path: []const u8) ![]const u8 { |
| 1206 | | 1166 | |
| 1207 | pub const DebugInfo = struct { | 1167 | pub const DebugInfo = struct { |
| 1208 | allocator: *mem.Allocator, | 1168 | allocator: *mem.Allocator, |
| 1209 | address_map: std.AutoHashMap(usize, *ObjectDebugInfo), | 1169 | address_map: std.AutoHashMap(usize, *ModuleDebugInfo), |
| 1210 | | 1170 | |
| 1211 | pub fn init(allocator: *mem.Allocator) DebugInfo { | 1171 | pub fn init(allocator: *mem.Allocator) DebugInfo { |
| 1212 | return DebugInfo{ | 1172 | return DebugInfo{ |
| 1213 | .allocator = allocator, | 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,17 +1180,16 @@ pub const DebugInfo = struct { |
| 1220 | self.address_map.deinit(); | 1180 | self.address_map.deinit(); |
| 1221 | } | 1181 | } |
| 1222 | | 1182 | |
| 1223 | pub fn lookupByAddress(self: *DebugInfo, address: usize) !*ObjectDebugInfo { | 1183 | pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo { |
| 1224 | const obj_di = if (comptime std.Target.current.isDarwin()) | 1184 | if (comptime std.Target.current.isDarwin()) |
| 1225 | try self.lookupModuleDyld(address) | 1185 | return self.lookupModuleDyld(address) |
| 1226 | else if (builtin.os == .windows) | 1186 | else if (builtin.os == .windows) |
| 1227 | try self.lookupModuleWin32(address) | 1187 | return self.lookupModuleWin32(address) |
| 1228 | else | 1188 | else |
| 1229 | try self.lookupModuleDl(address); | 1189 | return self.lookupModuleDl(address); |
| 1230 | return obj_di; | | |
| 1231 | } | 1190 | } |
| 1232 | | 1191 | |
| 1233 | fn lookupModuleDyld(self: *DebugInfo, address: usize) !*ObjectDebugInfo { | 1192 | fn lookupModuleDyld(self: *DebugInfo, address: usize) !*ModuleDebugInfo { |
| 1234 | const image_count = std.c._dyld_image_count(); | 1193 | const image_count = std.c._dyld_image_count(); |
| 1235 | | 1194 | |
| 1236 | var i: u32 = 0; | 1195 | var i: u32 = 0; |
| ... | @@ -1266,7 +1225,7 @@ pub const DebugInfo = struct { | ... | @@ -1266,7 +1225,7 @@ pub const DebugInfo = struct { |
| 1266 | return obj_di; | 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 | errdefer self.allocator.destroy(obj_di); | 1229 | errdefer self.allocator.destroy(obj_di); |
| 1271 | | 1230 | |
| 1272 | try self.address_map.putNoClobber(base_address, obj_di); | 1231 | try self.address_map.putNoClobber(base_address, obj_di); |
| ... | @@ -1283,7 +1242,7 @@ pub const DebugInfo = struct { | ... | @@ -1283,7 +1242,7 @@ pub const DebugInfo = struct { |
| 1283 | return error.MissingDebugInfo; | 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 | const process_handle = windows.kernel32.GetCurrentProcess(); | 1246 | const process_handle = windows.kernel32.GetCurrentProcess(); |
| 1288 | | 1247 | |
| 1289 | // Find how many modules are actually loaded | 1248 | // Find how many modules are actually loaded |
| ... | @@ -1345,7 +1304,7 @@ pub const DebugInfo = struct { | ... | @@ -1345,7 +1304,7 @@ pub const DebugInfo = struct { |
| 1345 | ); | 1304 | ); |
| 1346 | assert(len > 0); | 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 | errdefer self.allocator.destroy(obj_di); | 1308 | errdefer self.allocator.destroy(obj_di); |
| 1350 | | 1309 | |
| 1351 | try self.address_map.putNoClobber(seg_start, obj_di); | 1310 | try self.address_map.putNoClobber(seg_start, obj_di); |
| ... | @@ -1360,7 +1319,7 @@ pub const DebugInfo = struct { | ... | @@ -1360,7 +1319,7 @@ pub const DebugInfo = struct { |
| 1360 | return error.MissingDebugInfo; | 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 | var ctx: struct { | 1323 | var ctx: struct { |
| 1365 | // Input | 1324 | // Input |
| 1366 | address: usize, | 1325 | address: usize, |
| ... | @@ -1414,7 +1373,7 @@ pub const DebugInfo = struct { | ... | @@ -1414,7 +1373,7 @@ pub const DebugInfo = struct { |
| 1414 | break :blk try fs.selfExePath(&buf); | 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 | errdefer self.allocator.destroy(obj_di); | 1377 | errdefer self.allocator.destroy(obj_di); |
| 1419 | | 1378 | |
| 1420 | try self.address_map.putNoClobber(ctx.base_address, obj_di); | 1379 | try self.address_map.putNoClobber(ctx.base_address, obj_di); |
| ... | @@ -1427,29 +1386,173 @@ pub const DebugInfo = struct { | ... | @@ -1427,29 +1386,173 @@ pub const DebugInfo = struct { |
| 1427 | }; | 1386 | }; |
| 1428 | | 1387 | |
| 1429 | const SymbolInfo = struct { | 1388 | const SymbolInfo = struct { |
| 1430 | symbol_name: []const u8, | 1389 | symbol_name: []const u8 = "???", |
| 1431 | compile_unit_name: []const u8, | 1390 | compile_unit_name: []const u8 = "???", |
| 1432 | line_info: ?LineInfo, | 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 | .macosx, .ios, .watchos, .tvos => struct { | 1401 | .macosx, .ios, .watchos, .tvos => struct { |
| 1437 | base_address: usize, | 1402 | base_address: usize, |
| 1438 | mapped_memory: []const u8, | 1403 | mapped_memory: []const u8, |
| 1439 | symbols: []const MachoSymbol, | 1404 | symbols: []const MachoSymbol, |
| 1440 | strings: []const u8, | 1405 | strings: [:0]const u8, |
| 1441 | ofiles: OFileTable, | 1406 | ofiles: OFileTable, |
| 1442 | | 1407 | |
| 1443 | const OFileTable = std.HashMap( | 1408 | const OFileTable = std.StringHashMap(DW.DwarfInfo); |
| 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 | ); | | |
| 1449 | | 1409 | |
| 1450 | pub fn allocator(self: @This()) *mem.Allocator { | 1410 | pub fn allocator(self: @This()) *mem.Allocator { |
| 1451 | return self.ofiles.allocator; | 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 | .uefi, .windows => struct { | 1557 | .uefi, .windows => struct { |
| 1455 | base_address: usize, | 1558 | base_address: usize, |
| ... | @@ -1481,11 +1584,7 @@ pub const ObjectDebugInfo = switch (builtin.os) { | ... | @@ -1481,11 +1584,7 @@ pub const ObjectDebugInfo = switch (builtin.os) { |
| 1481 | }; | 1584 | }; |
| 1482 | } else |err| switch (err) { | 1585 | } else |err| switch (err) { |
| 1483 | error.MissingDebugInfo, error.InvalidDebugInfo => { | 1586 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 1484 | return SymbolInfo{ | 1587 | return SymbolInfo{}; |
| 1485 | .symbol_name = "???", | | |
| 1486 | .compile_unit_name = "???", | | |
| 1487 | .line_info = null, | | |
| 1488 | }; | | |
| 1489 | }, | 1588 | }, |
| 1490 | else => return err, | 1589 | else => return err, |
| 1491 | } | 1590 | } |
| ... | @@ -1496,115 +1595,6 @@ pub const ObjectDebugInfo = switch (builtin.os) { | ... | @@ -1496,115 +1595,6 @@ pub const ObjectDebugInfo = switch (builtin.os) { |
| 1496 | else => DW.DwarfInfo, | 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 | /// TODO multithreaded awareness | 1598 | /// TODO multithreaded awareness |
| 1609 | var debug_info_allocator: ?*mem.Allocator = null; | 1599 | var debug_info_allocator: ?*mem.Allocator = null; |
| 1610 | var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined; | 1600 | var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined; |