| author | |
| committer | |
| log | 0da8ba816a14aeb43c0c98adc13943336f9525fa |
| tree | af203e98ffaa2874b973f7645003cb0935e6a593 |
| parent | 41b91442f4af293d4cbbabbe9e451bd31c5c5679 |
3 files changed, 214 insertions(+), 285 deletions(-)
src/link/MachO.zig+206-60| ... | @@ -4,6 +4,7 @@ const std = @import("std"); | ... | @@ -4,6 +4,7 @@ const std = @import("std"); |
| 4 | const build_options = @import("build_options"); | 4 | const build_options = @import("build_options"); |
| 5 | const builtin = @import("builtin"); | 5 | const builtin = @import("builtin"); |
| 6 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 7 | const dwarf = std.dwarf; | ||
| 7 | const fmt = std.fmt; | 8 | const fmt = std.fmt; |
| 8 | const fs = std.fs; | 9 | const fs = std.fs; |
| 9 | const log = std.log.scoped(.link); | 10 | const log = std.log.scoped(.link); |
| ... | @@ -187,7 +188,6 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, | ... | @@ -187,7 +188,6 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 187 | load_commands_dirty: bool = false, | 188 | load_commands_dirty: bool = false, |
| 188 | sections_order_dirty: bool = false, | 189 | sections_order_dirty: bool = false, |
| 189 | has_dices: bool = false, | 190 | has_dices: bool = false, |
| 190 | has_stabs: bool = false, | ||
| 191 | 191 | ||
| 192 | /// A helper var to indicate if we are at the start of the incremental updates, or | 192 | /// A helper var to indicate if we are at the start of the incremental updates, or |
| 193 | /// already somewhere further along the update-and-run chain. | 193 | /// already somewhere further along the update-and-run chain. |
| ... | @@ -725,6 +725,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) | ... | @@ -725,6 +725,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) |
| 725 | man.hash.add(self.base.options.headerpad_max_install_names); | 725 | man.hash.add(self.base.options.headerpad_max_install_names); |
| 726 | man.hash.add(dead_strip); | 726 | man.hash.add(dead_strip); |
| 727 | man.hash.add(self.base.options.dead_strip_dylibs); | 727 | man.hash.add(self.base.options.dead_strip_dylibs); |
| 728 | man.hash.add(self.base.options.strip); | ||
| 728 | man.hash.addListOfBytes(self.base.options.lib_dirs); | 729 | man.hash.addListOfBytes(self.base.options.lib_dirs); |
| 729 | man.hash.addListOfBytes(self.base.options.framework_dirs); | 730 | man.hash.addListOfBytes(self.base.options.framework_dirs); |
| 730 | link.hashAddSystemLibs(&man.hash, self.base.options.frameworks); | 731 | link.hashAddSystemLibs(&man.hash, self.base.options.frameworks); |
| ... | @@ -1388,9 +1389,15 @@ fn parseObject(self: *MachO, path: []const u8) !bool { | ... | @@ -1388,9 +1389,15 @@ fn parseObject(self: *MachO, path: []const u8) !bool { |
| 1388 | const name = try self.base.allocator.dupe(u8, path); | 1389 | const name = try self.base.allocator.dupe(u8, path); |
| 1389 | errdefer self.base.allocator.free(name); | 1390 | errdefer self.base.allocator.free(name); |
| 1390 | 1391 | ||
| 1392 | const mtime: u64 = mtime: { | ||
| 1393 | const stat = file.stat() catch break :mtime 0; | ||
| 1394 | break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000)); | ||
| 1395 | }; | ||
| 1396 | |||
| 1391 | var object = Object{ | 1397 | var object = Object{ |
| 1392 | .name = name, | 1398 | .name = name, |
| 1393 | .file = file, | 1399 | .file = file, |
| 1400 | .mtime = mtime, | ||
| 1394 | }; | 1401 | }; |
| 1395 | 1402 | ||
| 1396 | object.parse(self.base.allocator, self.base.options.target) catch |err| switch (err) { | 1403 | object.parse(self.base.allocator, self.base.options.target) catch |err| switch (err) { |
| ... | @@ -2910,7 +2917,6 @@ fn createTentativeDefAtoms(self: *MachO) !void { | ... | @@ -2910,7 +2917,6 @@ fn createTentativeDefAtoms(self: *MachO) !void { |
| 2910 | try atom.contained.append(gpa, .{ | 2917 | try atom.contained.append(gpa, .{ |
| 2911 | .sym_index = global.sym_index, | 2918 | .sym_index = global.sym_index, |
| 2912 | .offset = 0, | 2919 | .offset = 0, |
| 2913 | .stab = if (object.debug_info) |_| .static else null, | ||
| 2914 | }); | 2920 | }); |
| 2915 | 2921 | ||
| 2916 | try object.managed_atoms.append(gpa, atom); | 2922 | try object.managed_atoms.append(gpa, atom); |
| ... | @@ -6188,64 +6194,6 @@ fn writeSymtab(self: *MachO) !void { | ... | @@ -6188,64 +6194,6 @@ fn writeSymtab(self: *MachO) !void { |
| 6188 | } | 6194 | } |
| 6189 | 6195 | ||
| 6190 | for (self.objects.items) |object, object_id| { | 6196 | for (self.objects.items) |object, object_id| { |
| 6191 | if (self.has_stabs) { | ||
| 6192 | if (object.debug_info) |_| { | ||
| 6193 | // Open scope | ||
| 6194 | try locals.ensureUnusedCapacity(3); | ||
| 6195 | locals.appendAssumeCapacity(.{ | ||
| 6196 | .n_strx = try self.strtab.insert(gpa, object.tu_comp_dir.?), | ||
| 6197 | .n_type = macho.N_SO, | ||
| 6198 | .n_sect = 0, | ||
| 6199 | .n_desc = 0, | ||
| 6200 | .n_value = 0, | ||
| 6201 | }); | ||
| 6202 | locals.appendAssumeCapacity(.{ | ||
| 6203 | .n_strx = try self.strtab.insert(gpa, object.tu_name.?), | ||
| 6204 | .n_type = macho.N_SO, | ||
| 6205 | .n_sect = 0, | ||
| 6206 | .n_desc = 0, | ||
| 6207 | .n_value = 0, | ||
| 6208 | }); | ||
| 6209 | locals.appendAssumeCapacity(.{ | ||
| 6210 | .n_strx = try self.strtab.insert(gpa, object.name), | ||
| 6211 | .n_type = macho.N_OSO, | ||
| 6212 | .n_sect = 0, | ||
| 6213 | .n_desc = 1, | ||
| 6214 | .n_value = object.mtime orelse 0, | ||
| 6215 | }); | ||
| 6216 | |||
| 6217 | for (object.managed_atoms.items) |atom| { | ||
| 6218 | for (atom.contained.items) |sym_at_off| { | ||
| 6219 | const stab = sym_at_off.stab orelse continue; | ||
| 6220 | const sym_loc = SymbolWithLoc{ | ||
| 6221 | .sym_index = sym_at_off.sym_index, | ||
| 6222 | .file = atom.file, | ||
| 6223 | }; | ||
| 6224 | const sym = self.getSymbol(sym_loc); | ||
| 6225 | if (sym.n_strx == 0) continue; | ||
| 6226 | if (sym.n_desc == N_DESC_GCED) continue; | ||
| 6227 | if (self.symbolIsTemp(sym_loc)) continue; | ||
| 6228 | |||
| 6229 | const nlists = try stab.asNlists(.{ | ||
| 6230 | .sym_index = sym_at_off.sym_index, | ||
| 6231 | .file = atom.file, | ||
| 6232 | }, self); | ||
| 6233 | defer gpa.free(nlists); | ||
| 6234 | |||
| 6235 | try locals.appendSlice(nlists); | ||
| 6236 | } | ||
| 6237 | } | ||
| 6238 | |||
| 6239 | // Close scope | ||
| 6240 | try locals.append(.{ | ||
| 6241 | .n_strx = 0, | ||
| 6242 | .n_type = macho.N_SO, | ||
| 6243 | .n_sect = 0, | ||
| 6244 | .n_desc = 0, | ||
| 6245 | .n_value = 0, | ||
| 6246 | }); | ||
| 6247 | } | ||
| 6248 | } | ||
| 6249 | for (object.symtab.items) |sym, sym_id| { | 6197 | for (object.symtab.items) |sym, sym_id| { |
| 6250 | if (sym.n_strx == 0) continue; // no name, skip | 6198 | if (sym.n_strx == 0) continue; // no name, skip |
| 6251 | if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip | 6199 | if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip |
| ... | @@ -6256,6 +6204,10 @@ fn writeSymtab(self: *MachO) !void { | ... | @@ -6256,6 +6204,10 @@ fn writeSymtab(self: *MachO) !void { |
| 6256 | out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(sym_loc)); | 6204 | out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(sym_loc)); |
| 6257 | try locals.append(out_sym); | 6205 | try locals.append(out_sym); |
| 6258 | } | 6206 | } |
| 6207 | |||
| 6208 | if (!self.base.options.strip) { | ||
| 6209 | try self.generateSymbolStabs(object, &locals); | ||
| 6210 | } | ||
| 6259 | } | 6211 | } |
| 6260 | 6212 | ||
| 6261 | var exports = std.ArrayList(macho.nlist_64).init(gpa); | 6213 | var exports = std.ArrayList(macho.nlist_64).init(gpa); |
| ... | @@ -6663,6 +6615,200 @@ pub fn findFirst(comptime T: type, haystack: []const T, start: usize, predicate: | ... | @@ -6663,6 +6615,200 @@ pub fn findFirst(comptime T: type, haystack: []const T, start: usize, predicate: |
| 6663 | return i; | 6615 | return i; |
| 6664 | } | 6616 | } |
| 6665 | 6617 | ||
| 6618 | const DebugInfo = struct { | ||
| 6619 | inner: dwarf.DwarfInfo, | ||
| 6620 | debug_info: []const u8, | ||
| 6621 | debug_abbrev: []const u8, | ||
| 6622 | debug_str: []const u8, | ||
| 6623 | debug_line: []const u8, | ||
| 6624 | debug_line_str: []const u8, | ||
| 6625 | debug_ranges: []const u8, | ||
| 6626 | |||
| 6627 | pub fn parse(allocator: Allocator, object: Object) !?DebugInfo { | ||
| 6628 | var debug_info = blk: { | ||
| 6629 | const index = object.dwarf_debug_info_index orelse return null; | ||
| 6630 | break :blk try object.getSectionContents(index); | ||
| 6631 | }; | ||
| 6632 | var debug_abbrev = blk: { | ||
| 6633 | const index = object.dwarf_debug_abbrev_index orelse return null; | ||
| 6634 | break :blk try object.getSectionContents(index); | ||
| 6635 | }; | ||
| 6636 | var debug_str = blk: { | ||
| 6637 | const index = object.dwarf_debug_str_index orelse return null; | ||
| 6638 | break :blk try object.getSectionContents(index); | ||
| 6639 | }; | ||
| 6640 | var debug_line = blk: { | ||
| 6641 | const index = object.dwarf_debug_line_index orelse return null; | ||
| 6642 | break :blk try object.getSectionContents(index); | ||
| 6643 | }; | ||
| 6644 | var debug_line_str = blk: { | ||
| 6645 | if (object.dwarf_debug_line_str_index) |ind| { | ||
| 6646 | break :blk try object.getSectionContents(ind); | ||
| 6647 | } | ||
| 6648 | break :blk &[0]u8{}; | ||
| 6649 | }; | ||
| 6650 | var debug_ranges = blk: { | ||
| 6651 | if (object.dwarf_debug_ranges_index) |ind| { | ||
| 6652 | break :blk try object.getSectionContents(ind); | ||
| 6653 | } | ||
| 6654 | break :blk &[0]u8{}; | ||
| 6655 | }; | ||
| 6656 | |||
| 6657 | var inner: dwarf.DwarfInfo = .{ | ||
| 6658 | .endian = .Little, | ||
| 6659 | .debug_info = debug_info, | ||
| 6660 | .debug_abbrev = debug_abbrev, | ||
| 6661 | .debug_str = debug_str, | ||
| 6662 | .debug_line = debug_line, | ||
| 6663 | .debug_line_str = debug_line_str, | ||
| 6664 | .debug_ranges = debug_ranges, | ||
| 6665 | }; | ||
| 6666 | try dwarf.openDwarfDebugInfo(&inner, allocator); | ||
| 6667 | |||
| 6668 | return DebugInfo{ | ||
| 6669 | .inner = inner, | ||
| 6670 | .debug_info = debug_info, | ||
| 6671 | .debug_abbrev = debug_abbrev, | ||
| 6672 | .debug_str = debug_str, | ||
| 6673 | .debug_line = debug_line, | ||
| 6674 | .debug_line_str = debug_line_str, | ||
| 6675 | .debug_ranges = debug_ranges, | ||
| 6676 | }; | ||
| 6677 | } | ||
| 6678 | |||
| 6679 | pub fn deinit(self: *DebugInfo, allocator: Allocator) void { | ||
| 6680 | self.inner.deinit(allocator); | ||
| 6681 | } | ||
| 6682 | }; | ||
| 6683 | |||
| 6684 | pub fn generateSymbolStabs( | ||
| 6685 | self: *MachO, | ||
| 6686 | object: Object, | ||
| 6687 | locals: *std.ArrayList(macho.nlist_64), | ||
| 6688 | ) !void { | ||
| 6689 | assert(!self.base.options.strip); | ||
| 6690 | |||
| 6691 | const gpa = self.base.allocator; | ||
| 6692 | |||
| 6693 | log.debug("parsing debug info in '{s}'", .{object.name}); | ||
| 6694 | |||
| 6695 | var debug_info = (try DebugInfo.parse(gpa, object)) orelse return; | ||
| 6696 | |||
| 6697 | // We assume there is only one CU. | ||
| 6698 | const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) { | ||
| 6699 | error.MissingDebugInfo => { | ||
| 6700 | // TODO audit cases with missing debug info and audit our dwarf.zig module. | ||
| 6701 | log.debug("invalid or missing debug info in {s}; skipping", .{object.name}); | ||
| 6702 | return; | ||
| 6703 | }, | ||
| 6704 | else => |e| return e, | ||
| 6705 | }; | ||
| 6706 | const tu_name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.name); | ||
| 6707 | const tu_comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.comp_dir); | ||
| 6708 | const source_symtab = object.getSourceSymtab(); | ||
| 6709 | |||
| 6710 | // Open scope | ||
| 6711 | try locals.ensureUnusedCapacity(3); | ||
| 6712 | locals.appendAssumeCapacity(.{ | ||
| 6713 | .n_strx = try self.strtab.insert(gpa, tu_comp_dir), | ||
| 6714 | .n_type = macho.N_SO, | ||
| 6715 | .n_sect = 0, | ||
| 6716 | .n_desc = 0, | ||
| 6717 | .n_value = 0, | ||
| 6718 | }); | ||
| 6719 | locals.appendAssumeCapacity(.{ | ||
| 6720 | .n_strx = try self.strtab.insert(gpa, tu_name), | ||
| 6721 | .n_type = macho.N_SO, | ||
| 6722 | .n_sect = 0, | ||
| 6723 | .n_desc = 0, | ||
| 6724 | .n_value = 0, | ||
| 6725 | }); | ||
| 6726 | locals.appendAssumeCapacity(.{ | ||
| 6727 | .n_strx = try self.strtab.insert(gpa, object.name), | ||
| 6728 | .n_type = macho.N_OSO, | ||
| 6729 | .n_sect = 0, | ||
| 6730 | .n_desc = 1, | ||
| 6731 | .n_value = object.mtime, | ||
| 6732 | }); | ||
| 6733 | |||
| 6734 | for (object.managed_atoms.items) |atom| { | ||
| 6735 | for (atom.contained.items) |sym_at_off| { | ||
| 6736 | const sym_loc = SymbolWithLoc{ | ||
| 6737 | .sym_index = sym_at_off.sym_index, | ||
| 6738 | .file = atom.file, | ||
| 6739 | }; | ||
| 6740 | const sym = self.getSymbol(sym_loc); | ||
| 6741 | const sym_name = self.getSymbolName(sym_loc); | ||
| 6742 | if (sym.n_strx == 0) continue; | ||
| 6743 | if (sym.n_desc == N_DESC_GCED) continue; | ||
| 6744 | if (self.symbolIsTemp(sym_loc)) continue; | ||
| 6745 | if (sym_at_off.sym_index >= source_symtab.len) continue; // synthetic, linker generated | ||
| 6746 | |||
| 6747 | const source_sym = source_symtab[sym_at_off.sym_index]; | ||
| 6748 | const size: ?u64 = size: { | ||
| 6749 | if (source_sym.tentative()) break :size null; | ||
| 6750 | for (debug_info.inner.func_list.items) |func| { | ||
| 6751 | if (func.pc_range) |range| { | ||
| 6752 | if (source_sym.n_value >= range.start and source_sym.n_value < range.end) { | ||
| 6753 | break :size range.end - range.start; | ||
| 6754 | } | ||
| 6755 | } | ||
| 6756 | } | ||
| 6757 | break :size null; | ||
| 6758 | }; | ||
| 6759 | |||
| 6760 | if (size) |ss| { | ||
| 6761 | try locals.ensureUnusedCapacity(4); | ||
| 6762 | locals.appendAssumeCapacity(.{ | ||
| 6763 | .n_strx = 0, | ||
| 6764 | .n_type = macho.N_BNSYM, | ||
| 6765 | .n_sect = sym.n_sect, | ||
| 6766 | .n_desc = 0, | ||
| 6767 | .n_value = sym.n_value, | ||
| 6768 | }); | ||
| 6769 | locals.appendAssumeCapacity(.{ | ||
| 6770 | .n_strx = try self.strtab.insert(gpa, sym_name), | ||
| 6771 | .n_type = macho.N_FUN, | ||
| 6772 | .n_sect = sym.n_sect, | ||
| 6773 | .n_desc = 0, | ||
| 6774 | .n_value = sym.n_value, | ||
| 6775 | }); | ||
| 6776 | locals.appendAssumeCapacity(.{ | ||
| 6777 | .n_strx = 0, | ||
| 6778 | .n_type = macho.N_FUN, | ||
| 6779 | .n_sect = 0, | ||
| 6780 | .n_desc = 0, | ||
| 6781 | .n_value = ss, | ||
| 6782 | }); | ||
| 6783 | locals.appendAssumeCapacity(.{ | ||
| 6784 | .n_strx = 0, | ||
| 6785 | .n_type = macho.N_ENSYM, | ||
| 6786 | .n_sect = sym.n_sect, | ||
| 6787 | .n_desc = 0, | ||
| 6788 | .n_value = ss, | ||
| 6789 | }); | ||
| 6790 | } else { | ||
| 6791 | try locals.append(.{ | ||
| 6792 | .n_strx = try self.strtab.insert(gpa, sym_name), | ||
| 6793 | .n_type = macho.N_STSYM, | ||
| 6794 | .n_sect = sym.n_sect, | ||
| 6795 | .n_desc = 0, | ||
| 6796 | .n_value = sym.n_value, | ||
| 6797 | }); | ||
| 6798 | } | ||
| 6799 | } | ||
| 6800 | } | ||
| 6801 | |||
| 6802 | // Close scope | ||
| 6803 | try locals.append(.{ | ||
| 6804 | .n_strx = 0, | ||
| 6805 | .n_type = macho.N_SO, | ||
| 6806 | .n_sect = 0, | ||
| 6807 | .n_desc = 0, | ||
| 6808 | .n_value = 0, | ||
| 6809 | }); | ||
| 6810 | } | ||
| 6811 | |||
| 6666 | fn snapshotState(self: *MachO) !void { | 6812 | fn snapshotState(self: *MachO) !void { |
| 6667 | const emit = self.base.options.emit orelse { | 6813 | const emit = self.base.options.emit orelse { |
| 6668 | log.debug("no emit directory found; skipping snapshot...", .{}); | 6814 | log.debug("no emit directory found; skipping snapshot...", .{}); |
src/link/MachO/Atom.zig-70| ... | @@ -78,76 +78,6 @@ pub const Binding = struct { | ... | @@ -78,76 +78,6 @@ pub const Binding = struct { |
| 78 | pub const SymbolAtOffset = struct { | 78 | pub const SymbolAtOffset = struct { |
| 79 | sym_index: u32, | 79 | sym_index: u32, |
| 80 | offset: u64, | 80 | offset: u64, |
| 81 | stab: ?Stab = null, | ||
| 82 | }; | ||
| 83 | |||
| 84 | pub const Stab = union(enum) { | ||
| 85 | function: u64, | ||
| 86 | static, | ||
| 87 | global, | ||
| 88 | |||
| 89 | pub fn asNlists(stab: Stab, sym_loc: SymbolWithLoc, macho_file: *MachO) ![]macho.nlist_64 { | ||
| 90 | const gpa = macho_file.base.allocator; | ||
| 91 | |||
| 92 | var nlists = std.ArrayList(macho.nlist_64).init(gpa); | ||
| 93 | defer nlists.deinit(); | ||
| 94 | |||
| 95 | const sym = macho_file.getSymbol(sym_loc); | ||
| 96 | const sym_name = macho_file.getSymbolName(sym_loc); | ||
| 97 | switch (stab) { | ||
| 98 | .function => |size| { | ||
| 99 | try nlists.ensureUnusedCapacity(4); | ||
| 100 | nlists.appendAssumeCapacity(.{ | ||
| 101 | .n_strx = 0, | ||
| 102 | .n_type = macho.N_BNSYM, | ||
| 103 | .n_sect = sym.n_sect, | ||
| 104 | .n_desc = 0, | ||
| 105 | .n_value = sym.n_value, | ||
| 106 | }); | ||
| 107 | nlists.appendAssumeCapacity(.{ | ||
| 108 | .n_strx = try macho_file.strtab.insert(gpa, sym_name), | ||
| 109 | .n_type = macho.N_FUN, | ||
| 110 | .n_sect = sym.n_sect, | ||
| 111 | .n_desc = 0, | ||
| 112 | .n_value = sym.n_value, | ||
| 113 | }); | ||
| 114 | nlists.appendAssumeCapacity(.{ | ||
| 115 | .n_strx = 0, | ||
| 116 | .n_type = macho.N_FUN, | ||
| 117 | .n_sect = 0, | ||
| 118 | .n_desc = 0, | ||
| 119 | .n_value = size, | ||
| 120 | }); | ||
| 121 | nlists.appendAssumeCapacity(.{ | ||
| 122 | .n_strx = 0, | ||
| 123 | .n_type = macho.N_ENSYM, | ||
| 124 | .n_sect = sym.n_sect, | ||
| 125 | .n_desc = 0, | ||
| 126 | .n_value = size, | ||
| 127 | }); | ||
| 128 | }, | ||
| 129 | .global => { | ||
| 130 | try nlists.append(.{ | ||
| 131 | .n_strx = try macho_file.strtab.insert(gpa, sym_name), | ||
| 132 | .n_type = macho.N_GSYM, | ||
| 133 | .n_sect = 0, | ||
| 134 | .n_desc = 0, | ||
| 135 | .n_value = 0, | ||
| 136 | }); | ||
| 137 | }, | ||
| 138 | .static => { | ||
| 139 | try nlists.append(.{ | ||
| 140 | .n_strx = try macho_file.strtab.insert(gpa, sym_name), | ||
| 141 | .n_type = macho.N_STSYM, | ||
| 142 | .n_sect = sym.n_sect, | ||
| 143 | .n_desc = 0, | ||
| 144 | .n_value = sym.n_value, | ||
| 145 | }); | ||
| 146 | }, | ||
| 147 | } | ||
| 148 | |||
| 149 | return nlists.toOwnedSlice(); | ||
| 150 | } | ||
| 151 | }; | 81 | }; |
| 152 | 82 | ||
| 153 | pub const Relocation = struct { | 83 | pub const Relocation = struct { |
src/link/MachO/Object.zig+8-155| ... | @@ -3,7 +3,6 @@ const Object = @This(); | ... | @@ -3,7 +3,6 @@ const Object = @This(); |
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const build_options = @import("build_options"); | 4 | const build_options = @import("build_options"); |
| 5 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| 6 | const dwarf = std.dwarf; | ||
| 7 | const fs = std.fs; | 6 | const fs = std.fs; |
| 8 | const io = std.io; | 7 | const io = std.io; |
| 9 | const log = std.log.scoped(.link); | 8 | const log = std.log.scoped(.link); |
| ... | @@ -17,9 +16,11 @@ const Allocator = mem.Allocator; | ... | @@ -17,9 +16,11 @@ const Allocator = mem.Allocator; |
| 17 | const Atom = @import("Atom.zig"); | 16 | const Atom = @import("Atom.zig"); |
| 18 | const MachO = @import("../MachO.zig"); | 17 | const MachO = @import("../MachO.zig"); |
| 19 | const MatchingSection = MachO.MatchingSection; | 18 | const MatchingSection = MachO.MatchingSection; |
| 19 | const SymbolWithLoc = MachO.SymbolWithLoc; | ||
| 20 | 20 | ||
| 21 | file: fs.File, | 21 | file: fs.File, |
| 22 | name: []const u8, | 22 | name: []const u8, |
| 23 | mtime: u64, | ||
| 23 | 24 | ||
| 24 | /// Data contents of the file. Includes sections, and data of load commands. | 25 | /// Data contents of the file. Includes sections, and data of load commands. |
| 25 | /// Excludes the backing memory for the header and load commands. | 26 | /// Excludes the backing memory for the header and load commands. |
| ... | @@ -51,12 +52,6 @@ symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | ... | @@ -51,12 +52,6 @@ symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 51 | strtab: []const u8 = &.{}, | 52 | strtab: []const u8 = &.{}, |
| 52 | data_in_code_entries: []const macho.data_in_code_entry = &.{}, | 53 | data_in_code_entries: []const macho.data_in_code_entry = &.{}, |
| 53 | 54 | ||
| 54 | // Debug info | ||
| 55 | debug_info: ?DebugInfo = null, | ||
| 56 | tu_name: ?[]const u8 = null, | ||
| 57 | tu_comp_dir: ?[]const u8 = null, | ||
| 58 | mtime: ?u64 = null, | ||
| 59 | |||
| 60 | sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{}, | 55 | sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{}, |
| 61 | 56 | ||
| 62 | /// List of atoms that map to the symbols parsed from this object file. | 57 | /// List of atoms that map to the symbols parsed from this object file. |
| ... | @@ -65,72 +60,6 @@ managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, | ... | @@ -65,72 +60,6 @@ managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, |
| 65 | /// Table of atoms belonging to this object file indexed by the symbol index. | 60 | /// Table of atoms belonging to this object file indexed by the symbol index. |
| 66 | atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{}, | 61 | atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{}, |
| 67 | 62 | ||
| 68 | const DebugInfo = struct { | ||
| 69 | inner: dwarf.DwarfInfo, | ||
| 70 | debug_info: []const u8, | ||
| 71 | debug_abbrev: []const u8, | ||
| 72 | debug_str: []const u8, | ||
| 73 | debug_line: []const u8, | ||
| 74 | debug_line_str: []const u8, | ||
| 75 | debug_ranges: []const u8, | ||
| 76 | |||
| 77 | pub fn parseFromObject(allocator: Allocator, object: *const Object) !?DebugInfo { | ||
| 78 | var debug_info = blk: { | ||
| 79 | const index = object.dwarf_debug_info_index orelse return null; | ||
| 80 | break :blk try object.getSectionContents(index); | ||
| 81 | }; | ||
| 82 | var debug_abbrev = blk: { | ||
| 83 | const index = object.dwarf_debug_abbrev_index orelse return null; | ||
| 84 | break :blk try object.getSectionContents(index); | ||
| 85 | }; | ||
| 86 | var debug_str = blk: { | ||
| 87 | const index = object.dwarf_debug_str_index orelse return null; | ||
| 88 | break :blk try object.getSectionContents(index); | ||
| 89 | }; | ||
| 90 | var debug_line = blk: { | ||
| 91 | const index = object.dwarf_debug_line_index orelse return null; | ||
| 92 | break :blk try object.getSectionContents(index); | ||
| 93 | }; | ||
| 94 | var debug_line_str = blk: { | ||
| 95 | if (object.dwarf_debug_line_str_index) |ind| { | ||
| 96 | break :blk try object.getSectionContents(ind); | ||
| 97 | } | ||
| 98 | break :blk &[0]u8{}; | ||
| 99 | }; | ||
| 100 | var debug_ranges = blk: { | ||
| 101 | if (object.dwarf_debug_ranges_index) |ind| { | ||
| 102 | break :blk try object.getSectionContents(ind); | ||
| 103 | } | ||
| 104 | break :blk &[0]u8{}; | ||
| 105 | }; | ||
| 106 | |||
| 107 | var inner: dwarf.DwarfInfo = .{ | ||
| 108 | .endian = .Little, | ||
| 109 | .debug_info = debug_info, | ||
| 110 | .debug_abbrev = debug_abbrev, | ||
| 111 | .debug_str = debug_str, | ||
| 112 | .debug_line = debug_line, | ||
| 113 | .debug_line_str = debug_line_str, | ||
| 114 | .debug_ranges = debug_ranges, | ||
| 115 | }; | ||
| 116 | try dwarf.openDwarfDebugInfo(&inner, allocator); | ||
| 117 | |||
| 118 | return DebugInfo{ | ||
| 119 | .inner = inner, | ||
| 120 | .debug_info = debug_info, | ||
| 121 | .debug_abbrev = debug_abbrev, | ||
| 122 | .debug_str = debug_str, | ||
| 123 | .debug_line = debug_line, | ||
| 124 | .debug_line_str = debug_line_str, | ||
| 125 | .debug_ranges = debug_ranges, | ||
| 126 | }; | ||
| 127 | } | ||
| 128 | |||
| 129 | pub fn deinit(self: *DebugInfo, allocator: Allocator) void { | ||
| 130 | self.inner.deinit(allocator); | ||
| 131 | } | ||
| 132 | }; | ||
| 133 | |||
| 134 | pub fn deinit(self: *Object, gpa: Allocator) void { | 63 | pub fn deinit(self: *Object, gpa: Allocator) void { |
| 135 | for (self.load_commands.items) |*lc| { | 64 | for (self.load_commands.items) |*lc| { |
| 136 | lc.deinit(gpa); | 65 | lc.deinit(gpa); |
| ... | @@ -147,10 +76,6 @@ pub fn deinit(self: *Object, gpa: Allocator) void { | ... | @@ -147,10 +76,6 @@ pub fn deinit(self: *Object, gpa: Allocator) void { |
| 147 | self.managed_atoms.deinit(gpa); | 76 | self.managed_atoms.deinit(gpa); |
| 148 | 77 | ||
| 149 | gpa.free(self.name); | 78 | gpa.free(self.name); |
| 150 | |||
| 151 | if (self.debug_info) |*db| { | ||
| 152 | db.deinit(gpa); | ||
| 153 | } | ||
| 154 | } | 79 | } |
| 155 | 80 | ||
| 156 | pub fn parse(self: *Object, allocator: Allocator, target: std.Target) !void { | 81 | pub fn parse(self: *Object, allocator: Allocator, target: std.Target) !void { |
| ... | @@ -253,7 +178,6 @@ pub fn parse(self: *Object, allocator: Allocator, target: std.Target) !void { | ... | @@ -253,7 +178,6 @@ pub fn parse(self: *Object, allocator: Allocator, target: std.Target) !void { |
| 253 | 178 | ||
| 254 | try self.parseSymtab(allocator); | 179 | try self.parseSymtab(allocator); |
| 255 | self.parseDataInCode(); | 180 | self.parseDataInCode(); |
| 256 | try self.parseDebugInfo(allocator); | ||
| 257 | } | 181 | } |
| 258 | 182 | ||
| 259 | const Context = struct { | 183 | const Context = struct { |
| ... | @@ -462,7 +386,6 @@ pub fn splitIntoAtomsOneShot( | ... | @@ -462,7 +386,6 @@ pub fn splitIntoAtomsOneShot( |
| 462 | } | 386 | } |
| 463 | break :blk false; | 387 | break :blk false; |
| 464 | }; | 388 | }; |
| 465 | macho_file.has_stabs = macho_file.has_stabs or self.debug_info != null; | ||
| 466 | 389 | ||
| 467 | if (subsections_via_symbols and filtered_syms.len > 0) { | 390 | if (subsections_via_symbols and filtered_syms.len > 0) { |
| 468 | // If the first nlist does not match the start of the section, | 391 | // If the first nlist does not match the start of the section, |
| ... | @@ -566,7 +489,6 @@ pub fn splitIntoAtomsOneShot( | ... | @@ -566,7 +489,6 @@ pub fn splitIntoAtomsOneShot( |
| 566 | try atom.contained.append(gpa, .{ | 489 | try atom.contained.append(gpa, .{ |
| 567 | .sym_index = alias, | 490 | .sym_index = alias, |
| 568 | .offset = 0, | 491 | .offset = 0, |
| 569 | .stab = null, | ||
| 570 | }); | 492 | }); |
| 571 | try self.atom_by_index_table.put(gpa, alias, atom); | 493 | try self.atom_by_index_table.put(gpa, alias, atom); |
| 572 | } | 494 | } |
| ... | @@ -671,54 +593,17 @@ fn createAtomFromSubsection( | ... | @@ -671,54 +593,17 @@ fn createAtomFromSubsection( |
| 671 | // we can properly allocate addresses down the line. | 593 | // we can properly allocate addresses down the line. |
| 672 | // While we're at it, we need to update segment,section mapping of each symbol too. | 594 | // While we're at it, we need to update segment,section mapping of each symbol too. |
| 673 | try atom.contained.ensureTotalCapacity(gpa, indexes.len + 1); | 595 | try atom.contained.ensureTotalCapacity(gpa, indexes.len + 1); |
| 674 | 596 | atom.contained.appendAssumeCapacity(.{ | |
| 675 | { | 597 | .sym_index = sym_index, |
| 676 | const stab: ?Atom.Stab = if (self.debug_info) |di| blk: { | 598 | .offset = 0, |
| 677 | // TODO there has to be a better to handle this. | 599 | }); |
| 678 | for (di.inner.func_list.items) |func| { | ||
| 679 | if (func.pc_range) |range| { | ||
| 680 | if (sym.n_value >= range.start and sym.n_value < range.end) { | ||
| 681 | break :blk Atom.Stab{ | ||
| 682 | .function = range.end - range.start, | ||
| 683 | }; | ||
| 684 | } | ||
| 685 | } | ||
| 686 | } | ||
| 687 | // TODO | ||
| 688 | // if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global; | ||
| 689 | break :blk .static; | ||
| 690 | } else null; | ||
| 691 | |||
| 692 | atom.contained.appendAssumeCapacity(.{ | ||
| 693 | .sym_index = sym_index, | ||
| 694 | .offset = 0, | ||
| 695 | .stab = stab, | ||
| 696 | }); | ||
| 697 | } | ||
| 698 | 600 | ||
| 699 | for (indexes) |inner_sym_index| { | 601 | for (indexes) |inner_sym_index| { |
| 700 | const inner_sym = &self.symtab.items[inner_sym_index.index]; | 602 | const inner_sym = &self.symtab.items[inner_sym_index.index]; |
| 701 | inner_sym.n_sect = macho_file.getSectionOrdinal(match); | 603 | inner_sym.n_sect = macho_file.getSectionOrdinal(match); |
| 702 | |||
| 703 | const stab: ?Atom.Stab = if (self.debug_info) |di| blk: { | ||
| 704 | // TODO there has to be a better to handle this. | ||
| 705 | for (di.inner.func_list.items) |func| { | ||
| 706 | if (func.pc_range) |range| { | ||
| 707 | if (inner_sym.n_value >= range.start and inner_sym.n_value < range.end) { | ||
| 708 | break :blk Atom.Stab{ | ||
| 709 | .function = range.end - range.start, | ||
| 710 | }; | ||
| 711 | } | ||
| 712 | } | ||
| 713 | } | ||
| 714 | // TODO | ||
| 715 | // if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global; | ||
| 716 | break :blk .static; | ||
| 717 | } else null; | ||
| 718 | atom.contained.appendAssumeCapacity(.{ | 604 | atom.contained.appendAssumeCapacity(.{ |
| 719 | .sym_index = inner_sym_index.index, | 605 | .sym_index = inner_sym_index.index, |
| 720 | .offset = inner_sym.n_value - sym.n_value, | 606 | .offset = inner_sym.n_value - sym.n_value, |
| 721 | .stab = stab, | ||
| 722 | }); | 607 | }); |
| 723 | 608 | ||
| 724 | try self.atom_by_index_table.putNoClobber(gpa, inner_sym_index.index, atom); | 609 | try self.atom_by_index_table.putNoClobber(gpa, inner_sym_index.index, atom); |
| ... | @@ -755,7 +640,7 @@ fn parseSymtab(self: *Object, allocator: Allocator) !void { | ... | @@ -755,7 +640,7 @@ fn parseSymtab(self: *Object, allocator: Allocator) !void { |
| 755 | self.strtab = self.contents[symtab.stroff..][0..symtab.strsize]; | 640 | self.strtab = self.contents[symtab.stroff..][0..symtab.strsize]; |
| 756 | } | 641 | } |
| 757 | 642 | ||
| 758 | fn getSourceSymtab(self: *Object) []const macho.nlist_64 { | 643 | pub fn getSourceSymtab(self: Object) []const macho.nlist_64 { |
| 759 | const index = self.symtab_cmd_index orelse return &[0]macho.nlist_64{}; | 644 | const index = self.symtab_cmd_index orelse return &[0]macho.nlist_64{}; |
| 760 | const symtab = self.load_commands.items[index].symtab; | 645 | const symtab = self.load_commands.items[index].symtab; |
| 761 | const symtab_size = @sizeOf(macho.nlist_64) * symtab.nsyms; | 646 | const symtab_size = @sizeOf(macho.nlist_64) * symtab.nsyms; |
| ... | @@ -766,38 +651,6 @@ fn getSourceSymtab(self: *Object) []const macho.nlist_64 { | ... | @@ -766,38 +651,6 @@ fn getSourceSymtab(self: *Object) []const macho.nlist_64 { |
| 766 | ); | 651 | ); |
| 767 | } | 652 | } |
| 768 | 653 | ||
| 769 | fn parseDebugInfo(self: *Object, allocator: Allocator) !void { | ||
| 770 | log.debug("parsing debug info in '{s}'", .{self.name}); | ||
| 771 | |||
| 772 | var debug_info = blk: { | ||
| 773 | var di = try DebugInfo.parseFromObject(allocator, self); | ||
| 774 | break :blk di orelse return; | ||
| 775 | }; | ||
| 776 | |||
| 777 | // We assume there is only one CU. | ||
| 778 | const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) { | ||
| 779 | error.MissingDebugInfo => { | ||
| 780 | // TODO audit cases with missing debug info and audit our dwarf.zig module. | ||
| 781 | log.debug("invalid or missing debug info in {s}; skipping", .{self.name}); | ||
| 782 | return; | ||
| 783 | }, | ||
| 784 | else => |e| return e, | ||
| 785 | }; | ||
| 786 | const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.name); | ||
| 787 | const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.comp_dir); | ||
| 788 | |||
| 789 | self.debug_info = debug_info; | ||
| 790 | self.tu_name = name; | ||
| 791 | self.tu_comp_dir = comp_dir; | ||
| 792 | |||
| 793 | if (self.mtime == null) { | ||
| 794 | self.mtime = mtime: { | ||
| 795 | const stat = self.file.stat() catch break :mtime 0; | ||
| 796 | break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000)); | ||
| 797 | }; | ||
| 798 | } | ||
| 799 | } | ||
| 800 | |||
| 801 | fn parseDataInCode(self: *Object) void { | 654 | fn parseDataInCode(self: *Object) void { |
| 802 | const index = self.data_in_code_cmd_index orelse return; | 655 | const index = self.data_in_code_cmd_index orelse return; |
| 803 | const data_in_code = self.load_commands.items[index].linkedit_data; | 656 | const data_in_code = self.load_commands.items[index].linkedit_data; |
| ... | @@ -808,7 +661,7 @@ fn parseDataInCode(self: *Object) void { | ... | @@ -808,7 +661,7 @@ fn parseDataInCode(self: *Object) void { |
| 808 | ); | 661 | ); |
| 809 | } | 662 | } |
| 810 | 663 | ||
| 811 | fn getSectionContents(self: Object, sect_id: u16) error{Overflow}![]const u8 { | 664 | pub fn getSectionContents(self: Object, sect_id: u16) error{Overflow}![]const u8 { |
| 812 | const sect = self.getSection(sect_id); | 665 | const sect = self.getSection(sect_id); |
| 813 | const size = math.cast(usize, sect.size) orelse return error.Overflow; | 666 | const size = math.cast(usize, sect.size) orelse return error.Overflow; |
| 814 | log.debug("getting {s},{s} data at 0x{x} - 0x{x}", .{ | 667 | log.debug("getting {s},{s} data at 0x{x} - 0x{x}", .{ |