| ... | @@ -726,32 +726,38 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt | ... | @@ -726,32 +726,38 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt |
| 726 | } | 726 | } |
| 727 | | 727 | |
| 728 | pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void { | 728 | pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void { |
| 729 | const compile_unit = debug_info.findCompileUnit(address) catch { | 729 | // XXX Print as much as possible anyway |
| | 730 | const module = try debug_info.lookupByAddress(address); |
| | 731 | |
| | 732 | const reloc_address = address - module.base_address; |
| | 733 | warn("reloc {x} => {x}\n", .{ address, reloc_address }); |
| | 734 | |
| | 735 | if (module.dwarf.findCompileUnit(reloc_address) catch null) |compile_unit| { |
| | 736 | const compile_unit_name = try compile_unit.die.getAttrString(&module.dwarf, DW.AT_name); |
| | 737 | const symbol_name = module.dwarf.getSymbolName(reloc_address) orelse "???"; |
| | 738 | const line_info = module.dwarf.getLineNumberInfo(compile_unit.*, reloc_address) catch |err| switch (err) { |
| | 739 | error.MissingDebugInfo, error.InvalidDebugInfo => null, |
| | 740 | else => return err, |
| | 741 | }; |
| | 742 | defer if (line_info) |li| li.deinit(); |
| | 743 | |
| 730 | return printLineInfo( | 744 | return printLineInfo( |
| 731 | out_stream, | 745 | out_stream, |
| 732 | null, | 746 | line_info, |
| 733 | address, | 747 | address, |
| 734 | "???", | 748 | symbol_name, |
| 735 | "???", | 749 | compile_unit_name, |
| 736 | tty_config, | 750 | tty_config, |
| 737 | printLineFromFileAnyOs, | 751 | printLineFromFileAnyOs, |
| 738 | ); | 752 | ); |
| 739 | }; | 753 | } |
| 740 | | | |
| 741 | const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name); | | |
| 742 | const symbol_name = debug_info.getSymbolName(address) orelse "???"; | | |
| 743 | const line_info = debug_info.getLineNumberInfo(compile_unit.*, address) catch |err| switch (err) { | | |
| 744 | error.MissingDebugInfo, error.InvalidDebugInfo => null, | | |
| 745 | else => return err, | | |
| 746 | }; | | |
| 747 | defer if (line_info) |li| li.deinit(); | | |
| 748 | | 754 | |
| 749 | try printLineInfo( | 755 | return printLineInfo( |
| 750 | out_stream, | 756 | out_stream, |
| 751 | line_info, | 757 | null, |
| 752 | address, | 758 | address, |
| 753 | symbol_name, | 759 | "???", |
| 754 | compile_unit_name, | 760 | "???", |
| 755 | tty_config, | 761 | tty_config, |
| 756 | printLineFromFileAnyOs, | 762 | printLineFromFileAnyOs, |
| 757 | ); | 763 | ); |
| ... | @@ -824,6 +830,10 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { | ... | @@ -824,6 +830,10 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { |
| 824 | if (comptime std.Target.current.isDarwin()) { | 830 | if (comptime std.Target.current.isDarwin()) { |
| 825 | return noasync openSelfDebugInfoMacOs(allocator); | 831 | return noasync openSelfDebugInfoMacOs(allocator); |
| 826 | } | 832 | } |
| | 833 | if (builtin.os == .linux) { |
| | 834 | _ = try allocator.create(u32); |
| | 835 | return DebugInfo.init(allocator); |
| | 836 | } |
| 827 | return noasync openSelfDebugInfoPosix(allocator); | 837 | return noasync openSelfDebugInfoPosix(allocator); |
| 828 | } | 838 | } |
| 829 | | 839 | |
| ... | @@ -1190,7 +1200,113 @@ const MachoSymbol = struct { | ... | @@ -1190,7 +1200,113 @@ const MachoSymbol = struct { |
| 1190 | } | 1200 | } |
| 1191 | }; | 1201 | }; |
| 1192 | | 1202 | |
| 1193 | pub const DebugInfo = switch (builtin.os) { | 1203 | pub const DebugInfo = struct { |
| | 1204 | allocator: *mem.Allocator, |
| | 1205 | address_map: std.StringHashMap(*ObjectDebugInfo), |
| | 1206 | |
| | 1207 | pub fn init(allocator: *mem.Allocator) DebugInfo { |
| | 1208 | return DebugInfo{ |
| | 1209 | .allocator = allocator, |
| | 1210 | .address_map = std.StringHashMap(*ObjectDebugInfo).init(allocator), |
| | 1211 | }; |
| | 1212 | } |
| | 1213 | |
| | 1214 | pub fn deinit(self: *DebugInfo) void { |
| | 1215 | self.address_map.deinit(); |
| | 1216 | } |
| | 1217 | |
| | 1218 | pub fn lookupByAddress(self: *DebugInfo, address: usize) !*ObjectDebugInfo { |
| | 1219 | const obj_di = try self.lookupModuleDl(address); |
| | 1220 | return obj_di; |
| | 1221 | } |
| | 1222 | |
| | 1223 | fn lookupModuleDl(self: *DebugInfo, address: usize) !*ObjectDebugInfo { |
| | 1224 | var ctx = DIPContext{ .address = address }; |
| | 1225 | |
| | 1226 | warn("lookup {x}\n", .{address}); |
| | 1227 | |
| | 1228 | // XXX Locking? |
| | 1229 | if (os.dl_iterate_phdr(DIPContext, dl_iterate_phdr_callback, &ctx) == 0) |
| | 1230 | return error.DebugInfoNotFound; |
| | 1231 | |
| | 1232 | warn("found in \"{s}\"\n", .{ctx.name}); |
| | 1233 | |
| | 1234 | if (self.address_map.getValue(ctx.name)) |obj_di| { |
| | 1235 | warn("cache hit!\n", .{}); |
| | 1236 | return obj_di; |
| | 1237 | } |
| | 1238 | |
| | 1239 | const exe_file = if (ctx.name.len > 0) |
| | 1240 | try fs.openFileAbsolute(ctx.name, .{}) |
| | 1241 | else |
| | 1242 | try fs.openSelfExe(); |
| | 1243 | defer exe_file.close(); |
| | 1244 | |
| | 1245 | const exe_len = math.cast(usize, try exe_file.getEndPos()) catch |
| | 1246 | return error.DebugInfoTooLarge; |
| | 1247 | const exe_mmap = try os.mmap( |
| | 1248 | null, |
| | 1249 | exe_len, |
| | 1250 | os.PROT_READ, |
| | 1251 | os.MAP_SHARED, |
| | 1252 | exe_file.handle, |
| | 1253 | 0, |
| | 1254 | ); |
| | 1255 | errdefer os.munmap(exe_mmap); |
| | 1256 | |
| | 1257 | const obj_di = try self.allocator.create(ObjectDebugInfo); |
| | 1258 | errdefer self.allocator.destroy(obj_di); |
| | 1259 | |
| | 1260 | try self.address_map.putNoClobber(ctx.name, obj_di); |
| | 1261 | |
| | 1262 | obj_di.* = .{ |
| | 1263 | .dwarf = try openElfDebugInfo(self.allocator, exe_mmap), |
| | 1264 | .mapped_memory = exe_mmap, |
| | 1265 | .base_address = ctx.base_address, |
| | 1266 | }; |
| | 1267 | |
| | 1268 | return obj_di; |
| | 1269 | } |
| | 1270 | }; |
| | 1271 | |
| | 1272 | const DIPContext = struct { |
| | 1273 | address: usize, |
| | 1274 | base_address: usize = undefined, |
| | 1275 | name: []const u8 = undefined, |
| | 1276 | }; |
| | 1277 | |
| | 1278 | fn dl_iterate_phdr_callback(info: *os.dl_phdr_info, size: usize, context: ?*DIPContext) callconv(.C) i32 { |
| | 1279 | const address = context.?.address; |
| | 1280 | |
| | 1281 | // The base address is too high |
| | 1282 | if (address < info.dlpi_addr) |
| | 1283 | return 0; |
| | 1284 | |
| | 1285 | const phdrs = info.dlpi_phdr[0..info.dlpi_phnum]; |
| | 1286 | for (phdrs) |*phdr| { |
| | 1287 | if (phdr.p_type != elf.PT_LOAD) continue; |
| | 1288 | |
| | 1289 | const seg_start = info.dlpi_addr + phdr.p_vaddr; |
| | 1290 | const seg_end = seg_start + phdr.p_memsz; |
| | 1291 | |
| | 1292 | if (address > seg_start and address <= seg_end) { |
| | 1293 | // Android libc uses NULL instead of an empty string to mark the |
| | 1294 | // main program |
| | 1295 | context.?.name = if (info.dlpi_name) |dlpi_name| |
| | 1296 | mem.toSliceConst(u8, dlpi_name) |
| | 1297 | else |
| | 1298 | ""; |
| | 1299 | context.?.base_address = info.dlpi_addr; |
| | 1300 | // Stop the iteration |
| | 1301 | return 1; |
| | 1302 | } |
| | 1303 | } |
| | 1304 | |
| | 1305 | // Continue the iteration |
| | 1306 | return 0; |
| | 1307 | } |
| | 1308 | |
| | 1309 | pub const ObjectDebugInfo = switch (builtin.os) { |
| 1194 | .macosx, .ios, .watchos, .tvos => struct { | 1310 | .macosx, .ios, .watchos, .tvos => struct { |
| 1195 | symbols: []const MachoSymbol, | 1311 | symbols: []const MachoSymbol, |
| 1196 | strings: []const u8, | 1312 | strings: []const u8, |
| ... | @@ -1213,6 +1329,11 @@ pub const DebugInfo = switch (builtin.os) { | ... | @@ -1213,6 +1329,11 @@ pub const DebugInfo = switch (builtin.os) { |
| 1213 | sect_contribs: []pdb.SectionContribEntry, | 1329 | sect_contribs: []pdb.SectionContribEntry, |
| 1214 | modules: []Module, | 1330 | modules: []Module, |
| 1215 | }, | 1331 | }, |
| | 1332 | .linux => struct { |
| | 1333 | base_address: usize, |
| | 1334 | dwarf: DW.DwarfInfo, |
| | 1335 | mapped_memory: []u8, |
| | 1336 | }, |
| 1216 | else => DW.DwarfInfo, | 1337 | else => DW.DwarfInfo, |
| 1217 | }; | 1338 | }; |
| 1218 | | 1339 | |