| ... | @@ -700,7 +700,8 @@ fn printSourceAtAddressMacOs(di1: *DebugInfo, out_stream: var, address: usize, t | ... | @@ -700,7 +700,8 @@ fn printSourceAtAddressMacOs(di1: *DebugInfo, out_stream: var, address: usize, t |
| 700 | const di = try di1.lookupByAddress(address); | 700 | const di = try di1.lookupByAddress(address); |
| 701 | | 701 | |
| 702 | const base_addr = di.base_address; | 702 | const base_addr = di.base_address; |
| 703 | const adjusted_addr = 0x100000000 + (address - base_addr); | 703 | const adjusted_addr = address - base_addr; |
| | 704 | assert(adjusted_addr >= 0x100000000); |
| 704 | | 705 | |
| 705 | const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse { | 706 | const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse { |
| 706 | return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs); | 707 | return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs); |
| ... | @@ -734,7 +735,6 @@ pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, addres | ... | @@ -734,7 +735,6 @@ pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, addres |
| 734 | const module = try debug_info.lookupByAddress(address); | 735 | const module = try debug_info.lookupByAddress(address); |
| 735 | | 736 | |
| 736 | const reloc_address = address - module.base_address; | 737 | const reloc_address = address - module.base_address; |
| 737 | warn("reloc {x} => {x}\n", .{ address, reloc_address }); | | |
| 738 | | 738 | |
| 739 | if (module.dwarf.findCompileUnit(reloc_address) catch null) |compile_unit| { | 739 | if (module.dwarf.findCompileUnit(reloc_address) catch null) |compile_unit| { |
| 740 | const compile_unit_name = try compile_unit.die.getAttrString(&module.dwarf, DW.AT_name); | 740 | const compile_unit_name = try compile_unit.die.getAttrString(&module.dwarf, DW.AT_name); |
| ... | @@ -1078,29 +1078,33 @@ fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DW.DwarfInfo { | ... | @@ -1078,29 +1078,33 @@ fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DW.DwarfInfo { |
| 1078 | } | 1078 | } |
| 1079 | | 1079 | |
| 1080 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 1080 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 1081 | fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { | 1081 | fn openMachODebugInfo(allocator: *mem.Allocator, memmo: []const u8) !ObjectDebugInfo { |
| 1082 | const hdr = &std.c._mh_execute_header; | 1082 | // const hdr = &std.c._mh_execute_header; |
| | 1083 | const hdr = @ptrCast( |
| | 1084 | *const macho.mach_header_64, |
| | 1085 | @alignCast(@alignOf(macho.mach_header_64), memmo.ptr), |
| | 1086 | ); |
| 1083 | assert(hdr.magic == std.macho.MH_MAGIC_64); | 1087 | assert(hdr.magic == std.macho.MH_MAGIC_64); |
| 1084 | | 1088 | |
| 1085 | const hdr_base = @ptrCast([*]u8, hdr); | 1089 | const hdr_base = @ptrCast([*]const u8, hdr); |
| 1086 | var ptr = hdr_base + @sizeOf(macho.mach_header_64); | 1090 | var ptr = hdr_base + @sizeOf(macho.mach_header_64); |
| 1087 | var ncmd: u32 = hdr.ncmds; | 1091 | var ncmd: u32 = hdr.ncmds; |
| 1088 | const symtab = while (ncmd != 0) : (ncmd -= 1) { | 1092 | const symtab = while (ncmd != 0) : (ncmd -= 1) { |
| 1089 | const lc = @ptrCast(*std.macho.load_command, ptr); | 1093 | const lc = @ptrCast(*const std.macho.load_command, ptr); |
| 1090 | switch (lc.cmd) { | 1094 | switch (lc.cmd) { |
| 1091 | std.macho.LC_SYMTAB => break @ptrCast(*std.macho.symtab_command, ptr), | 1095 | std.macho.LC_SYMTAB => break @ptrCast(*const std.macho.symtab_command, ptr), |
| 1092 | else => {}, | 1096 | else => {}, |
| 1093 | } | 1097 | } |
| 1094 | ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize); | 1098 | ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize); |
| 1095 | } else { | 1099 | } else { |
| 1096 | return error.MissingDebugInfo; | 1100 | return error.MissingDebugInfo; |
| 1097 | }; | 1101 | }; |
| 1098 | const syms = @ptrCast([*]macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms]; | 1102 | const syms = @ptrCast([*]const macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms]; |
| 1099 | const strings = @ptrCast([*]u8, hdr_base + symtab.stroff)[0..symtab.strsize]; | 1103 | const strings = @ptrCast([*]const u8, hdr_base + symtab.stroff)[0..symtab.strsize]; |
| 1100 | | 1104 | |
| 1101 | const symbols_buf = try allocator.alloc(MachoSymbol, syms.len); | 1105 | const symbols_buf = try allocator.alloc(MachoSymbol, syms.len); |
| 1102 | | 1106 | |
| 1103 | var ofile: ?*macho.nlist_64 = null; | 1107 | var ofile: ?*const macho.nlist_64 = null; |
| 1104 | var reloc: u64 = 0; | 1108 | var reloc: u64 = 0; |
| 1105 | var symbol_index: usize = 0; | 1109 | var symbol_index: usize = 0; |
| 1106 | var last_len: u64 = 0; | 1110 | var last_len: u64 = 0; |
| ... | @@ -1148,8 +1152,10 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { | ... | @@ -1148,8 +1152,10 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { |
| 1148 | // This sort is so that we can binary search later. | 1152 | // This sort is so that we can binary search later. |
| 1149 | std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan); | 1153 | std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan); |
| 1150 | | 1154 | |
| 1151 | return DebugInfo{ | 1155 | return ObjectDebugInfo{ |
| 1152 | .ofiles = DebugInfo.OFileTable.init(allocator), | 1156 | .base_address = undefined, |
| | 1157 | .mapped_memory = undefined, |
| | 1158 | .ofiles = ObjectDebugInfo.OFileTable.init(allocator), |
| 1153 | .symbols = symbols, | 1159 | .symbols = symbols, |
| 1154 | .strings = strings, | 1160 | .strings = strings, |
| 1155 | }; | 1161 | }; |
| ... | @@ -1188,8 +1194,8 @@ fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void { | ... | @@ -1188,8 +1194,8 @@ fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void { |
| 1188 | } | 1194 | } |
| 1189 | | 1195 | |
| 1190 | const MachoSymbol = struct { | 1196 | const MachoSymbol = struct { |
| 1191 | nlist: *macho.nlist_64, | 1197 | nlist: *const macho.nlist_64, |
| 1192 | ofile: ?*macho.nlist_64, | 1198 | ofile: ?*const macho.nlist_64, |
| 1193 | reloc: u64, | 1199 | reloc: u64, |
| 1194 | | 1200 | |
| 1195 | /// Returns the address from the macho file | 1201 | /// Returns the address from the macho file |
| ... | @@ -1233,18 +1239,68 @@ pub const DebugInfo = struct { | ... | @@ -1233,18 +1239,68 @@ pub const DebugInfo = struct { |
| 1233 | | 1239 | |
| 1234 | var i: u32 = 0; | 1240 | var i: u32 = 0; |
| 1235 | while (i < image_count) : (i += 1) { | 1241 | while (i < image_count) : (i += 1) { |
| | 1242 | const base_address = std.c._dyld_get_image_vmaddr_slide(i); |
| | 1243 | |
| | 1244 | if (address < base_address) continue; |
| | 1245 | |
| 1236 | const header = std.c._dyld_get_image_header(i) orelse continue; | 1246 | const header = std.c._dyld_get_image_header(i) orelse continue; |
| 1237 | // The array of load commands is right after the header | 1247 | // The array of load commands is right after the header |
| 1238 | var cmd_ptr = @intToPtr([*]u8, @ptrToInt(header) + @sizeOf(macho.mach_header_64)); | 1248 | var cmd_ptr = @intToPtr([*]u8, @ptrToInt(header) + @sizeOf(macho.mach_header_64)); |
| 1239 | const cmd_ptr_end = cmd_ptr + header.sizeofcmds; | | |
| 1240 | | 1249 | |
| 1241 | var cmd = | 1250 | var cmds = header.ncmds; |
| 1242 | for (cmds) |*lc| { | 1251 | while (cmds != 0) : (cmds -= 1) { |
| | 1252 | const lc = @ptrCast( |
| | 1253 | *macho.load_command, |
| | 1254 | @alignCast(@alignOf(macho.load_command), cmd_ptr), |
| | 1255 | ); |
| | 1256 | cmd_ptr += lc.cmdsize; |
| 1243 | if (lc.cmd != macho.LC_SEGMENT_64) continue; | 1257 | if (lc.cmd != macho.LC_SEGMENT_64) continue; |
| 1244 | | 1258 | |
| 1245 | const segment_cmd = @ptrCast(*macho.segment_command_64, lc); | 1259 | const segment_cmd = @ptrCast( |
| | 1260 | *const std.macho.segment_command_64, |
| | 1261 | @alignCast(@alignOf(std.macho.segment_command_64), lc), |
| | 1262 | ); |
| | 1263 | |
| | 1264 | const rebased_address = address - base_address; |
| | 1265 | const seg_start = segment_cmd.vmaddr; |
| | 1266 | const seg_end = seg_start + segment_cmd.vmsize; |
| | 1267 | |
| | 1268 | if (rebased_address >= seg_start and rebased_address < seg_end) { |
| | 1269 | if (self.address_map.getValue(base_address)) |obj_di| { |
| | 1270 | return obj_di; |
| | 1271 | } |
| | 1272 | |
| | 1273 | const image_name = std.c._dyld_get_image_name(i); |
| | 1274 | const exe_file = try fs.openFileAbsoluteC(image_name, .{}); |
| | 1275 | errdefer exe_file.close(); |
| | 1276 | |
| | 1277 | const exe_len = math.cast(usize, try exe_file.getEndPos()) catch |
| | 1278 | return error.DebugInfoTooLarge; |
| | 1279 | const exe_mmap = try os.mmap( |
| | 1280 | null, |
| | 1281 | exe_len, |
| | 1282 | os.PROT_READ, |
| | 1283 | os.MAP_SHARED, |
| | 1284 | exe_file.handle, |
| | 1285 | 0, |
| | 1286 | ); |
| | 1287 | errdefer os.munmap(exe_mmap); |
| | 1288 | |
| | 1289 | const obj_di = try self.allocator.create(ObjectDebugInfo); |
| | 1290 | errdefer self.allocator.destroy(obj_di); |
| | 1291 | |
| | 1292 | try self.address_map.putNoClobber(base_address, obj_di); |
| | 1293 | |
| | 1294 | obj_di.* = try openMachODebugInfo(self.allocator, exe_mmap); |
| | 1295 | obj_di.base_address = base_address; |
| | 1296 | obj_di.mapped_memory = exe_mmap; |
| | 1297 | |
| | 1298 | return obj_di; |
| | 1299 | } |
| 1246 | } | 1300 | } |
| 1247 | } | 1301 | } |
| | 1302 | |
| | 1303 | return error.DebugInfoNotFound; |
| 1248 | } | 1304 | } |
| 1249 | | 1305 | |
| 1250 | fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ObjectDebugInfo { | 1306 | fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ObjectDebugInfo { |
| ... | @@ -1252,7 +1308,8 @@ pub const DebugInfo = struct { | ... | @@ -1252,7 +1308,8 @@ pub const DebugInfo = struct { |
| 1252 | | 1308 | |
| 1253 | var modules: [32]windows.HMODULE = undefined; | 1309 | var modules: [32]windows.HMODULE = undefined; |
| 1254 | var modules_needed: windows.DWORD = undefined; | 1310 | var modules_needed: windows.DWORD = undefined; |
| 1255 | // XXX Ask for the number of modules by passing size zero | 1311 | // TODO: Ask for the number of modules by passing size zero, 32 ought to |
| | 1312 | // be enough for everyone in the meanwhile |
| 1256 | if (windows.kernel32.K32EnumProcessModules( | 1313 | if (windows.kernel32.K32EnumProcessModules( |
| 1257 | process_handle, | 1314 | process_handle, |
| 1258 | @ptrCast([*]windows.HMODULE, &modules), | 1315 | @ptrCast([*]windows.HMODULE, &modules), |
| ... | @@ -1275,6 +1332,10 @@ pub const DebugInfo = struct { | ... | @@ -1275,6 +1332,10 @@ pub const DebugInfo = struct { |
| 1275 | const seg_end = seg_start + info.SizeOfImage; | 1332 | const seg_end = seg_start + info.SizeOfImage; |
| 1276 | | 1333 | |
| 1277 | if (address >= seg_start and address < seg_end) { | 1334 | if (address >= seg_start and address < seg_end) { |
| | 1335 | if (self.address_map.getValue(seg_start)) |obj_di| { |
| | 1336 | return obj_di; |
| | 1337 | } |
| | 1338 | |
| 1278 | var name_buffer: [windows.PATH_MAX_WIDE + 4:0]u16 = undefined; | 1339 | var name_buffer: [windows.PATH_MAX_WIDE + 4:0]u16 = undefined; |
| 1279 | // openFileAbsoluteW requires the prefix to be present | 1340 | // openFileAbsoluteW requires the prefix to be present |
| 1280 | mem.copy(u16, name_buffer[0..4], &[_]u16{ '\\', '?', '?', '\\' }); | 1341 | mem.copy(u16, name_buffer[0..4], &[_]u16{ '\\', '?', '?', '\\' }); |
| ... | @@ -1286,12 +1347,8 @@ pub const DebugInfo = struct { | ... | @@ -1286,12 +1347,8 @@ pub const DebugInfo = struct { |
| 1286 | ); | 1347 | ); |
| 1287 | assert(len > 0); | 1348 | assert(len > 0); |
| 1288 | | 1349 | |
| 1289 | if (self.address_map.getValue(seg_start)) |obj_di| { | 1350 | // The compiler segfaults if the slicing is done as a parameter |
| 1290 | return obj_di; | 1351 | // (#4423) |
| 1291 | } | | |
| 1292 | | | |
| 1293 | // XXX: The compiler segfaults if the slicing is done as a | | |
| 1294 | // parameter (#4423) | | |
| 1295 | const tmp = name_buffer[0..:0]; | 1352 | const tmp = name_buffer[0..:0]; |
| 1296 | const file_obj = try fs.openFileAbsoluteW(tmp, .{}); | 1353 | const file_obj = try fs.openFileAbsoluteW(tmp, .{}); |
| 1297 | errdefer file_obj.close(); | 1354 | errdefer file_obj.close(); |
| ... | @@ -1312,11 +1369,49 @@ pub const DebugInfo = struct { | ... | @@ -1312,11 +1369,49 @@ pub const DebugInfo = struct { |
| 1312 | } | 1369 | } |
| 1313 | | 1370 | |
| 1314 | fn lookupModuleDl(self: *DebugInfo, address: usize) !*ObjectDebugInfo { | 1371 | fn lookupModuleDl(self: *DebugInfo, address: usize) !*ObjectDebugInfo { |
| 1315 | var ctx = DIPContext{ .address = address }; | 1372 | var ctx: struct { |
| | 1373 | // Input |
| | 1374 | address: usize, |
| | 1375 | // Output |
| | 1376 | base_address: usize = undefined, |
| | 1377 | name: []const u8 = undefined, |
| | 1378 | } = .{ .address = address }; |
| | 1379 | const CtxTy = @TypeOf(ctx); |
| | 1380 | |
| | 1381 | if (os.dl_iterate_phdr(&ctx, anyerror, struct { |
| | 1382 | fn callback(info: *os.dl_phdr_info, size: usize, context: *CtxTy) !void { |
| | 1383 | // The base address is too high |
| | 1384 | if (context.address < info.dlpi_addr) |
| | 1385 | return; |
| 1316 | | 1386 | |
| 1317 | // XXX Locking? | 1387 | const phdrs = info.dlpi_phdr[0..info.dlpi_phnum]; |
| 1318 | if (os.dl_iterate_phdr(DIPContext, dl_iterate_phdr_callback, &ctx) == 0) | 1388 | for (phdrs) |*phdr| { |
| | 1389 | if (phdr.p_type != elf.PT_LOAD) continue; |
| | 1390 | |
| | 1391 | const seg_start = info.dlpi_addr + phdr.p_vaddr; |
| | 1392 | const seg_end = seg_start + phdr.p_memsz; |
| | 1393 | |
| | 1394 | if (context.address >= seg_start and context.address < seg_end) { |
| | 1395 | // Android libc uses NULL instead of an empty string to mark the |
| | 1396 | // main program |
| | 1397 | context.name = if (info.dlpi_name) |dlpi_name| |
| | 1398 | mem.toSliceConst(u8, dlpi_name) |
| | 1399 | else |
| | 1400 | ""; |
| | 1401 | context.base_address = info.dlpi_addr; |
| | 1402 | // Stop the iteration |
| | 1403 | return error.Found; |
| | 1404 | } |
| | 1405 | } |
| | 1406 | } |
| | 1407 | }.callback)) { |
| 1319 | return error.DebugInfoNotFound; | 1408 | return error.DebugInfoNotFound; |
| | 1409 | } else |err| { |
| | 1410 | switch (err) { |
| | 1411 | error.Found => {}, |
| | 1412 | else => return error.DebugInfoNotFound, |
| | 1413 | } |
| | 1414 | } |
| 1320 | | 1415 | |
| 1321 | if (self.address_map.getValue(ctx.base_address)) |obj_di| { | 1416 | if (self.address_map.getValue(ctx.base_address)) |obj_di| { |
| 1322 | return obj_di; | 1417 | return obj_di; |
| ... | @@ -1355,58 +1450,24 @@ pub const DebugInfo = struct { | ... | @@ -1355,58 +1450,24 @@ pub const DebugInfo = struct { |
| 1355 | } | 1450 | } |
| 1356 | }; | 1451 | }; |
| 1357 | | 1452 | |
| 1358 | const DIPContext = struct { | 1453 | const DIPContext = struct {}; |
| 1359 | address: usize, | | |
| 1360 | base_address: usize = undefined, | | |
| 1361 | name: []const u8 = undefined, | | |
| 1362 | }; | | |
| 1363 | | | |
| 1364 | fn dl_iterate_phdr_callback(info: *os.dl_phdr_info, size: usize, context: ?*DIPContext) callconv(.C) i32 { | | |
| 1365 | const address = context.?.address; | | |
| 1366 | | | |
| 1367 | // The base address is too high | | |
| 1368 | if (address < info.dlpi_addr) | | |
| 1369 | return 0; | | |
| 1370 | | | |
| 1371 | const phdrs = info.dlpi_phdr[0..info.dlpi_phnum]; | | |
| 1372 | for (phdrs) |*phdr| { | | |
| 1373 | if (phdr.p_type != elf.PT_LOAD) continue; | | |
| 1374 | | | |
| 1375 | const seg_start = info.dlpi_addr + phdr.p_vaddr; | | |
| 1376 | const seg_end = seg_start + phdr.p_memsz; | | |
| 1377 | | | |
| 1378 | if (address >= seg_start and address < seg_end) { | | |
| 1379 | // Android libc uses NULL instead of an empty string to mark the | | |
| 1380 | // main program | | |
| 1381 | context.?.name = if (info.dlpi_name) |dlpi_name| | | |
| 1382 | mem.toSliceConst(u8, dlpi_name) | | |
| 1383 | else | | |
| 1384 | ""; | | |
| 1385 | context.?.base_address = info.dlpi_addr; | | |
| 1386 | // Stop the iteration | | |
| 1387 | return 1; | | |
| 1388 | } | | |
| 1389 | } | | |
| 1390 | | | |
| 1391 | // Continue the iteration | | |
| 1392 | return 0; | | |
| 1393 | } | | |
| 1394 | | 1454 | |
| 1395 | pub const ObjectDebugInfo = switch (builtin.os) { | 1455 | pub const ObjectDebugInfo = switch (builtin.os) { |
| 1396 | .macosx, .ios, .watchos, .tvos => struct { | 1456 | .macosx, .ios, .watchos, .tvos => struct { |
| 1397 | base_address: usize, | 1457 | base_address: usize, |
| | 1458 | mapped_memory: []u8, |
| 1398 | symbols: []const MachoSymbol, | 1459 | symbols: []const MachoSymbol, |
| 1399 | strings: []const u8, | 1460 | strings: []const u8, |
| 1400 | ofiles: OFileTable, | 1461 | ofiles: OFileTable, |
| 1401 | | 1462 | |
| 1402 | const OFileTable = std.HashMap( | 1463 | const OFileTable = std.HashMap( |
| 1403 | *macho.nlist_64, | 1464 | *const macho.nlist_64, |
| 1404 | DW.DwarfInfo, | 1465 | DW.DwarfInfo, |
| 1405 | std.hash_map.getHashPtrAddrFn(*macho.nlist_64), | 1466 | std.hash_map.getHashPtrAddrFn(*const macho.nlist_64), |
| 1406 | std.hash_map.getTrivialEqlFn(*macho.nlist_64), | 1467 | std.hash_map.getTrivialEqlFn(*const macho.nlist_64), |
| 1407 | ); | 1468 | ); |
| 1408 | | 1469 | |
| 1409 | pub fn allocator(self: DebugInfo) *mem.Allocator { | 1470 | pub fn allocator(self: @This()) *mem.Allocator { |
| 1410 | return self.ofiles.allocator; | 1471 | return self.ofiles.allocator; |
| 1411 | } | 1472 | } |
| 1412 | }, | 1473 | }, |
| ... | @@ -1426,7 +1487,7 @@ pub const ObjectDebugInfo = switch (builtin.os) { | ... | @@ -1426,7 +1487,7 @@ pub const ObjectDebugInfo = switch (builtin.os) { |
| 1426 | }; | 1487 | }; |
| 1427 | | 1488 | |
| 1428 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 1489 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 1429 | fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !LineInfo { | 1490 | fn getLineNumberInfoMacOs(di: *ObjectDebugInfo, symbol: MachoSymbol, address: usize) !LineInfo { |
| 1430 | const ofile = symbol.ofile orelse return error.MissingDebugInfo; | 1491 | const ofile = symbol.ofile orelse return error.MissingDebugInfo; |
| 1431 | const gop = try di.ofiles.getOrPut(ofile); | 1492 | const gop = try di.ofiles.getOrPut(ofile); |
| 1432 | const dwarf_info = if (gop.found_existing) &gop.kv.value else blk: { | 1493 | const dwarf_info = if (gop.found_existing) &gop.kv.value else blk: { |