Commit 82628dd151

Jakub Konka <kubkon@jakubkonka.com>
2024-01-22 13:29:53
macho: synthesise unwind records from __eh_frame even if no __compact_unwind
1 parent fe19d1e
Changed files (3)
src/link/MachO/Object.zig
@@ -164,6 +164,10 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
         try self.initUnwindRecords(index, macho_file);
     }
 
+    if (self.hasUnwindRecords() or self.hasEhFrameRecords()) {
+        try self.parseUnwindRecords(macho_file);
+    }
+
     self.initPlatform();
 
     if (self.platform) |platform| {
@@ -816,36 +820,9 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
             }
         }
     }
-
-    if (!macho_file.base.isObject()) try self.synthesiseNullUnwindRecords(macho_file);
-
-    const sortFn = struct {
-        fn sortFn(ctx: *MachO, lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool {
-            const lhs = ctx.getUnwindRecord(lhs_index);
-            const rhs = ctx.getUnwindRecord(rhs_index);
-            const lhsa = lhs.getAtom(ctx);
-            const rhsa = rhs.getAtom(ctx);
-            return lhsa.getInputAddress(ctx) + lhs.atom_offset < rhsa.getInputAddress(ctx) + rhs.atom_offset;
-        }
-    }.sortFn;
-    mem.sort(UnwindInfo.Record.Index, self.unwind_records.items, macho_file, sortFn);
-
-    // Associate unwind records to atoms
-    var next_cu: u32 = 0;
-    while (next_cu < self.unwind_records.items.len) {
-        const start = next_cu;
-        const rec_index = self.unwind_records.items[start];
-        const rec = macho_file.getUnwindRecord(rec_index);
-        while (next_cu < self.unwind_records.items.len and
-            macho_file.getUnwindRecord(self.unwind_records.items[next_cu]).atom == rec.atom) : (next_cu += 1)
-        {}
-
-        const atom = rec.getAtom(macho_file);
-        atom.unwind_records = .{ .pos = start, .len = next_cu - start };
-    }
 }
 
-fn synthesiseNullUnwindRecords(self: *Object, macho_file: *MachO) !void {
+fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
     // Synthesise missing unwind records.
     // The logic here is as follows:
     // 1. if an atom has unwind info record that is not DWARF, FDE is marked dead
@@ -902,12 +879,10 @@ fn synthesiseNullUnwindRecords(self: *Object, macho_file: *MachO) !void {
                 }
             } else {
                 // Synthesise new unwind info record
-                const fde_data = fde.getData(macho_file);
-                const atom_size = mem.readInt(u64, fde_data[16..][0..8], .little);
                 const rec_index = try macho_file.addUnwindRecord();
                 const rec = macho_file.getUnwindRecord(rec_index);
                 try self.unwind_records.append(gpa, rec_index);
-                rec.length = @intCast(atom_size);
+                rec.length = @intCast(meta.size);
                 rec.atom = fde.atom;
                 rec.atom_offset = fde.atom_offset;
                 rec.fde = fde_index;
@@ -930,6 +905,31 @@ fn synthesiseNullUnwindRecords(self: *Object, macho_file: *MachO) !void {
             rec.file = self.index;
         }
     }
+
+    const sortFn = struct {
+        fn sortFn(ctx: *MachO, lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool {
+            const lhs = ctx.getUnwindRecord(lhs_index);
+            const rhs = ctx.getUnwindRecord(rhs_index);
+            const lhsa = lhs.getAtom(ctx);
+            const rhsa = rhs.getAtom(ctx);
+            return lhsa.getInputAddress(ctx) + lhs.atom_offset < rhsa.getInputAddress(ctx) + rhs.atom_offset;
+        }
+    }.sortFn;
+    mem.sort(UnwindInfo.Record.Index, self.unwind_records.items, macho_file, sortFn);
+
+    // Associate unwind records to atoms
+    var next_cu: u32 = 0;
+    while (next_cu < self.unwind_records.items.len) {
+        const start = next_cu;
+        const rec_index = self.unwind_records.items[start];
+        const rec = macho_file.getUnwindRecord(rec_index);
+        while (next_cu < self.unwind_records.items.len and
+            macho_file.getUnwindRecord(self.unwind_records.items[next_cu]).atom == rec.atom) : (next_cu += 1)
+        {}
+
+        const atom = rec.getAtom(macho_file);
+        atom.unwind_records = .{ .pos = start, .len = next_cu - start };
+    }
 }
 
 fn initPlatform(self: *Object) void {
@@ -1566,6 +1566,14 @@ fn getString(self: Object, off: u32) [:0]const u8 {
     return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);
 }
 
+pub fn hasUnwindRecords(self: Object) bool {
+    return self.unwind_records.items.len > 0;
+}
+
+pub fn hasEhFrameRecords(self: Object) bool {
+    return self.cies.items.len > 0;
+}
+
 /// TODO handle multiple CUs
 pub fn hasDebugInfo(self: Object) bool {
     if (self.dwarf_info) |dw| {
src/link/MachO/relocatable.zig
@@ -143,7 +143,7 @@ fn initOutputSections(macho_file: *MachO) !void {
     }
 
     const needs_unwind_info = for (macho_file.objects.items) |index| {
-        if (macho_file.getFile(index).?.object.compact_unwind_sect_index != null) break true;
+        if (macho_file.getFile(index).?.object.hasUnwindRecords()) break true;
     } else false;
     if (needs_unwind_info) {
         macho_file.unwind_info_sect_index = try macho_file.addSection("__LD", "__compact_unwind", .{
@@ -152,7 +152,7 @@ fn initOutputSections(macho_file: *MachO) !void {
     }
 
     const needs_eh_frame = for (macho_file.objects.items) |index| {
-        if (macho_file.getFile(index).?.object.eh_frame_sect_index != null) break true;
+        if (macho_file.getFile(index).?.object.hasEhFrameRecords()) break true;
     } else false;
     if (needs_eh_frame) {
         assert(needs_unwind_info);
src/link/MachO.zig
@@ -1862,14 +1862,14 @@ fn initSyntheticSections(self: *MachO) !void {
     }
 
     const needs_unwind_info = for (self.objects.items) |index| {
-        if (self.getFile(index).?.object.compact_unwind_sect_index != null) break true;
+        if (self.getFile(index).?.object.hasUnwindRecords()) break true;
     } else false;
     if (needs_unwind_info) {
         self.unwind_info_sect_index = try self.addSection("__TEXT", "__unwind_info", .{});
     }
 
     const needs_eh_frame = for (self.objects.items) |index| {
-        if (self.getFile(index).?.object.eh_frame_sect_index != null) break true;
+        if (self.getFile(index).?.object.hasEhFrameRecords()) break true;
     } else false;
     if (needs_eh_frame) {
         assert(needs_unwind_info);