authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-22 13:29:53+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-24 12:34:42+01:00
log82628dd151c15241cffd17884ed5124808dc4ed2
tree75a7da2bdf55c2c0f0863cb1e61c54b5857c2e46
parentfe19d1e09b283c8f09afa49abb0f3835fdc40aaa

macho: synthesise unwind records from __eh_frame even if no __compact_unwind


3 files changed, 43 insertions(+), 35 deletions(-)

src/link/MachO.zig+2-2
......@@ -1862,14 +1862,14 @@ fn initSyntheticSections(self: *MachO) !void {
18621862 }
18631863
18641864 const needs_unwind_info = for (self.objects.items) |index| {
1865 if (self.getFile(index).?.object.compact_unwind_sect_index != null) break true;
1865 if (self.getFile(index).?.object.hasUnwindRecords()) break true;
18661866 } else false;
18671867 if (needs_unwind_info) {
18681868 self.unwind_info_sect_index = try self.addSection("__TEXT", "__unwind_info", .{});
18691869 }
18701870
18711871 const needs_eh_frame = for (self.objects.items) |index| {
1872 if (self.getFile(index).?.object.eh_frame_sect_index != null) break true;
1872 if (self.getFile(index).?.object.hasEhFrameRecords()) break true;
18731873 } else false;
18741874 if (needs_eh_frame) {
18751875 assert(needs_unwind_info);
src/link/MachO/Object.zig+39-31
......@@ -164,6 +164,10 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
164164 try self.initUnwindRecords(index, macho_file);
165165 }
166166
167 if (self.hasUnwindRecords() or self.hasEhFrameRecords()) {
168 try self.parseUnwindRecords(macho_file);
169 }
170
167171 self.initPlatform();
168172
169173 if (self.platform) |platform| {
......@@ -816,36 +820,9 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
816820 }
817821 }
818822 }
819
820 if (!macho_file.base.isObject()) try self.synthesiseNullUnwindRecords(macho_file);
821
822 const sortFn = struct {
823 fn sortFn(ctx: *MachO, lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool {
824 const lhs = ctx.getUnwindRecord(lhs_index);
825 const rhs = ctx.getUnwindRecord(rhs_index);
826 const lhsa = lhs.getAtom(ctx);
827 const rhsa = rhs.getAtom(ctx);
828 return lhsa.getInputAddress(ctx) + lhs.atom_offset < rhsa.getInputAddress(ctx) + rhs.atom_offset;
829 }
830 }.sortFn;
831 mem.sort(UnwindInfo.Record.Index, self.unwind_records.items, macho_file, sortFn);
832
833 // Associate unwind records to atoms
834 var next_cu: u32 = 0;
835 while (next_cu < self.unwind_records.items.len) {
836 const start = next_cu;
837 const rec_index = self.unwind_records.items[start];
838 const rec = macho_file.getUnwindRecord(rec_index);
839 while (next_cu < self.unwind_records.items.len and
840 macho_file.getUnwindRecord(self.unwind_records.items[next_cu]).atom == rec.atom) : (next_cu += 1)
841 {}
842
843 const atom = rec.getAtom(macho_file);
844 atom.unwind_records = .{ .pos = start, .len = next_cu - start };
845 }
846823}
847824
848fn synthesiseNullUnwindRecords(self: *Object, macho_file: *MachO) !void {
825fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
849826 // Synthesise missing unwind records.
850827 // The logic here is as follows:
851828 // 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 {
902879 }
903880 } else {
904881 // Synthesise new unwind info record
905 const fde_data = fde.getData(macho_file);
906 const atom_size = mem.readInt(u64, fde_data[16..][0..8], .little);
907882 const rec_index = try macho_file.addUnwindRecord();
908883 const rec = macho_file.getUnwindRecord(rec_index);
909884 try self.unwind_records.append(gpa, rec_index);
910 rec.length = @intCast(atom_size);
885 rec.length = @intCast(meta.size);
911886 rec.atom = fde.atom;
912887 rec.atom_offset = fde.atom_offset;
913888 rec.fde = fde_index;
......@@ -930,6 +905,31 @@ fn synthesiseNullUnwindRecords(self: *Object, macho_file: *MachO) !void {
930905 rec.file = self.index;
931906 }
932907 }
908
909 const sortFn = struct {
910 fn sortFn(ctx: *MachO, lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool {
911 const lhs = ctx.getUnwindRecord(lhs_index);
912 const rhs = ctx.getUnwindRecord(rhs_index);
913 const lhsa = lhs.getAtom(ctx);
914 const rhsa = rhs.getAtom(ctx);
915 return lhsa.getInputAddress(ctx) + lhs.atom_offset < rhsa.getInputAddress(ctx) + rhs.atom_offset;
916 }
917 }.sortFn;
918 mem.sort(UnwindInfo.Record.Index, self.unwind_records.items, macho_file, sortFn);
919
920 // Associate unwind records to atoms
921 var next_cu: u32 = 0;
922 while (next_cu < self.unwind_records.items.len) {
923 const start = next_cu;
924 const rec_index = self.unwind_records.items[start];
925 const rec = macho_file.getUnwindRecord(rec_index);
926 while (next_cu < self.unwind_records.items.len and
927 macho_file.getUnwindRecord(self.unwind_records.items[next_cu]).atom == rec.atom) : (next_cu += 1)
928 {}
929
930 const atom = rec.getAtom(macho_file);
931 atom.unwind_records = .{ .pos = start, .len = next_cu - start };
932 }
933933}
934934
935935fn initPlatform(self: *Object) void {
......@@ -1566,6 +1566,14 @@ fn getString(self: Object, off: u32) [:0]const u8 {
15661566 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);
15671567}
15681568
1569pub fn hasUnwindRecords(self: Object) bool {
1570 return self.unwind_records.items.len > 0;
1571}
1572
1573pub fn hasEhFrameRecords(self: Object) bool {
1574 return self.cies.items.len > 0;
1575}
1576
15691577/// TODO handle multiple CUs
15701578pub fn hasDebugInfo(self: Object) bool {
15711579 if (self.dwarf_info) |dw| {
src/link/MachO/relocatable.zig+2-2
......@@ -143,7 +143,7 @@ fn initOutputSections(macho_file: *MachO) !void {
143143 }
144144
145145 const needs_unwind_info = for (macho_file.objects.items) |index| {
146 if (macho_file.getFile(index).?.object.compact_unwind_sect_index != null) break true;
146 if (macho_file.getFile(index).?.object.hasUnwindRecords()) break true;
147147 } else false;
148148 if (needs_unwind_info) {
149149 macho_file.unwind_info_sect_index = try macho_file.addSection("__LD", "__compact_unwind", .{
......@@ -152,7 +152,7 @@ fn initOutputSections(macho_file: *MachO) !void {
152152 }
153153
154154 const needs_eh_frame = for (macho_file.objects.items) |index| {
155 if (macho_file.getFile(index).?.object.eh_frame_sect_index != null) break true;
155 if (macho_file.getFile(index).?.object.hasEhFrameRecords()) break true;
156156 } else false;
157157 if (needs_eh_frame) {
158158 assert(needs_unwind_info);