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 {...@@ -1862,14 +1862,14 @@ fn initSyntheticSections(self: *MachO) !void {
1862 }1862 }
18631863
1864 const needs_unwind_info = for (self.objects.items) |index| {1864 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;
1866 } else false;1866 } else false;
1867 if (needs_unwind_info) {1867 if (needs_unwind_info) {
1868 self.unwind_info_sect_index = try self.addSection("__TEXT", "__unwind_info", .{});1868 self.unwind_info_sect_index = try self.addSection("__TEXT", "__unwind_info", .{});
1869 }1869 }
18701870
1871 const needs_eh_frame = for (self.objects.items) |index| {1871 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;
1873 } else false;1873 } else false;
1874 if (needs_eh_frame) {1874 if (needs_eh_frame) {
1875 assert(needs_unwind_info);1875 assert(needs_unwind_info);
src/link/MachO/Object.zig+39-31
...@@ -164,6 +164,10 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -164,6 +164,10 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
164 try self.initUnwindRecords(index, macho_file);164 try self.initUnwindRecords(index, macho_file);
165 }165 }
166166
167 if (self.hasUnwindRecords() or self.hasEhFrameRecords()) {
168 try self.parseUnwindRecords(macho_file);
169 }
170
167 self.initPlatform();171 self.initPlatform();
168172
169 if (self.platform) |platform| {173 if (self.platform) |platform| {
...@@ -816,36 +820,9 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {...@@ -816,36 +820,9 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
816 }820 }
817 }821 }
818 }822 }
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 }
846}823}
847824
848fn synthesiseNullUnwindRecords(self: *Object, macho_file: *MachO) !void {825fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
849 // Synthesise missing unwind records.826 // Synthesise missing unwind records.
850 // The logic here is as follows:827 // The logic here is as follows:
851 // 1. if an atom has unwind info record that is not DWARF, FDE is marked dead828 // 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 {...@@ -902,12 +879,10 @@ fn synthesiseNullUnwindRecords(self: *Object, macho_file: *MachO) !void {
902 }879 }
903 } else {880 } else {
904 // Synthesise new unwind info record881 // 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);
907 const rec_index = try macho_file.addUnwindRecord();882 const rec_index = try macho_file.addUnwindRecord();
908 const rec = macho_file.getUnwindRecord(rec_index);883 const rec = macho_file.getUnwindRecord(rec_index);
909 try self.unwind_records.append(gpa, rec_index);884 try self.unwind_records.append(gpa, rec_index);
910 rec.length = @intCast(atom_size);885 rec.length = @intCast(meta.size);
911 rec.atom = fde.atom;886 rec.atom = fde.atom;
912 rec.atom_offset = fde.atom_offset;887 rec.atom_offset = fde.atom_offset;
913 rec.fde = fde_index;888 rec.fde = fde_index;
...@@ -930,6 +905,31 @@ fn synthesiseNullUnwindRecords(self: *Object, macho_file: *MachO) !void {...@@ -930,6 +905,31 @@ fn synthesiseNullUnwindRecords(self: *Object, macho_file: *MachO) !void {
930 rec.file = self.index;905 rec.file = self.index;
931 }906 }
932 }907 }
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 }
933}933}
934934
935fn initPlatform(self: *Object) void {935fn initPlatform(self: *Object) void {
...@@ -1566,6 +1566,14 @@ fn getString(self: Object, off: u32) [:0]const u8 {...@@ -1566,6 +1566,14 @@ fn getString(self: Object, off: u32) [:0]const u8 {
1566 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);1566 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);
1567}1567}
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
1569/// TODO handle multiple CUs1577/// TODO handle multiple CUs
1570pub fn hasDebugInfo(self: Object) bool {1578pub fn hasDebugInfo(self: Object) bool {
1571 if (self.dwarf_info) |dw| {1579 if (self.dwarf_info) |dw| {
src/link/MachO/relocatable.zig+2-2
...@@ -143,7 +143,7 @@ fn initOutputSections(macho_file: *MachO) !void {...@@ -143,7 +143,7 @@ fn initOutputSections(macho_file: *MachO) !void {
143 }143 }
144144
145 const needs_unwind_info = for (macho_file.objects.items) |index| {145 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;
147 } else false;147 } else false;
148 if (needs_unwind_info) {148 if (needs_unwind_info) {
149 macho_file.unwind_info_sect_index = try macho_file.addSection("__LD", "__compact_unwind", .{149 macho_file.unwind_info_sect_index = try macho_file.addSection("__LD", "__compact_unwind", .{
...@@ -152,7 +152,7 @@ fn initOutputSections(macho_file: *MachO) !void {...@@ -152,7 +152,7 @@ fn initOutputSections(macho_file: *MachO) !void {
152 }152 }
153153
154 const needs_eh_frame = for (macho_file.objects.items) |index| {154 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;
156 } else false;156 } else false;
157 if (needs_eh_frame) {157 if (needs_eh_frame) {
158 assert(needs_unwind_info);158 assert(needs_unwind_info);