authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-02-18 12:37:25+01:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-02-20 19:41:29+01:00
logb9c02e4076204c49500fd1d0dcb91420aed17f03
treea89d863b97585a14379e147b2586ee29a8fcc711
parent2a350cf1745f08c98c5897ce2d27627d28ea00da

elvis entered the building


1 files changed, 130 insertions(+), 69 deletions(-)

lib/std/debug.zig+130-69
......@@ -700,7 +700,8 @@ fn printSourceAtAddressMacOs(di1: *DebugInfo, out_stream: var, address: usize, t
700700 const di = try di1.lookupByAddress(address);
701701
702702 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);
704705
705706 const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {
706707 return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs);
......@@ -734,7 +735,6 @@ pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, addres
734735 const module = try debug_info.lookupByAddress(address);
735736
736737 const reloc_address = address - module.base_address;
737 warn("reloc {x} => {x}\n", .{ address, reloc_address });
738738
739739 if (module.dwarf.findCompileUnit(reloc_address) catch null) |compile_unit| {
740740 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 {
10781078}
10791079
10801080/// TODO resources https://github.com/ziglang/zig/issues/4353
1081fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
1082 const hdr = &std.c._mh_execute_header;
1081fn openMachODebugInfo(allocator: *mem.Allocator, memmo: []const u8) !ObjectDebugInfo {
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 );
10831087 assert(hdr.magic == std.macho.MH_MAGIC_64);
10841088
1085 const hdr_base = @ptrCast([*]u8, hdr);
1089 const hdr_base = @ptrCast([*]const u8, hdr);
10861090 var ptr = hdr_base + @sizeOf(macho.mach_header_64);
10871091 var ncmd: u32 = hdr.ncmds;
10881092 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);
10901094 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),
10921096 else => {},
10931097 }
10941098 ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
10951099 } else {
10961100 return error.MissingDebugInfo;
10971101 };
1098 const syms = @ptrCast([*]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];
1102 const syms = @ptrCast([*]const macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms];
1103 const strings = @ptrCast([*]const u8, hdr_base + symtab.stroff)[0..symtab.strsize];
11001104
11011105 const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);
11021106
1103 var ofile: ?*macho.nlist_64 = null;
1107 var ofile: ?*const macho.nlist_64 = null;
11041108 var reloc: u64 = 0;
11051109 var symbol_index: usize = 0;
11061110 var last_len: u64 = 0;
......@@ -1148,8 +1152,10 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
11481152 // This sort is so that we can binary search later.
11491153 std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan);
11501154
1151 return DebugInfo{
1152 .ofiles = DebugInfo.OFileTable.init(allocator),
1155 return ObjectDebugInfo{
1156 .base_address = undefined,
1157 .mapped_memory = undefined,
1158 .ofiles = ObjectDebugInfo.OFileTable.init(allocator),
11531159 .symbols = symbols,
11541160 .strings = strings,
11551161 };
......@@ -1188,8 +1194,8 @@ fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
11881194}
11891195
11901196const MachoSymbol = struct {
1191 nlist: *macho.nlist_64,
1192 ofile: ?*macho.nlist_64,
1197 nlist: *const macho.nlist_64,
1198 ofile: ?*const macho.nlist_64,
11931199 reloc: u64,
11941200
11951201 /// Returns the address from the macho file
......@@ -1233,18 +1239,68 @@ pub const DebugInfo = struct {
12331239
12341240 var i: u32 = 0;
12351241 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
12361246 const header = std.c._dyld_get_image_header(i) orelse continue;
12371247 // The array of load commands is right after the header
12381248 var cmd_ptr = @intToPtr([*]u8, @ptrToInt(header) + @sizeOf(macho.mach_header_64));
1239 const cmd_ptr_end = cmd_ptr + header.sizeofcmds;
12401249
1241 var cmd =
1242 for (cmds) |*lc| {
1250 var cmds = header.ncmds;
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;
12431257 if (lc.cmd != macho.LC_SEGMENT_64) continue;
12441258
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 }
12461300 }
12471301 }
1302
1303 return error.DebugInfoNotFound;
12481304 }
12491305
12501306 fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ObjectDebugInfo {
......@@ -1252,7 +1308,8 @@ pub const DebugInfo = struct {
12521308
12531309 var modules: [32]windows.HMODULE = undefined;
12541310 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
12561313 if (windows.kernel32.K32EnumProcessModules(
12571314 process_handle,
12581315 @ptrCast([*]windows.HMODULE, &modules),
......@@ -1275,6 +1332,10 @@ pub const DebugInfo = struct {
12751332 const seg_end = seg_start + info.SizeOfImage;
12761333
12771334 if (address >= seg_start and address < seg_end) {
1335 if (self.address_map.getValue(seg_start)) |obj_di| {
1336 return obj_di;
1337 }
1338
12781339 var name_buffer: [windows.PATH_MAX_WIDE + 4:0]u16 = undefined;
12791340 // openFileAbsoluteW requires the prefix to be present
12801341 mem.copy(u16, name_buffer[0..4], &[_]u16{ '\\', '?', '?', '\\' });
......@@ -1286,12 +1347,8 @@ pub const DebugInfo = struct {
12861347 );
12871348 assert(len > 0);
12881349
1289 if (self.address_map.getValue(seg_start)) |obj_di| {
1290 return obj_di;
1291 }
1292
1293 // XXX: The compiler segfaults if the slicing is done as a
1294 // parameter (#4423)
1350 // The compiler segfaults if the slicing is done as a parameter
1351 // (#4423)
12951352 const tmp = name_buffer[0..:0];
12961353 const file_obj = try fs.openFileAbsoluteW(tmp, .{});
12971354 errdefer file_obj.close();
......@@ -1312,11 +1369,49 @@ pub const DebugInfo = struct {
13121369 }
13131370
13141371 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;
13161386
1317 // XXX Locking?
1318 if (os.dl_iterate_phdr(DIPContext, dl_iterate_phdr_callback, &ctx) == 0)
1387 const phdrs = info.dlpi_phdr[0..info.dlpi_phnum];
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)) {
13191408 return error.DebugInfoNotFound;
1409 } else |err| {
1410 switch (err) {
1411 error.Found => {},
1412 else => return error.DebugInfoNotFound,
1413 }
1414 }
13201415
13211416 if (self.address_map.getValue(ctx.base_address)) |obj_di| {
13221417 return obj_di;
......@@ -1355,58 +1450,24 @@ pub const DebugInfo = struct {
13551450 }
13561451};
13571452
1358const DIPContext = struct {
1359 address: usize,
1360 base_address: usize = undefined,
1361 name: []const u8 = undefined,
1362};
1363
1364fn 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}
1453const DIPContext = struct {};
13941454
13951455pub const ObjectDebugInfo = switch (builtin.os) {
13961456 .macosx, .ios, .watchos, .tvos => struct {
13971457 base_address: usize,
1458 mapped_memory: []u8,
13981459 symbols: []const MachoSymbol,
13991460 strings: []const u8,
14001461 ofiles: OFileTable,
14011462
14021463 const OFileTable = std.HashMap(
1403 *macho.nlist_64,
1464 *const macho.nlist_64,
14041465 DW.DwarfInfo,
1405 std.hash_map.getHashPtrAddrFn(*macho.nlist_64),
1406 std.hash_map.getTrivialEqlFn(*macho.nlist_64),
1466 std.hash_map.getHashPtrAddrFn(*const macho.nlist_64),
1467 std.hash_map.getTrivialEqlFn(*const macho.nlist_64),
14071468 );
14081469
1409 pub fn allocator(self: DebugInfo) *mem.Allocator {
1470 pub fn allocator(self: @This()) *mem.Allocator {
14101471 return self.ofiles.allocator;
14111472 }
14121473 },
......@@ -1426,7 +1487,7 @@ pub const ObjectDebugInfo = switch (builtin.os) {
14261487};
14271488
14281489/// TODO resources https://github.com/ziglang/zig/issues/4353
1429fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !LineInfo {
1490fn getLineNumberInfoMacOs(di: *ObjectDebugInfo, symbol: MachoSymbol, address: usize) !LineInfo {
14301491 const ofile = symbol.ofile orelse return error.MissingDebugInfo;
14311492 const gop = try di.ofiles.getOrPut(ofile);
14321493 const dwarf_info = if (gop.found_existing) &gop.kv.value else blk: {