| ... | @@ -1,8 +1,10 @@ | ... | @@ -1,8 +1,10 @@ |
| 1 | archive: ?InArchive = null, | 1 | /// Non-zero for fat object files or archives |
| | 2 | offset: u64, |
| 2 | path: []const u8, | 3 | path: []const u8, |
| 3 | file_handle: File.HandleIndex, | 4 | file_handle: File.HandleIndex, |
| 4 | mtime: u64, | 5 | mtime: u64, |
| 5 | index: File.Index, | 6 | index: File.Index, |
| | 7 | in_archive: ?InArchive = null, |
| 6 | | 8 | |
| 7 | header: ?macho.mach_header_64 = null, | 9 | header: ?macho.mach_header_64 = null, |
| 8 | sections: std.MultiArrayList(Section) = .{}, | 10 | sections: std.MultiArrayList(Section) = .{}, |
| ... | @@ -21,7 +23,8 @@ compact_unwind_sect_index: ?u8 = null, | ... | @@ -21,7 +23,8 @@ compact_unwind_sect_index: ?u8 = null, |
| 21 | cies: std.ArrayListUnmanaged(Cie) = .{}, | 23 | cies: std.ArrayListUnmanaged(Cie) = .{}, |
| 22 | fdes: std.ArrayListUnmanaged(Fde) = .{}, | 24 | fdes: std.ArrayListUnmanaged(Fde) = .{}, |
| 23 | eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, | 25 | eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, |
| 24 | unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record.Index) = .{}, | 26 | unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record) = .{}, |
| | 27 | unwind_records_indexes: std.ArrayListUnmanaged(UnwindInfo.Record.Index) = .{}, |
| 25 | data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, | 28 | data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, |
| 26 | | 29 | |
| 27 | alive: bool = true, | 30 | alive: bool = true, |
| ... | @@ -39,7 +42,7 @@ pub fn isObject(path: []const u8) !bool { | ... | @@ -39,7 +42,7 @@ pub fn isObject(path: []const u8) !bool { |
| 39 | } | 42 | } |
| 40 | | 43 | |
| 41 | pub fn deinit(self: *Object, allocator: Allocator) void { | 44 | pub fn deinit(self: *Object, allocator: Allocator) void { |
| 42 | if (self.archive) |*ar| allocator.free(ar.path); | 45 | if (self.in_archive) |*ar| allocator.free(ar.path); |
| 43 | allocator.free(self.path); | 46 | allocator.free(self.path); |
| 44 | for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| { | 47 | for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| { |
| 45 | relocs.deinit(allocator); | 48 | relocs.deinit(allocator); |
| ... | @@ -54,6 +57,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void { | ... | @@ -54,6 +57,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void { |
| 54 | self.fdes.deinit(allocator); | 57 | self.fdes.deinit(allocator); |
| 55 | self.eh_frame_data.deinit(allocator); | 58 | self.eh_frame_data.deinit(allocator); |
| 56 | self.unwind_records.deinit(allocator); | 59 | self.unwind_records.deinit(allocator); |
| | 60 | self.unwind_records_indexes.deinit(allocator); |
| 57 | for (self.stab_files.items) |*sf| { | 61 | for (self.stab_files.items) |*sf| { |
| 58 | sf.stabs.deinit(allocator); | 62 | sf.stabs.deinit(allocator); |
| 59 | } | 63 | } |
| ... | @@ -66,12 +70,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { | ... | @@ -66,12 +70,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 66 | defer tracy.end(); | 70 | defer tracy.end(); |
| 67 | | 71 | |
| 68 | const gpa = macho_file.base.comp.gpa; | 72 | const gpa = macho_file.base.comp.gpa; |
| 69 | const offset = if (self.archive) |ar| ar.offset else 0; | | |
| 70 | const handle = macho_file.getFileHandle(self.file_handle); | 73 | const handle = macho_file.getFileHandle(self.file_handle); |
| 71 | | 74 | |
| 72 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; | 75 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; |
| 73 | { | 76 | { |
| 74 | const amt = try handle.preadAll(&header_buffer, offset); | 77 | const amt = try handle.preadAll(&header_buffer, self.offset); |
| 75 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; | 78 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; |
| 76 | } | 79 | } |
| 77 | self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; | 80 | self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; |
| ... | @@ -92,7 +95,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { | ... | @@ -92,7 +95,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 92 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); | 95 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); |
| 93 | defer gpa.free(lc_buffer); | 96 | defer gpa.free(lc_buffer); |
| 94 | { | 97 | { |
| 95 | const amt = try handle.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64)); | 98 | const amt = try handle.preadAll(lc_buffer, self.offset + @sizeOf(macho.mach_header_64)); |
| 96 | if (amt != self.header.?.sizeofcmds) return error.InputOutput; | 99 | if (amt != self.header.?.sizeofcmds) return error.InputOutput; |
| 97 | } | 100 | } |
| 98 | | 101 | |
| ... | @@ -119,14 +122,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { | ... | @@ -119,14 +122,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 119 | const cmd = lc.cast(macho.symtab_command).?; | 122 | const cmd = lc.cast(macho.symtab_command).?; |
| 120 | try self.strtab.resize(gpa, cmd.strsize); | 123 | try self.strtab.resize(gpa, cmd.strsize); |
| 121 | { | 124 | { |
| 122 | const amt = try handle.preadAll(self.strtab.items, cmd.stroff + offset); | 125 | const amt = try handle.preadAll(self.strtab.items, cmd.stroff + self.offset); |
| 123 | if (amt != self.strtab.items.len) return error.InputOutput; | 126 | if (amt != self.strtab.items.len) return error.InputOutput; |
| 124 | } | 127 | } |
| 125 | | 128 | |
| 126 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); | 129 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); |
| 127 | defer gpa.free(symtab_buffer); | 130 | defer gpa.free(symtab_buffer); |
| 128 | { | 131 | { |
| 129 | const amt = try handle.preadAll(symtab_buffer, cmd.symoff + offset); | 132 | const amt = try handle.preadAll(symtab_buffer, cmd.symoff + self.offset); |
| 130 | if (amt != symtab_buffer.len) return error.InputOutput; | 133 | if (amt != symtab_buffer.len) return error.InputOutput; |
| 131 | } | 134 | } |
| 132 | const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms]; | 135 | const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms]; |
| ... | @@ -144,7 +147,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { | ... | @@ -144,7 +147,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 144 | const buffer = try gpa.alloc(u8, cmd.datasize); | 147 | const buffer = try gpa.alloc(u8, cmd.datasize); |
| 145 | defer gpa.free(buffer); | 148 | defer gpa.free(buffer); |
| 146 | { | 149 | { |
| 147 | const amt = try handle.preadAll(buffer, offset + cmd.dataoff); | 150 | const amt = try handle.preadAll(buffer, self.offset + cmd.dataoff); |
| 148 | if (amt != buffer.len) return error.InputOutput; | 151 | if (amt != buffer.len) return error.InputOutput; |
| 149 | } | 152 | } |
| 150 | const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry)); | 153 | const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry)); |
| ... | @@ -218,11 +221,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { | ... | @@ -218,11 +221,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 218 | | 221 | |
| 219 | // Parse Apple's __LD,__compact_unwind section | 222 | // Parse Apple's __LD,__compact_unwind section |
| 220 | if (self.compact_unwind_sect_index) |index| { | 223 | if (self.compact_unwind_sect_index) |index| { |
| 221 | try self.initUnwindRecords(index, macho_file); | 224 | try self.initUnwindRecords(gpa, index, handle, macho_file); |
| 222 | } | 225 | } |
| 223 | | 226 | |
| 224 | if (self.hasUnwindRecords() or self.hasEhFrameRecords()) { | 227 | if (self.hasUnwindRecords() or self.hasEhFrameRecords()) { |
| 225 | try self.parseUnwindRecords(macho_file); | 228 | try self.parseUnwindRecords(gpa, macho_file.getTarget().cpu.arch, macho_file); |
| 226 | } | 229 | } |
| 227 | | 230 | |
| 228 | if (self.platform) |platform| { | 231 | if (self.platform) |platform| { |
| ... | @@ -987,7 +990,7 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | ... | @@ -987,7 +990,7 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 987 | } | 990 | } |
| 988 | } | 991 | } |
| 989 | | 992 | |
| 990 | fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | 993 | fn initUnwindRecords(self: *Object, allocator: Allocator, sect_id: u8, file: File.Handle, macho_file: *MachO) !void { |
| 991 | const tracy = trace(@src()); | 994 | const tracy = trace(@src()); |
| 992 | defer tracy.end(); | 995 | defer tracy.end(); |
| 993 | | 996 | |
| ... | @@ -1003,19 +1006,22 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | ... | @@ -1003,19 +1006,22 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 1003 | } | 1006 | } |
| 1004 | }; | 1007 | }; |
| 1005 | | 1008 | |
| 1006 | const gpa = macho_file.base.comp.gpa; | 1009 | const header = self.sections.items(.header)[sect_id]; |
| 1007 | const data = try self.getSectionData(sect_id, macho_file); | 1010 | const data = try allocator.alloc(u8, header.size); |
| 1008 | defer gpa.free(data); | 1011 | defer allocator.free(data); |
| | 1012 | const amt = try file.preadAll(data, header.offset + self.offset); |
| | 1013 | if (amt != data.len) return error.InputOutput; |
| | 1014 | |
| 1009 | const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry)); | 1015 | const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry)); |
| 1010 | const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs]; | 1016 | const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs]; |
| 1011 | const sym_lookup = SymbolLookup{ .ctx = self }; | 1017 | const sym_lookup = SymbolLookup{ .ctx = self }; |
| 1012 | | 1018 | |
| 1013 | try self.unwind_records.resize(gpa, nrecs); | 1019 | try self.unwind_records.ensureTotalCapacityPrecise(allocator, nrecs); |
| | 1020 | try self.unwind_records_indexes.ensureTotalCapacityPrecise(allocator, nrecs); |
| 1014 | | 1021 | |
| 1015 | const header = self.sections.items(.header)[sect_id]; | | |
| 1016 | const relocs = self.sections.items(.relocs)[sect_id].items; | 1022 | const relocs = self.sections.items(.relocs)[sect_id].items; |
| 1017 | var reloc_idx: usize = 0; | 1023 | var reloc_idx: usize = 0; |
| 1018 | for (recs, self.unwind_records.items, 0..) |rec, *out_index, rec_idx| { | 1024 | for (recs, 0..) |rec, rec_idx| { |
| 1019 | const rec_start = rec_idx * @sizeOf(macho.compact_unwind_entry); | 1025 | const rec_start = rec_idx * @sizeOf(macho.compact_unwind_entry); |
| 1020 | const rec_end = rec_start + @sizeOf(macho.compact_unwind_entry); | 1026 | const rec_end = rec_start + @sizeOf(macho.compact_unwind_entry); |
| 1021 | const reloc_start = reloc_idx; | 1027 | const reloc_start = reloc_idx; |
| ... | @@ -1023,11 +1029,11 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | ... | @@ -1023,11 +1029,11 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 1023 | relocs[reloc_idx].offset < rec_end) : (reloc_idx += 1) | 1029 | relocs[reloc_idx].offset < rec_end) : (reloc_idx += 1) |
| 1024 | {} | 1030 | {} |
| 1025 | | 1031 | |
| 1026 | out_index.* = try macho_file.addUnwindRecord(); | 1032 | const out_index = self.addUnwindRecordAssumeCapacity(); |
| 1027 | const out = macho_file.getUnwindRecord(out_index.*); | 1033 | self.unwind_records_indexes.appendAssumeCapacity(out_index); |
| | 1034 | const out = self.getUnwindRecord(out_index); |
| 1028 | out.length = rec.rangeLength; | 1035 | out.length = rec.rangeLength; |
| 1029 | out.enc = .{ .enc = rec.compactUnwindEncoding }; | 1036 | out.enc = .{ .enc = rec.compactUnwindEncoding }; |
| 1030 | out.file = self.index; | | |
| 1031 | | 1037 | |
| 1032 | for (relocs[reloc_start..reloc_idx]) |rel| { | 1038 | for (relocs[reloc_start..reloc_idx]) |rel| { |
| 1033 | if (rel.type != .unsigned or rel.meta.length != 3) { | 1039 | if (rel.type != .unsigned or rel.meta.length != 3) { |
| ... | @@ -1090,7 +1096,7 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | ... | @@ -1090,7 +1096,7 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 1090 | } | 1096 | } |
| 1091 | } | 1097 | } |
| 1092 | | 1098 | |
| 1093 | fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | 1099 | fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch, macho_file: *MachO) !void { |
| 1094 | // Synthesise missing unwind records. | 1100 | // Synthesise missing unwind records. |
| 1095 | // The logic here is as follows: | 1101 | // The logic here is as follows: |
| 1096 | // 1. if an atom has unwind info record that is not DWARF, FDE is marked dead | 1102 | // 1. if an atom has unwind info record that is not DWARF, FDE is marked dead |
| ... | @@ -1100,8 +1106,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -1100,8 +1106,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1100 | | 1106 | |
| 1101 | const Superposition = struct { atom: Atom.Index, size: u64, cu: ?UnwindInfo.Record.Index = null, fde: ?Fde.Index = null }; | 1107 | const Superposition = struct { atom: Atom.Index, size: u64, cu: ?UnwindInfo.Record.Index = null, fde: ?Fde.Index = null }; |
| 1102 | | 1108 | |
| 1103 | const gpa = macho_file.base.comp.gpa; | 1109 | var superposition = std.AutoArrayHashMap(u64, Superposition).init(allocator); |
| 1104 | var superposition = std.AutoArrayHashMap(u64, Superposition).init(gpa); | | |
| 1105 | defer superposition.deinit(); | 1110 | defer superposition.deinit(); |
| 1106 | | 1111 | |
| 1107 | const slice = self.symtab.slice(); | 1112 | const slice = self.symtab.slice(); |
| ... | @@ -1119,8 +1124,8 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -1119,8 +1124,8 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1119 | } | 1124 | } |
| 1120 | } | 1125 | } |
| 1121 | | 1126 | |
| 1122 | for (self.unwind_records.items) |rec_index| { | 1127 | for (self.unwind_records_indexes.items) |rec_index| { |
| 1123 | const rec = macho_file.getUnwindRecord(rec_index); | 1128 | const rec = self.getUnwindRecord(rec_index); |
| 1124 | const atom = rec.getAtom(macho_file); | 1129 | const atom = rec.getAtom(macho_file); |
| 1125 | const addr = atom.getInputAddress(macho_file) + rec.atom_offset; | 1130 | const addr = atom.getInputAddress(macho_file) + rec.atom_offset; |
| 1126 | superposition.getPtr(addr).?.cu = rec_index; | 1131 | superposition.getPtr(addr).?.cu = rec_index; |
| ... | @@ -1137,7 +1142,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -1137,7 +1142,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1137 | const fde = &self.fdes.items[fde_index]; | 1142 | const fde = &self.fdes.items[fde_index]; |
| 1138 | | 1143 | |
| 1139 | if (meta.cu) |rec_index| { | 1144 | if (meta.cu) |rec_index| { |
| 1140 | const rec = macho_file.getUnwindRecord(rec_index); | 1145 | const rec = self.getUnwindRecord(rec_index); |
| 1141 | if (!rec.enc.isDwarf(macho_file)) { | 1146 | if (!rec.enc.isDwarf(macho_file)) { |
| 1142 | // Mark FDE dead | 1147 | // Mark FDE dead |
| 1143 | fde.alive = false; | 1148 | fde.alive = false; |
| ... | @@ -1147,15 +1152,14 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -1147,15 +1152,14 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1147 | } | 1152 | } |
| 1148 | } else { | 1153 | } else { |
| 1149 | // Synthesise new unwind info record | 1154 | // Synthesise new unwind info record |
| 1150 | const rec_index = try macho_file.addUnwindRecord(); | 1155 | const rec_index = try self.addUnwindRecord(allocator); |
| 1151 | const rec = macho_file.getUnwindRecord(rec_index); | 1156 | const rec = self.getUnwindRecord(rec_index); |
| 1152 | try self.unwind_records.append(gpa, rec_index); | 1157 | try self.unwind_records_indexes.append(allocator, rec_index); |
| 1153 | rec.length = @intCast(meta.size); | 1158 | rec.length = @intCast(meta.size); |
| 1154 | rec.atom = fde.atom; | 1159 | rec.atom = fde.atom; |
| 1155 | rec.atom_offset = fde.atom_offset; | 1160 | rec.atom_offset = fde.atom_offset; |
| 1156 | rec.fde = fde_index; | 1161 | rec.fde = fde_index; |
| 1157 | rec.file = fde.file; | 1162 | switch (cpu_arch) { |
| 1158 | switch (macho_file.getTarget().cpu.arch) { | | |
| 1159 | .x86_64 => rec.enc.setMode(macho.UNWIND_X86_64_MODE.DWARF), | 1163 | .x86_64 => rec.enc.setMode(macho.UNWIND_X86_64_MODE.DWARF), |
| 1160 | .aarch64 => rec.enc.setMode(macho.UNWIND_ARM64_MODE.DWARF), | 1164 | .aarch64 => rec.enc.setMode(macho.UNWIND_ARM64_MODE.DWARF), |
| 1161 | else => unreachable, | 1165 | else => unreachable, |
| ... | @@ -1163,10 +1167,10 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -1163,10 +1167,10 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1163 | } | 1167 | } |
| 1164 | } else if (meta.cu == null and meta.fde == null) { | 1168 | } else if (meta.cu == null and meta.fde == null) { |
| 1165 | // Create a null record | 1169 | // Create a null record |
| 1166 | const rec_index = try macho_file.addUnwindRecord(); | 1170 | const rec_index = try self.addUnwindRecord(allocator); |
| 1167 | const rec = macho_file.getUnwindRecord(rec_index); | 1171 | const rec = self.getUnwindRecord(rec_index); |
| 1168 | const atom = macho_file.getAtom(meta.atom).?; | 1172 | const atom = macho_file.getAtom(meta.atom).?; |
| 1169 | try self.unwind_records.append(gpa, rec_index); | 1173 | try self.unwind_records_indexes.append(allocator, rec_index); |
| 1170 | rec.length = @intCast(meta.size); | 1174 | rec.length = @intCast(meta.size); |
| 1171 | rec.atom = meta.atom; | 1175 | rec.atom = meta.atom; |
| 1172 | rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file)); | 1176 | rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file)); |
| ... | @@ -1174,25 +1178,31 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -1174,25 +1178,31 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1174 | } | 1178 | } |
| 1175 | } | 1179 | } |
| 1176 | | 1180 | |
| 1177 | const sortFn = struct { | 1181 | const SortCtx = struct { |
| 1178 | fn sortFn(ctx: *MachO, lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool { | 1182 | object: *Object, |
| 1179 | const lhs = ctx.getUnwindRecord(lhs_index); | 1183 | mfile: *MachO, |
| 1180 | const rhs = ctx.getUnwindRecord(rhs_index); | 1184 | |
| 1181 | const lhsa = lhs.getAtom(ctx); | 1185 | fn sort(ctx: @This(), lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool { |
| 1182 | const rhsa = rhs.getAtom(ctx); | 1186 | const lhs = ctx.object.getUnwindRecord(lhs_index); |
| 1183 | return lhsa.getInputAddress(ctx) + lhs.atom_offset < rhsa.getInputAddress(ctx) + rhs.atom_offset; | 1187 | const rhs = ctx.object.getUnwindRecord(rhs_index); |
| | 1188 | const lhsa = lhs.getAtom(ctx.mfile); |
| | 1189 | const rhsa = rhs.getAtom(ctx.mfile); |
| | 1190 | return lhsa.getInputAddress(ctx.mfile) + lhs.atom_offset < rhsa.getInputAddress(ctx.mfile) + rhs.atom_offset; |
| 1184 | } | 1191 | } |
| 1185 | }.sortFn; | 1192 | }; |
| 1186 | mem.sort(UnwindInfo.Record.Index, self.unwind_records.items, macho_file, sortFn); | 1193 | mem.sort(UnwindInfo.Record.Index, self.unwind_records_indexes.items, SortCtx{ |
| | 1194 | .object = self, |
| | 1195 | .mfile = macho_file, |
| | 1196 | }, SortCtx.sort); |
| 1187 | | 1197 | |
| 1188 | // Associate unwind records to atoms | 1198 | // Associate unwind records to atoms |
| 1189 | var next_cu: u32 = 0; | 1199 | var next_cu: u32 = 0; |
| 1190 | while (next_cu < self.unwind_records.items.len) { | 1200 | while (next_cu < self.unwind_records_indexes.items.len) { |
| 1191 | const start = next_cu; | 1201 | const start = next_cu; |
| 1192 | const rec_index = self.unwind_records.items[start]; | 1202 | const rec_index = self.unwind_records_indexes.items[start]; |
| 1193 | const rec = macho_file.getUnwindRecord(rec_index); | 1203 | const rec = self.getUnwindRecord(rec_index); |
| 1194 | while (next_cu < self.unwind_records.items.len and | 1204 | while (next_cu < self.unwind_records_indexes.items.len and |
| 1195 | macho_file.getUnwindRecord(self.unwind_records.items[next_cu]).atom == rec.atom) : (next_cu += 1) | 1205 | self.getUnwindRecord(self.unwind_records_indexes.items[next_cu]).atom == rec.atom) : (next_cu += 1) |
| 1196 | {} | 1206 | {} |
| 1197 | | 1207 | |
| 1198 | const atom = rec.getAtom(macho_file); | 1208 | const atom = rec.getAtom(macho_file); |
| ... | @@ -1441,7 +1451,7 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, macho_file: *MachO) error{ | ... | @@ -1441,7 +1451,7 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, macho_file: *MachO) error{ |
| 1441 | } | 1451 | } |
| 1442 | } | 1452 | } |
| 1443 | | 1453 | |
| 1444 | pub fn scanRelocs(self: Object, macho_file: *MachO) !void { | 1454 | pub fn scanRelocs(self: *Object, macho_file: *MachO) !void { |
| 1445 | const tracy = trace(@src()); | 1455 | const tracy = trace(@src()); |
| 1446 | defer tracy.end(); | 1456 | defer tracy.end(); |
| 1447 | | 1457 | |
| ... | @@ -1453,8 +1463,8 @@ pub fn scanRelocs(self: Object, macho_file: *MachO) !void { | ... | @@ -1453,8 +1463,8 @@ pub fn scanRelocs(self: Object, macho_file: *MachO) !void { |
| 1453 | try atom.scanRelocs(macho_file); | 1463 | try atom.scanRelocs(macho_file); |
| 1454 | } | 1464 | } |
| 1455 | | 1465 | |
| 1456 | for (self.unwind_records.items) |rec_index| { | 1466 | for (self.unwind_records_indexes.items) |rec_index| { |
| 1457 | const rec = macho_file.getUnwindRecord(rec_index); | 1467 | const rec = self.getUnwindRecord(rec_index); |
| 1458 | if (!rec.alive) continue; | 1468 | if (!rec.alive) continue; |
| 1459 | if (rec.getFde(macho_file)) |fde| { | 1469 | if (rec.getFde(macho_file)) |fde| { |
| 1460 | if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| { | 1470 | if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| { |
| ... | @@ -1532,12 +1542,11 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { | ... | @@ -1532,12 +1542,11 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { |
| 1532 | defer tracy.end(); | 1542 | defer tracy.end(); |
| 1533 | | 1543 | |
| 1534 | const gpa = macho_file.base.comp.gpa; | 1544 | const gpa = macho_file.base.comp.gpa; |
| 1535 | const offset = if (self.archive) |ar| ar.offset else 0; | | |
| 1536 | const handle = macho_file.getFileHandle(self.file_handle); | 1545 | const handle = macho_file.getFileHandle(self.file_handle); |
| 1537 | | 1546 | |
| 1538 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; | 1547 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; |
| 1539 | { | 1548 | { |
| 1540 | const amt = try handle.preadAll(&header_buffer, offset); | 1549 | const amt = try handle.preadAll(&header_buffer, self.offset); |
| 1541 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; | 1550 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; |
| 1542 | } | 1551 | } |
| 1543 | self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; | 1552 | self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; |
| ... | @@ -1558,7 +1567,7 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { | ... | @@ -1558,7 +1567,7 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { |
| 1558 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); | 1567 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); |
| 1559 | defer gpa.free(lc_buffer); | 1568 | defer gpa.free(lc_buffer); |
| 1560 | { | 1569 | { |
| 1561 | const amt = try handle.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64)); | 1570 | const amt = try handle.preadAll(lc_buffer, self.offset + @sizeOf(macho.mach_header_64)); |
| 1562 | if (amt != self.header.?.sizeofcmds) return error.InputOutput; | 1571 | if (amt != self.header.?.sizeofcmds) return error.InputOutput; |
| 1563 | } | 1572 | } |
| 1564 | | 1573 | |
| ... | @@ -1571,14 +1580,14 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { | ... | @@ -1571,14 +1580,14 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { |
| 1571 | const cmd = lc.cast(macho.symtab_command).?; | 1580 | const cmd = lc.cast(macho.symtab_command).?; |
| 1572 | try self.strtab.resize(gpa, cmd.strsize); | 1581 | try self.strtab.resize(gpa, cmd.strsize); |
| 1573 | { | 1582 | { |
| 1574 | const amt = try handle.preadAll(self.strtab.items, cmd.stroff + offset); | 1583 | const amt = try handle.preadAll(self.strtab.items, cmd.stroff + self.offset); |
| 1575 | if (amt != self.strtab.items.len) return error.InputOutput; | 1584 | if (amt != self.strtab.items.len) return error.InputOutput; |
| 1576 | } | 1585 | } |
| 1577 | | 1586 | |
| 1578 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); | 1587 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); |
| 1579 | defer gpa.free(symtab_buffer); | 1588 | defer gpa.free(symtab_buffer); |
| 1580 | { | 1589 | { |
| 1581 | const amt = try handle.preadAll(symtab_buffer, cmd.symoff + offset); | 1590 | const amt = try handle.preadAll(symtab_buffer, cmd.symoff + self.offset); |
| 1582 | if (amt != symtab_buffer.len) return error.InputOutput; | 1591 | if (amt != symtab_buffer.len) return error.InputOutput; |
| 1583 | } | 1592 | } |
| 1584 | const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms]; | 1593 | const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms]; |
| ... | @@ -1613,7 +1622,7 @@ pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, macho_file: *M | ... | @@ -1613,7 +1622,7 @@ pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, macho_file: *M |
| 1613 | } | 1622 | } |
| 1614 | | 1623 | |
| 1615 | pub fn updateArSize(self: *Object, macho_file: *MachO) !void { | 1624 | pub fn updateArSize(self: *Object, macho_file: *MachO) !void { |
| 1616 | self.output_ar_state.size = if (self.archive) |ar| ar.size else size: { | 1625 | self.output_ar_state.size = if (self.in_archive) |ar| ar.size else size: { |
| 1617 | const file = macho_file.getFileHandle(self.file_handle); | 1626 | const file = macho_file.getFileHandle(self.file_handle); |
| 1618 | break :size (try file.stat()).size; | 1627 | break :size (try file.stat()).size; |
| 1619 | }; | 1628 | }; |
| ... | @@ -1622,7 +1631,6 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { | ... | @@ -1622,7 +1631,6 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { |
| 1622 | pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { | 1631 | pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { |
| 1623 | // Header | 1632 | // Header |
| 1624 | const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; | 1633 | const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; |
| 1625 | const offset: u64 = if (self.archive) |ar| ar.offset else 0; | | |
| 1626 | try Archive.writeHeader(self.path, size, ar_format, writer); | 1634 | try Archive.writeHeader(self.path, size, ar_format, writer); |
| 1627 | // Data | 1635 | // Data |
| 1628 | const file = macho_file.getFileHandle(self.file_handle); | 1636 | const file = macho_file.getFileHandle(self.file_handle); |
| ... | @@ -1630,7 +1638,7 @@ pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writ | ... | @@ -1630,7 +1638,7 @@ pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writ |
| 1630 | const gpa = macho_file.base.comp.gpa; | 1638 | const gpa = macho_file.base.comp.gpa; |
| 1631 | const data = try gpa.alloc(u8, size); | 1639 | const data = try gpa.alloc(u8, size); |
| 1632 | defer gpa.free(data); | 1640 | defer gpa.free(data); |
| 1633 | const amt = try file.preadAll(data, offset); | 1641 | const amt = try file.preadAll(data, self.offset); |
| 1634 | if (amt != size) return error.InputOutput; | 1642 | if (amt != size) return error.InputOutput; |
| 1635 | try writer.writeAll(data); | 1643 | try writer.writeAll(data); |
| 1636 | } | 1644 | } |
| ... | @@ -1680,7 +1688,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void { | ... | @@ -1680,7 +1688,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void { |
| 1680 | self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir | 1688 | self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir |
| 1681 | self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name | 1689 | self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name |
| 1682 | | 1690 | |
| 1683 | if (self.archive) |ar| { | 1691 | if (self.in_archive) |ar| { |
| 1684 | self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1)); | 1692 | self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1)); |
| 1685 | } else { | 1693 | } else { |
| 1686 | self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1)); | 1694 | self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1)); |
| ... | @@ -1820,7 +1828,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O | ... | @@ -1820,7 +1828,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1820 | index += 1; | 1828 | index += 1; |
| 1821 | // N_OSO path | 1829 | // N_OSO path |
| 1822 | n_strx = @as(u32, @intCast(ctx.strtab.items.len)); | 1830 | n_strx = @as(u32, @intCast(ctx.strtab.items.len)); |
| 1823 | if (self.archive) |ar| { | 1831 | if (self.in_archive) |ar| { |
| 1824 | ctx.strtab.appendSliceAssumeCapacity(ar.path); | 1832 | ctx.strtab.appendSliceAssumeCapacity(ar.path); |
| 1825 | ctx.strtab.appendAssumeCapacity('('); | 1833 | ctx.strtab.appendAssumeCapacity('('); |
| 1826 | ctx.strtab.appendSliceAssumeCapacity(self.path); | 1834 | ctx.strtab.appendSliceAssumeCapacity(self.path); |
| ... | @@ -1989,11 +1997,10 @@ fn getSectionData(self: *const Object, index: u32, macho_file: *MachO) ![]u8 { | ... | @@ -1989,11 +1997,10 @@ fn getSectionData(self: *const Object, index: u32, macho_file: *MachO) ![]u8 { |
| 1989 | assert(index < slice.items(.header).len); | 1997 | assert(index < slice.items(.header).len); |
| 1990 | const sect = slice.items(.header)[index]; | 1998 | const sect = slice.items(.header)[index]; |
| 1991 | const handle = macho_file.getFileHandle(self.file_handle); | 1999 | const handle = macho_file.getFileHandle(self.file_handle); |
| 1992 | const offset = if (self.archive) |ar| ar.offset else 0; | | |
| 1993 | const size = math.cast(usize, sect.size) orelse return error.Overflow; | 2000 | const size = math.cast(usize, sect.size) orelse return error.Overflow; |
| 1994 | const buffer = try gpa.alloc(u8, size); | 2001 | const buffer = try gpa.alloc(u8, size); |
| 1995 | errdefer gpa.free(buffer); | 2002 | errdefer gpa.free(buffer); |
| 1996 | const amt = try handle.preadAll(buffer, sect.offset + offset); | 2003 | const amt = try handle.preadAll(buffer, sect.offset + self.offset); |
| 1997 | if (amt != buffer.len) return error.InputOutput; | 2004 | if (amt != buffer.len) return error.InputOutput; |
| 1998 | return buffer; | 2005 | return buffer; |
| 1999 | } | 2006 | } |
| ... | @@ -2002,9 +2009,8 @@ pub fn getAtomData(self: *const Object, macho_file: *MachO, atom: Atom, buffer: | ... | @@ -2002,9 +2009,8 @@ pub fn getAtomData(self: *const Object, macho_file: *MachO, atom: Atom, buffer: |
| 2002 | assert(buffer.len == atom.size); | 2009 | assert(buffer.len == atom.size); |
| 2003 | const slice = self.sections.slice(); | 2010 | const slice = self.sections.slice(); |
| 2004 | const handle = macho_file.getFileHandle(self.file_handle); | 2011 | const handle = macho_file.getFileHandle(self.file_handle); |
| 2005 | const offset = if (self.archive) |ar| ar.offset else 0; | | |
| 2006 | const sect = slice.items(.header)[atom.n_sect]; | 2012 | const sect = slice.items(.header)[atom.n_sect]; |
| 2007 | const amt = try handle.preadAll(buffer, sect.offset + offset + atom.off); | 2013 | const amt = try handle.preadAll(buffer, sect.offset + self.offset + atom.off); |
| 2008 | if (amt != buffer.len) return error.InputOutput; | 2014 | if (amt != buffer.len) return error.InputOutput; |
| 2009 | } | 2015 | } |
| 2010 | | 2016 | |
| ... | @@ -2068,6 +2074,23 @@ pub fn asFile(self: *Object) File { | ... | @@ -2068,6 +2074,23 @@ pub fn asFile(self: *Object) File { |
| 2068 | return .{ .object = self }; | 2074 | return .{ .object = self }; |
| 2069 | } | 2075 | } |
| 2070 | | 2076 | |
| | 2077 | fn addUnwindRecord(self: *Object, allocator: Allocator) !UnwindInfo.Record.Index { |
| | 2078 | try self.unwind_records.ensureUnusedCapacity(allocator, 1); |
| | 2079 | return self.addUnwindRecordAssumeCapacity(); |
| | 2080 | } |
| | 2081 | |
| | 2082 | fn addUnwindRecordAssumeCapacity(self: *Object) UnwindInfo.Record.Index { |
| | 2083 | const index = @as(UnwindInfo.Record.Index, @intCast(self.unwind_records.items.len)); |
| | 2084 | const rec = self.unwind_records.addOneAssumeCapacity(); |
| | 2085 | rec.* = .{ .file = self.index }; |
| | 2086 | return index; |
| | 2087 | } |
| | 2088 | |
| | 2089 | pub fn getUnwindRecord(self: *Object, index: UnwindInfo.Record.Index) *UnwindInfo.Record { |
| | 2090 | assert(index < self.unwind_records.items.len); |
| | 2091 | return &self.unwind_records.items[index]; |
| | 2092 | } |
| | 2093 | |
| 2071 | pub fn format( | 2094 | pub fn format( |
| 2072 | self: *Object, | 2095 | self: *Object, |
| 2073 | comptime unused_fmt_string: []const u8, | 2096 | comptime unused_fmt_string: []const u8, |
| ... | @@ -2171,8 +2194,8 @@ fn formatUnwindRecords( | ... | @@ -2171,8 +2194,8 @@ fn formatUnwindRecords( |
| 2171 | const object = ctx.object; | 2194 | const object = ctx.object; |
| 2172 | const macho_file = ctx.macho_file; | 2195 | const macho_file = ctx.macho_file; |
| 2173 | try writer.writeAll(" unwind records\n"); | 2196 | try writer.writeAll(" unwind records\n"); |
| 2174 | for (object.unwind_records.items) |rec| { | 2197 | for (object.unwind_records_indexes.items) |rec| { |
| 2175 | try writer.print(" rec({d}) : {}\n", .{ rec, macho_file.getUnwindRecord(rec).fmt(macho_file) }); | 2198 | try writer.print(" rec({d}) : {}\n", .{ rec, object.getUnwindRecord(rec).fmt(macho_file) }); |
| 2176 | } | 2199 | } |
| 2177 | } | 2200 | } |
| 2178 | | 2201 | |
| ... | @@ -2211,7 +2234,7 @@ fn formatPath( | ... | @@ -2211,7 +2234,7 @@ fn formatPath( |
| 2211 | ) !void { | 2234 | ) !void { |
| 2212 | _ = unused_fmt_string; | 2235 | _ = unused_fmt_string; |
| 2213 | _ = options; | 2236 | _ = options; |
| 2214 | if (object.archive) |ar| { | 2237 | if (object.in_archive) |ar| { |
| 2215 | try writer.writeAll(ar.path); | 2238 | try writer.writeAll(ar.path); |
| 2216 | try writer.writeByte('('); | 2239 | try writer.writeByte('('); |
| 2217 | try writer.writeAll(object.path); | 2240 | try writer.writeAll(object.path); |
| ... | @@ -2285,7 +2308,6 @@ const CompileUnit = struct { | ... | @@ -2285,7 +2308,6 @@ const CompileUnit = struct { |
| 2285 | | 2308 | |
| 2286 | const InArchive = struct { | 2309 | const InArchive = struct { |
| 2287 | path: []const u8, | 2310 | path: []const u8, |
| 2288 | offset: u64, | | |
| 2289 | size: u32, | 2311 | size: u32, |
| 2290 | }; | 2312 | }; |
| 2291 | | 2313 | |
| ... | @@ -2300,11 +2322,10 @@ const x86_64 = struct { | ... | @@ -2300,11 +2322,10 @@ const x86_64 = struct { |
| 2300 | const gpa = macho_file.base.comp.gpa; | 2322 | const gpa = macho_file.base.comp.gpa; |
| 2301 | | 2323 | |
| 2302 | const handle = macho_file.getFileHandle(self.file_handle); | 2324 | const handle = macho_file.getFileHandle(self.file_handle); |
| 2303 | const offset = if (self.archive) |ar| ar.offset else 0; | | |
| 2304 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); | 2325 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 2305 | defer gpa.free(relocs_buffer); | 2326 | defer gpa.free(relocs_buffer); |
| 2306 | { | 2327 | { |
| 2307 | const amt = try handle.preadAll(relocs_buffer, sect.reloff + offset); | 2328 | const amt = try handle.preadAll(relocs_buffer, sect.reloff + self.offset); |
| 2308 | if (amt != relocs_buffer.len) return error.InputOutput; | 2329 | if (amt != relocs_buffer.len) return error.InputOutput; |
| 2309 | } | 2330 | } |
| 2310 | const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; | 2331 | const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; |
| ... | @@ -2463,11 +2484,10 @@ const aarch64 = struct { | ... | @@ -2463,11 +2484,10 @@ const aarch64 = struct { |
| 2463 | const gpa = macho_file.base.comp.gpa; | 2484 | const gpa = macho_file.base.comp.gpa; |
| 2464 | | 2485 | |
| 2465 | const handle = macho_file.getFileHandle(self.file_handle); | 2486 | const handle = macho_file.getFileHandle(self.file_handle); |
| 2466 | const offset = if (self.archive) |ar| ar.offset else 0; | | |
| 2467 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); | 2487 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 2468 | defer gpa.free(relocs_buffer); | 2488 | defer gpa.free(relocs_buffer); |
| 2469 | { | 2489 | { |
| 2470 | const amt = try handle.preadAll(relocs_buffer, sect.reloff + offset); | 2490 | const amt = try handle.preadAll(relocs_buffer, sect.reloff + self.offset); |
| 2471 | if (amt != relocs_buffer.len) return error.InputOutput; | 2491 | if (amt != relocs_buffer.len) return error.InputOutput; |
| 2472 | } | 2492 | } |
| 2473 | const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; | 2493 | const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; |