authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-05 23:54:05+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-06 23:14:54-07:00
logae16c1d0835b517cb858cb9615888cdab1e351c5
tree96bf676789ca6e7006b77dbb56109137608980e0
parentb3d463c9e6ab41d55849e6cfbbc83d6a1f171ef9

std: use std.macho.LoadCommandIterator for MachO parsing in std.debug


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

lib/std/debug.zig+69-98
...@@ -968,24 +968,20 @@ fn readMachODebugInfo(allocator: mem.Allocator, macho_file: File) !ModuleDebugIn...@@ -968,24 +968,20 @@ fn readMachODebugInfo(allocator: mem.Allocator, macho_file: File) !ModuleDebugIn
968 if (hdr.magic != macho.MH_MAGIC_64)968 if (hdr.magic != macho.MH_MAGIC_64)
969 return error.InvalidDebugInfo;969 return error.InvalidDebugInfo;
970970
971 const hdr_base = @ptrCast([*]const u8, hdr);971 var it = macho.LoadCommandIterator{
972 var ptr = hdr_base + @sizeOf(macho.mach_header_64);972 .ncmds = hdr.ncmds,
973 var ncmd: u32 = hdr.ncmds;973 .buffer = mapped_mem[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
974 const symtab = while (ncmd != 0) : (ncmd -= 1) {
975 const lc = @ptrCast(*const std.macho.load_command, ptr);
976 switch (lc.cmd) {
977 .SYMTAB => break @ptrCast(*const std.macho.symtab_command, ptr),
978 else => {},
979 }
980 ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
981 } else {
982 return error.MissingDebugInfo;
983 };974 };
975 const symtab = while (it.next()) |cmd| switch (cmd.cmd()) {
976 .SYMTAB => break cmd.cast(macho.symtab_command).?,
977 else => {},
978 } else return error.MissingDebugInfo;
979
984 const syms = @ptrCast(980 const syms = @ptrCast(
985 [*]const macho.nlist_64,981 [*]const macho.nlist_64,
986 @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff),982 @alignCast(@alignOf(macho.nlist_64), &mapped_mem[symtab.symoff]),
987 )[0..symtab.nsyms];983 )[0..symtab.nsyms];
988 const strings = @ptrCast([*]const u8, hdr_base + symtab.stroff)[0 .. symtab.strsize - 1 :0];984 const strings = mapped_mem[symtab.stroff..][0 .. symtab.strsize - 1 :0];
989985
990 const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);986 const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);
991987
...@@ -1200,48 +1196,46 @@ pub const DebugInfo = struct {...@@ -1200,48 +1196,46 @@ pub const DebugInfo = struct {
1200 if (address < base_address) continue;1196 if (address < base_address) continue;
12011197
1202 const header = std.c._dyld_get_image_header(i) orelse continue;1198 const header = std.c._dyld_get_image_header(i) orelse continue;
1203 // The array of load commands is right after the header
1204 var cmd_ptr = @intToPtr([*]u8, @ptrToInt(header) + @sizeOf(macho.mach_header_64));
1205
1206 var cmds = header.ncmds;
1207 while (cmds != 0) : (cmds -= 1) {
1208 const lc = @ptrCast(
1209 *macho.load_command,
1210 @alignCast(@alignOf(macho.load_command), cmd_ptr),
1211 );
1212 cmd_ptr += lc.cmdsize;
1213 if (lc.cmd != .SEGMENT_64) continue;
12141199
1215 const segment_cmd = @ptrCast(1200 var it = macho.LoadCommandIterator{
1216 *const std.macho.segment_command_64,1201 .ncmds = header.ncmds,
1217 @alignCast(@alignOf(std.macho.segment_command_64), lc),1202 .buffer = @alignCast(@alignOf(u64), @intToPtr(
1218 );1203 [*]u8,
1204 @ptrToInt(header) + @sizeOf(macho.mach_header_64),
1205 ))[0..header.sizeofcmds],
1206 };
1207 while (it.next()) |cmd| switch (cmd.cmd()) {
1208 .SEGMENT_64 => {
1209 const segment_cmd = cmd.cast(macho.segment_command_64).?;
1210 const rebased_address = address - base_address;
1211 const seg_start = segment_cmd.vmaddr;
1212 const seg_end = seg_start + segment_cmd.vmsize;
1213
1214 if (rebased_address >= seg_start and rebased_address < seg_end) {
1215 if (self.address_map.get(base_address)) |obj_di| {
1216 return obj_di;
1217 }
1218
1219 const obj_di = try self.allocator.create(ModuleDebugInfo);
1220 errdefer self.allocator.destroy(obj_di);
1221
1222 const macho_path = mem.sliceTo(std.c._dyld_get_image_name(i), 0);
1223 const macho_file = fs.cwd().openFile(macho_path, .{
1224 .intended_io_mode = .blocking,
1225 }) catch |err| switch (err) {
1226 error.FileNotFound => return error.MissingDebugInfo,
1227 else => return err,
1228 };
1229 obj_di.* = try readMachODebugInfo(self.allocator, macho_file);
1230 obj_di.base_address = base_address;
12191231
1220 const rebased_address = address - base_address;1232 try self.address_map.putNoClobber(base_address, obj_di);
1221 const seg_start = segment_cmd.vmaddr;
1222 const seg_end = seg_start + segment_cmd.vmsize;
12231233
1224 if (rebased_address >= seg_start and rebased_address < seg_end) {
1225 if (self.address_map.get(base_address)) |obj_di| {
1226 return obj_di;1234 return obj_di;
1227 }1235 }
12281236 },
1229 const obj_di = try self.allocator.create(ModuleDebugInfo);1237 else => {},
1230 errdefer self.allocator.destroy(obj_di);1238 };
1231
1232 const macho_path = mem.sliceTo(std.c._dyld_get_image_name(i), 0);
1233 const macho_file = fs.cwd().openFile(macho_path, .{ .intended_io_mode = .blocking }) catch |err| switch (err) {
1234 error.FileNotFound => return error.MissingDebugInfo,
1235 else => return err,
1236 };
1237 obj_di.* = try readMachODebugInfo(self.allocator, macho_file);
1238 obj_di.base_address = base_address;
1239
1240 try self.address_map.putNoClobber(base_address, obj_di);
1241
1242 return obj_di;
1243 }
1244 }
1245 }1239 }
12461240
1247 return error.MissingDebugInfo;1241 return error.MissingDebugInfo;
...@@ -1445,44 +1439,31 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1445,44 +1439,31 @@ pub const ModuleDebugInfo = switch (native_os) {
1445 if (hdr.magic != std.macho.MH_MAGIC_64)1439 if (hdr.magic != std.macho.MH_MAGIC_64)
1446 return error.InvalidDebugInfo;1440 return error.InvalidDebugInfo;
14471441
1448 const hdr_base = @ptrCast([*]const u8, hdr);1442 var segcmd: ?macho.LoadCommandIterator.LoadCommand = null;
1449 var ptr = hdr_base + @sizeOf(macho.mach_header_64);1443 var symtabcmd: ?macho.symtab_command = null;
1450 var segptr = ptr;1444 var it = macho.LoadCommandIterator{
1451 var ncmd: u32 = hdr.ncmds;1445 .ncmds = hdr.ncmds,
1452 var segcmd: ?*const macho.segment_command_64 = null;1446 .buffer = mapped_mem[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
1453 var symtabcmd: ?*const macho.symtab_command = null;1447 };
14541448 while (it.next()) |cmd| switch (cmd.cmd()) {
1455 while (ncmd != 0) : (ncmd -= 1) {1449 .SEGMENT_64 => segcmd = cmd,
1456 const lc = @ptrCast(*const std.macho.load_command, ptr);1450 .SYMTAB => symtabcmd = cmd.cast(macho.symtab_command).?,
1457 switch (lc.cmd) {1451 else => {},
1458 .SEGMENT_64 => {1452 };
1459 segcmd = @ptrCast(
1460 *const std.macho.segment_command_64,
1461 @alignCast(@alignOf(std.macho.segment_command_64), ptr),
1462 );
1463 segptr = ptr;
1464 },
1465 .SYMTAB => {
1466 symtabcmd = @ptrCast(
1467 *const std.macho.symtab_command,
1468 @alignCast(@alignOf(std.macho.symtab_command), ptr),
1469 );
1470 },
1471 else => {},
1472 }
1473 ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
1474 }
14751453
1476 if (segcmd == null or symtabcmd == null) return error.MissingDebugInfo;1454 if (segcmd == null or symtabcmd == null) return error.MissingDebugInfo;
14771455
1478 // Parse symbols1456 // Parse symbols
1479 const strtab = @ptrCast(1457 const strtab = @ptrCast(
1480 [*]const u8,1458 [*]const u8,
1481 hdr_base + symtabcmd.?.stroff,1459 &mapped_mem[symtabcmd.?.stroff],
1482 )[0 .. symtabcmd.?.strsize - 1 :0];1460 )[0 .. symtabcmd.?.strsize - 1 :0];
1483 const symtab = @ptrCast(1461 const symtab = @ptrCast(
1484 [*]const macho.nlist_64,1462 [*]const macho.nlist_64,
1485 @alignCast(@alignOf(macho.nlist_64), hdr_base + symtabcmd.?.symoff),1463 @alignCast(
1464 @alignOf(macho.nlist_64),
1465 &mapped_mem[symtabcmd.?.symoff],
1466 ),
1486 )[0..symtabcmd.?.nsyms];1467 )[0..symtabcmd.?.nsyms];
14871468
1488 // TODO handle tentative (common) symbols1469 // TODO handle tentative (common) symbols
...@@ -1496,25 +1477,15 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1496,25 +1477,15 @@ pub const ModuleDebugInfo = switch (native_os) {
1496 addr_table.putAssumeCapacityNoClobber(sym_name, sym.n_value);1477 addr_table.putAssumeCapacityNoClobber(sym_name, sym.n_value);
1497 }1478 }
14981479
1499 var opt_debug_line: ?*const macho.section_64 = null;1480 var opt_debug_line: ?macho.section_64 = null;
1500 var opt_debug_info: ?*const macho.section_64 = null;1481 var opt_debug_info: ?macho.section_64 = null;
1501 var opt_debug_abbrev: ?*const macho.section_64 = null;1482 var opt_debug_abbrev: ?macho.section_64 = null;
1502 var opt_debug_str: ?*const macho.section_64 = null;1483 var opt_debug_str: ?macho.section_64 = null;
1503 var opt_debug_line_str: ?*const macho.section_64 = null;1484 var opt_debug_line_str: ?macho.section_64 = null;
1504 var opt_debug_ranges: ?*const macho.section_64 = null;1485 var opt_debug_ranges: ?macho.section_64 = null;
1505
1506 const sections = @ptrCast(
1507 [*]const macho.section_64,
1508 @alignCast(@alignOf(macho.section_64), segptr + @sizeOf(std.macho.segment_command_64)),
1509 )[0..segcmd.?.nsects];
1510 for (sections) |*sect| {
1511 // The section name may not exceed 16 chars and a trailing null may
1512 // not be present
1513 const name = if (mem.indexOfScalar(u8, sect.sectname[0..], 0)) |last|
1514 sect.sectname[0..last]
1515 else
1516 sect.sectname[0..];
15171486
1487 for (segcmd.?.getSections()) |sect| {
1488 const name = sect.sectName();
1518 if (mem.eql(u8, name, "__debug_line")) {1489 if (mem.eql(u8, name, "__debug_line")) {
1519 opt_debug_line = sect;1490 opt_debug_line = sect;
1520 } else if (mem.eql(u8, name, "__debug_info")) {1491 } else if (mem.eql(u8, name, "__debug_info")) {