authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-30 21:48:24+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-30 21:48:24+02:00
logebe371b75769dcc5526cdb7650c875764fb536e4
tree4fcd24e1212238b919cf747154fdcefc42a109e8
parentba710ec09dd3df4cd0ee8de9a5299aeaed53a847

macho: report basic __eh_frame problems as errors


7 files changed, 55 insertions(+), 43 deletions(-)

src/link.zig-3
......@@ -693,7 +693,6 @@ pub const File = struct {
693693 /// TODO audit this error set. most of these should be collapsed into one error,
694694 /// and ErrorFlags should be updated to convey the meaning to the user.
695695 pub const FlushError = error{
696 BadDwarfCfi,
697696 CacheUnavailable,
698697 CurrentWorkingDirectoryUnlinked,
699698 DivisionByZero,
......@@ -728,8 +727,6 @@ pub const File = struct {
728727 MissAlignment,
729728 MissingEndForBody,
730729 MissingEndForExpression,
731 /// TODO: this should be removed from the error set in favor of using ErrorFlags
732 MissingSection,
733730 MissingSymbol,
734731 MissingTableSymbols,
735732 ModuleNameMismatch,
src/link/MachO.zig+1-1
......@@ -4946,7 +4946,7 @@ fn reportDependencyError(
49464946 });
49474947}
49484948
4949fn reportParseError(
4949pub fn reportParseError(
49504950 self: *MachO,
49514951 path: []const u8,
49524952 comptime format: []const u8,
src/link/MachO/Object.zig+9-6
......@@ -334,7 +334,14 @@ fn sectionLessThanByAddress(ctx: void, lhs: SortedSection, rhs: SortedSection) b
334334 return lhs.header.addr < rhs.header.addr;
335335}
336336
337pub fn splitIntoAtoms(self: *Object, macho_file: *MachO, object_id: u32) !void {
337pub const SplitIntoAtomsError = error{
338 OutOfMemory,
339 EndOfStream,
340 MissingEhFrameSection,
341 BadDwarfCfi,
342};
343
344pub fn splitIntoAtoms(self: *Object, macho_file: *MachO, object_id: u32) SplitIntoAtomsError!void {
338345 log.debug("splitting object({d}, {s}) into atoms", .{ object_id, self.name });
339346
340347 try self.splitRegularSections(macho_file, object_id);
......@@ -788,11 +795,7 @@ fn parseUnwindInfo(self: *Object, macho_file: *MachO, object_id: u32) !void {
788795 if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) break true;
789796 } else false;
790797
791 if (needs_eh_frame and !self.hasEhFrameRecords()) {
792 log.err("missing __TEXT,__eh_frame section", .{});
793 log.err(" in object {s}", .{self.name});
794 return error.MissingSection;
795 }
798 if (needs_eh_frame and !self.hasEhFrameRecords()) return error.MissingEhFrameSection;
796799
797800 try self.parseRelocs(gpa, sect_id);
798801 const relocs = self.getRelocs(sect_id);
src/link/MachO/UnwindInfo.zig+6-6
......@@ -240,7 +240,7 @@ pub fn collect(info: *UnwindInfo, macho_file: *MachO) !void {
240240 var record = unwind_records[record_id];
241241
242242 if (UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) {
243 try info.collectPersonalityFromDwarf(macho_file, @as(u32, @intCast(object_id)), symbol, &record);
243 info.collectPersonalityFromDwarf(macho_file, @as(u32, @intCast(object_id)), symbol, &record);
244244 } else {
245245 if (getPersonalityFunctionReloc(
246246 macho_file,
......@@ -288,7 +288,7 @@ pub fn collect(info: *UnwindInfo, macho_file: *MachO) !void {
288288 if (object.eh_frame_records_lookup.get(symbol)) |fde_offset| {
289289 if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue;
290290 var record = nullRecord();
291 try info.collectPersonalityFromDwarf(macho_file, @as(u32, @intCast(object_id)), symbol, &record);
291 info.collectPersonalityFromDwarf(macho_file, @as(u32, @intCast(object_id)), symbol, &record);
292292 switch (cpu_arch) {
293293 .aarch64 => UnwindEncoding.setMode(&record.compactUnwindEncoding, macho.UNWIND_ARM64_MODE.DWARF),
294294 .x86_64 => UnwindEncoding.setMode(&record.compactUnwindEncoding, macho.UNWIND_X86_64_MODE.DWARF),
......@@ -500,16 +500,16 @@ fn collectPersonalityFromDwarf(
500500 object_id: u32,
501501 sym_loc: SymbolWithLoc,
502502 record: *macho.compact_unwind_entry,
503) !void {
503) void {
504504 const object = &macho_file.objects.items[object_id];
505505 var it = object.getEhFrameRecordsIterator();
506506 const fde_offset = object.eh_frame_records_lookup.get(sym_loc).?;
507507 it.seekTo(fde_offset);
508 const fde = (try it.next()).?;
508 const fde = (it.next() catch return).?; // We don't care about the error since we already handled it
509509 const cie_ptr = fde.getCiePointerSource(object_id, macho_file, fde_offset);
510510 const cie_offset = fde_offset + 4 - cie_ptr;
511511 it.seekTo(cie_offset);
512 const cie = (try it.next()).?;
512 const cie = (it.next() catch return).?; // We don't care about the error since we already handled it
513513
514514 if (cie.getPersonalityPointerReloc(
515515 macho_file,
......@@ -528,7 +528,7 @@ fn collectPersonalityFromDwarf(
528528 }
529529}
530530
531pub fn calcSectionSize(info: UnwindInfo, macho_file: *MachO) !void {
531pub fn calcSectionSize(info: UnwindInfo, macho_file: *MachO) void {
532532 const sect_id = macho_file.unwind_info_section_index orelse return;
533533 const sect = &macho_file.sections.items(.header)[sect_id];
534534 sect.@"align" = 2;
src/link/MachO/dead_strip.zig+11-11
......@@ -13,7 +13,7 @@ pub fn gcAtoms(macho_file: *MachO) !void {
1313 try alive.ensureTotalCapacity(@as(u32, @intCast(macho_file.atoms.items.len)));
1414
1515 try collectRoots(macho_file, &roots);
16 try mark(macho_file, roots, &alive);
16 mark(macho_file, roots, &alive);
1717 prune(macho_file, alive);
1818}
1919
......@@ -227,7 +227,7 @@ fn refersLive(macho_file: *MachO, atom_index: Atom.Index, alive: AtomTable) bool
227227 return false;
228228}
229229
230fn mark(macho_file: *MachO, roots: AtomTable, alive: *AtomTable) !void {
230fn mark(macho_file: *MachO, roots: AtomTable, alive: *AtomTable) void {
231231 var it = roots.keyIterator();
232232 while (it.next()) |root| {
233233 markLive(macho_file, root.*, alive);
......@@ -264,11 +264,11 @@ fn mark(macho_file: *MachO, roots: AtomTable, alive: *AtomTable) !void {
264264 for (macho_file.objects.items, 0..) |_, object_id| {
265265 // Traverse unwind and eh_frame records noting if the source symbol has been marked, and if so,
266266 // marking all references as live.
267 try markUnwindRecords(macho_file, @as(u32, @intCast(object_id)), alive);
267 markUnwindRecords(macho_file, @as(u32, @intCast(object_id)), alive);
268268 }
269269}
270270
271fn markUnwindRecords(macho_file: *MachO, object_id: u32, alive: *AtomTable) !void {
271fn markUnwindRecords(macho_file: *MachO, object_id: u32, alive: *AtomTable) void {
272272 const object = &macho_file.objects.items[object_id];
273273 const cpu_arch = macho_file.base.options.target.cpu.arch;
274274
......@@ -280,7 +280,7 @@ fn markUnwindRecords(macho_file: *MachO, object_id: u32, alive: *AtomTable) !voi
280280 if (!object.hasUnwindRecords()) {
281281 if (alive.contains(atom_index)) {
282282 // Mark references live and continue.
283 try markEhFrameRecords(macho_file, object_id, atom_index, alive);
283 markEhFrameRecords(macho_file, object_id, atom_index, alive);
284284 } else {
285285 while (inner_syms_it.next()) |sym| {
286286 if (object.eh_frame_records_lookup.get(sym)) |fde_offset| {
......@@ -306,7 +306,7 @@ fn markUnwindRecords(macho_file: *MachO, object_id: u32, alive: *AtomTable) !voi
306306
307307 const record = unwind_records[record_id];
308308 if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) {
309 try markEhFrameRecords(macho_file, object_id, atom_index, alive);
309 markEhFrameRecords(macho_file, object_id, atom_index, alive);
310310 } else {
311311 if (UnwindInfo.getPersonalityFunctionReloc(macho_file, object_id, record_id)) |rel| {
312312 const target = Atom.parseRelocTarget(macho_file, .{
......@@ -339,7 +339,7 @@ fn markUnwindRecords(macho_file: *MachO, object_id: u32, alive: *AtomTable) !voi
339339 }
340340}
341341
342fn markEhFrameRecords(macho_file: *MachO, object_id: u32, atom_index: Atom.Index, alive: *AtomTable) !void {
342fn markEhFrameRecords(macho_file: *MachO, object_id: u32, atom_index: Atom.Index, alive: *AtomTable) void {
343343 const cpu_arch = macho_file.base.options.target.cpu.arch;
344344 const object = &macho_file.objects.items[object_id];
345345 var it = object.getEhFrameRecordsIterator();
......@@ -348,12 +348,12 @@ fn markEhFrameRecords(macho_file: *MachO, object_id: u32, atom_index: Atom.Index
348348 while (inner_syms_it.next()) |sym| {
349349 const fde_offset = object.eh_frame_records_lookup.get(sym) orelse continue; // Continue in case we hit a temp symbol alias
350350 it.seekTo(fde_offset);
351 const fde = (try it.next()).?;
351 const fde = (it.next() catch continue).?; // We don't care about the error at this point since it was already handled
352352
353353 const cie_ptr = fde.getCiePointerSource(object_id, macho_file, fde_offset);
354354 const cie_offset = fde_offset + 4 - cie_ptr;
355355 it.seekTo(cie_offset);
356 const cie = (try it.next()).?;
356 const cie = (it.next() catch continue).?; // We don't care about the error at this point since it was already handled
357357
358358 switch (cpu_arch) {
359359 .aarch64 => {
......@@ -377,10 +377,10 @@ fn markEhFrameRecords(macho_file: *MachO, object_id: u32, atom_index: Atom.Index
377377 },
378378 .x86_64 => {
379379 const sect = object.getSourceSection(object.eh_frame_sect_id.?);
380 const lsda_ptr = try fde.getLsdaPointer(cie, .{
380 const lsda_ptr = fde.getLsdaPointer(cie, .{
381381 .base_addr = sect.addr,
382382 .base_offset = fde_offset,
383 });
383 }) catch continue; // We don't care about the error at this point since it was already handled
384384 if (lsda_ptr) |lsda_address| {
385385 // Mark LSDA record as live
386386 const sym_index = object.getSymbolByAddress(lsda_address, null);
src/link/MachO/eh_frame.zig+14-14
......@@ -13,7 +13,7 @@ pub fn scanRelocs(macho_file: *MachO) !void {
1313 const fde_offset = object.eh_frame_records_lookup.get(sym) orelse continue;
1414 if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue;
1515 it.seekTo(fde_offset);
16 const fde = (try it.next()).?;
16 const fde = (it.next() catch continue).?; // We don't care about this error since we already handled it
1717
1818 const cie_ptr = fde.getCiePointerSource(@intCast(object_id), macho_file, fde_offset);
1919 const cie_offset = fde_offset + 4 - cie_ptr;
......@@ -21,7 +21,7 @@ pub fn scanRelocs(macho_file: *MachO) !void {
2121 if (!cies.contains(cie_offset)) {
2222 try cies.putNoClobber(cie_offset, {});
2323 it.seekTo(cie_offset);
24 const cie = (try it.next()).?;
24 const cie = (it.next() catch continue).?; // We don't care about this error since we already handled it
2525 try cie.scanRelocs(macho_file, @as(u32, @intCast(object_id)), cie_offset);
2626 }
2727 }
......@@ -29,7 +29,7 @@ pub fn scanRelocs(macho_file: *MachO) !void {
2929 }
3030}
3131
32pub fn calcSectionSize(macho_file: *MachO, unwind_info: *const UnwindInfo) !void {
32pub fn calcSectionSize(macho_file: *MachO, unwind_info: *const UnwindInfo) error{OutOfMemory}!void {
3333 const sect_id = macho_file.eh_frame_section_index orelse return;
3434 const sect = &macho_file.sections.items(.header)[sect_id];
3535 sect.@"align" = 3;
......@@ -59,7 +59,7 @@ pub fn calcSectionSize(macho_file: *MachO, unwind_info: *const UnwindInfo) !void
5959 if (!is_dwarf) continue;
6060
6161 eh_it.seekTo(fde_record_offset);
62 const source_fde_record = (try eh_it.next()).?;
62 const source_fde_record = (eh_it.next() catch continue).?; // We already handled this error
6363
6464 const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), macho_file, fde_record_offset);
6565 const cie_offset = fde_record_offset + 4 - cie_ptr;
......@@ -67,7 +67,7 @@ pub fn calcSectionSize(macho_file: *MachO, unwind_info: *const UnwindInfo) !void
6767 const gop = try cies.getOrPut(cie_offset);
6868 if (!gop.found_existing) {
6969 eh_it.seekTo(cie_offset);
70 const source_cie_record = (try eh_it.next()).?;
70 const source_cie_record = (eh_it.next() catch continue).?; // We already handled this error
7171 gop.value_ptr.* = size;
7272 size += source_cie_record.getSize();
7373 }
......@@ -121,7 +121,7 @@ pub fn write(macho_file: *MachO, unwind_info: *UnwindInfo) !void {
121121 if (!is_dwarf) continue;
122122
123123 eh_it.seekTo(fde_record_offset);
124 const source_fde_record = (try eh_it.next()).?;
124 const source_fde_record = (eh_it.next() catch continue).?; // We already handled this error
125125
126126 const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), macho_file, fde_record_offset);
127127 const cie_offset = fde_record_offset + 4 - cie_ptr;
......@@ -129,7 +129,7 @@ pub fn write(macho_file: *MachO, unwind_info: *UnwindInfo) !void {
129129 const gop = try cies.getOrPut(cie_offset);
130130 if (!gop.found_existing) {
131131 eh_it.seekTo(cie_offset);
132 const source_cie_record = (try eh_it.next()).?;
132 const source_cie_record = (eh_it.next() catch continue).?; // We already handled this error
133133 var cie_record = try source_cie_record.toOwned(gpa);
134134 try cie_record.relocate(macho_file, @as(u32, @intCast(object_id)), .{
135135 .source_offset = cie_offset,
......@@ -164,17 +164,17 @@ pub fn write(macho_file: *MachO, unwind_info: *UnwindInfo) !void {
164164 eh_frame_offset + 4 - fde_record.getCiePointer(),
165165 ).?;
166166 const eh_frame_sect = object.getSourceSection(object.eh_frame_sect_id.?);
167 const source_lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{
167 const source_lsda_ptr = fde_record.getLsdaPointer(cie_record, .{
168168 .base_addr = eh_frame_sect.addr,
169169 .base_offset = fde_record_offset,
170 });
170 }) catch continue; // We already handled this error
171171 if (source_lsda_ptr) |ptr| {
172172 const sym_index = object.getSymbolByAddress(ptr, null);
173173 const sym = object.symtab[sym_index];
174 try fde_record.setLsdaPointer(cie_record, sym.n_value, .{
174 fde_record.setLsdaPointer(cie_record, sym.n_value, .{
175175 .base_addr = sect.addr,
176176 .base_offset = eh_frame_offset,
177 });
177 }) catch continue; // We already handled this error
178178 }
179179 },
180180 else => unreachable,
......@@ -191,10 +191,10 @@ pub fn write(macho_file: *MachO, unwind_info: *UnwindInfo) !void {
191191 const cie_record = eh_records.get(
192192 eh_frame_offset + 4 - fde_record.getCiePointer(),
193193 ).?;
194 const lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{
194 const lsda_ptr = fde_record.getLsdaPointer(cie_record, .{
195195 .base_addr = sect.addr,
196196 .base_offset = eh_frame_offset,
197 });
197 }) catch continue; // We already handled this error
198198 if (lsda_ptr) |ptr| {
199199 record.lsda = ptr - seg.vmaddr;
200200 }
......@@ -588,7 +588,7 @@ pub const Iterator = struct {
588588
589589 var size = try reader.readIntLittle(u32);
590590 if (size == 0xFFFFFFFF) {
591 log.err("MachO doesn't support 64bit DWARF CFI __eh_frame records", .{});
591 log.debug("MachO doesn't support 64bit DWARF CFI __eh_frame records", .{});
592592 return error.BadDwarfCfi;
593593 }
594594
src/link/MachO/zld.zig+14-2
......@@ -388,7 +388,19 @@ pub fn linkWithZld(
388388 }
389389
390390 for (macho_file.objects.items, 0..) |*object, object_id| {
391 try object.splitIntoAtoms(macho_file, @as(u32, @intCast(object_id)));
391 object.splitIntoAtoms(macho_file, @as(u32, @intCast(object_id))) catch |err| switch (err) {
392 error.MissingEhFrameSection => try macho_file.reportParseError(
393 object.name,
394 "missing section: '__TEXT,__eh_frame' is required but could not be found",
395 .{},
396 ),
397 error.BadDwarfCfi => try macho_file.reportParseError(
398 object.name,
399 "invalid DWARF: failed to parse '__TEXT,__eh_frame' section",
400 .{},
401 ),
402 else => |e| return e,
403 };
392404 }
393405
394406 if (gc_sections) {
......@@ -433,7 +445,7 @@ pub fn linkWithZld(
433445 try unwind_info.collect(macho_file);
434446
435447 try eh_frame.calcSectionSize(macho_file, &unwind_info);
436 try unwind_info.calcSectionSize(macho_file);
448 unwind_info.calcSectionSize(macho_file);
437449
438450 try pruneAndSortSections(macho_file);
439451 try createSegments(macho_file);