| ... | ... | @@ -634,8 +634,9 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 634 | 634 | } |
| 635 | 635 | } |
| 636 | 636 | |
| 637 | | try self.writeLinkeditSegment(); |
| 638 | 637 | self.updateDwarfSegment(); |
| 638 | try self.writeLinkeditSegment(); |
| 639 | try self.updateVirtualMemoryMapping(); |
| 639 | 640 | try self.writeLoadCommands(allocator); |
| 640 | 641 | try self.writeHeader(); |
| 641 | 642 | |
| ... | ... | @@ -706,10 +707,25 @@ fn copySegmentCommand( |
| 706 | 707 | |
| 707 | 708 | fn updateDwarfSegment(self: *DebugSymbols) void { |
| 708 | 709 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 709 | | var file_size: u64 = 0; |
| 710 | |
| 711 | var max_offset: u64 = 0; |
| 710 | 712 | for (dwarf_segment.sections.items) |sect| { |
| 711 | | file_size += sect.size; |
| 713 | log.debug(" {s},{s} - 0x{x}-0x{x} - 0x{x}-0x{x}", .{ |
| 714 | sect.segName(), |
| 715 | sect.sectName(), |
| 716 | sect.offset, |
| 717 | sect.offset + sect.size, |
| 718 | sect.addr, |
| 719 | sect.addr + sect.size, |
| 720 | }); |
| 721 | if (sect.offset + sect.size > max_offset) { |
| 722 | max_offset = sect.offset + sect.size; |
| 723 | } |
| 712 | 724 | } |
| 725 | |
| 726 | const file_size = max_offset - dwarf_segment.inner.fileoff; |
| 727 | log.debug("__DWARF size 0x{x}", .{file_size}); |
| 728 | |
| 713 | 729 | if (file_size != dwarf_segment.inner.filesize) { |
| 714 | 730 | dwarf_segment.inner.filesize = file_size; |
| 715 | 731 | if (dwarf_segment.inner.vmsize < dwarf_segment.inner.filesize) { |
| ... | ... | @@ -780,15 +796,59 @@ fn allocatedSize(self: *DebugSymbols, start: u64) u64 { |
| 780 | 796 | return min_pos - start; |
| 781 | 797 | } |
| 782 | 798 | |
| 799 | fn updateVirtualMemoryMapping(self: *DebugSymbols) !void { |
| 800 | const macho_file = self.base; |
| 801 | const allocator = macho_file.base.allocator; |
| 802 | |
| 803 | const IndexTuple = std.meta.Tuple(&[_]type{ *?u16, *?u16 }); |
| 804 | const indices = &[_]IndexTuple{ |
| 805 | .{ &macho_file.text_segment_cmd_index, &self.text_segment_cmd_index }, |
| 806 | .{ &macho_file.data_const_segment_cmd_index, &self.data_const_segment_cmd_index }, |
| 807 | .{ &macho_file.data_segment_cmd_index, &self.data_segment_cmd_index }, |
| 808 | }; |
| 809 | |
| 810 | for (indices) |tuple| { |
| 811 | const orig_cmd = macho_file.load_commands.items[tuple[0].*.?].segment; |
| 812 | const cmd = try self.copySegmentCommand(allocator, orig_cmd); |
| 813 | const comp_cmd = &self.load_commands.items[tuple[1].*.?]; |
| 814 | comp_cmd.deinit(allocator); |
| 815 | self.load_commands.items[tuple[1].*.?] = .{ .segment = cmd }; |
| 816 | } |
| 817 | |
| 818 | // TODO should we set the linkedit vmsize to that of the binary? |
| 819 | const orig_cmd = macho_file.load_commands.items[macho_file.linkedit_segment_cmd_index.?].segment; |
| 820 | const orig_vmaddr = orig_cmd.inner.vmaddr; |
| 821 | const linkedit_cmd = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 822 | linkedit_cmd.inner.vmaddr = orig_vmaddr; |
| 823 | |
| 824 | // Update VM address for the DWARF segment and sections including re-running relocations. |
| 825 | // TODO re-run relocations |
| 826 | const dwarf_cmd = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 827 | const new_start_aligned = orig_vmaddr + linkedit_cmd.inner.vmsize; |
| 828 | const old_start_aligned = dwarf_cmd.inner.vmaddr; |
| 829 | const diff = new_start_aligned - old_start_aligned; |
| 830 | if (diff > 0) { |
| 831 | dwarf_cmd.inner.vmaddr = new_start_aligned; |
| 832 | |
| 833 | for (dwarf_cmd.sections.items) |*sect| { |
| 834 | sect.addr += (new_start_aligned - old_start_aligned); |
| 835 | } |
| 836 | } |
| 837 | |
| 838 | self.load_commands_dirty = true; |
| 839 | } |
| 840 | |
| 783 | 841 | fn writeLinkeditSegment(self: *DebugSymbols) !void { |
| 784 | 842 | const tracy = trace(@src()); |
| 785 | 843 | defer tracy.end(); |
| 786 | 844 | |
| 787 | | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 788 | | seg.inner.filesize = 0; |
| 789 | | |
| 790 | 845 | try self.writeSymbolTable(); |
| 791 | 846 | try self.writeStringTable(); |
| 847 | |
| 848 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 849 | const aligned_size = mem.alignForwardGeneric(u64, seg.inner.filesize, self.base.page_size); |
| 850 | seg.inner.filesize = aligned_size; |
| 851 | seg.inner.vmsize = aligned_size; |
| 792 | 852 | } |
| 793 | 853 | |
| 794 | 854 | fn writeSymbolTable(self: *DebugSymbols) !void { |
| ... | ... | @@ -797,7 +857,7 @@ fn writeSymbolTable(self: *DebugSymbols) !void { |
| 797 | 857 | |
| 798 | 858 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 799 | 859 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; |
| 800 | | symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 860 | symtab.symoff = @intCast(u32, seg.inner.fileoff); |
| 801 | 861 | |
| 802 | 862 | var locals = std.ArrayList(macho.nlist_64).init(self.base.base.allocator); |
| 803 | 863 | defer locals.deinit(); |
| ... | ... | @@ -810,20 +870,52 @@ fn writeSymbolTable(self: *DebugSymbols) !void { |
| 810 | 870 | |
| 811 | 871 | const nlocals = locals.items.len; |
| 812 | 872 | const nexports = self.base.globals.items.len; |
| 813 | | |
| 814 | 873 | const locals_off = symtab.symoff; |
| 815 | 874 | const locals_size = nlocals * @sizeOf(macho.nlist_64); |
| 875 | const exports_off = locals_off + locals_size; |
| 876 | const exports_size = nexports * @sizeOf(macho.nlist_64); |
| 877 | |
| 878 | symtab.nsyms = @intCast(u32, nlocals + nexports); |
| 879 | const needed_size = (nlocals + nexports) * @sizeOf(macho.nlist_64); |
| 880 | |
| 881 | if (needed_size > seg.inner.filesize) { |
| 882 | const aligned_size = mem.alignForwardGeneric(u64, needed_size, self.base.page_size); |
| 883 | const diff = @intCast(u32, aligned_size - seg.inner.filesize); |
| 884 | const dwarf_seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 885 | seg.inner.filesize = aligned_size; |
| 886 | |
| 887 | try MachO.copyRangeAllOverlappingAlloc( |
| 888 | self.base.base.allocator, |
| 889 | self.file, |
| 890 | dwarf_seg.inner.fileoff, |
| 891 | dwarf_seg.inner.fileoff + diff, |
| 892 | try math.cast(usize, dwarf_seg.inner.filesize), |
| 893 | ); |
| 894 | |
| 895 | const old_seg_fileoff = dwarf_seg.inner.fileoff; |
| 896 | dwarf_seg.inner.fileoff += diff; |
| 897 | |
| 898 | log.debug(" (moving __DWARF segment from 0x{x} to 0x{x})", .{ old_seg_fileoff, dwarf_seg.inner.fileoff }); |
| 899 | |
| 900 | for (dwarf_seg.sections.items) |*sect| { |
| 901 | const old_offset = sect.offset; |
| 902 | sect.offset += diff; |
| 903 | |
| 904 | log.debug(" (moving {s},{s} from 0x{x} to 0x{x})", .{ |
| 905 | sect.segName(), |
| 906 | sect.sectName(), |
| 907 | old_offset, |
| 908 | sect.offset, |
| 909 | }); |
| 910 | } |
| 911 | } |
| 912 | |
| 816 | 913 | log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off }); |
| 817 | 914 | try self.file.pwriteAll(mem.sliceAsBytes(locals.items), locals_off); |
| 818 | 915 | |
| 819 | | const exports_off = locals_off + locals_size; |
| 820 | | const exports_size = nexports * @sizeOf(macho.nlist_64); |
| 821 | 916 | log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off }); |
| 822 | 917 | try self.file.pwriteAll(mem.sliceAsBytes(self.base.globals.items), exports_off); |
| 823 | 918 | |
| 824 | | symtab.nsyms = @intCast(u32, nlocals + nexports); |
| 825 | | seg.inner.filesize += locals_size + exports_size; |
| 826 | | |
| 827 | 919 | self.load_commands_dirty = true; |
| 828 | 920 | } |
| 829 | 921 | |
| ... | ... | @@ -833,18 +925,48 @@ fn writeStringTable(self: *DebugSymbols) !void { |
| 833 | 925 | |
| 834 | 926 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 835 | 927 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; |
| 836 | | symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 837 | | symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64))); |
| 838 | | seg.inner.filesize += symtab.strsize; |
| 928 | const symtab_size = @intCast(u32, symtab.nsyms * @sizeOf(macho.nlist_64)); |
| 929 | symtab.stroff = symtab.symoff + symtab_size; |
| 930 | |
| 931 | const needed_size = mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64)); |
| 932 | symtab.strsize = @intCast(u32, needed_size); |
| 933 | |
| 934 | if (symtab_size + needed_size > seg.inner.filesize) { |
| 935 | const aligned_size = mem.alignForwardGeneric(u64, symtab_size + needed_size, self.base.page_size); |
| 936 | const diff = @intCast(u32, aligned_size - seg.inner.filesize); |
| 937 | const dwarf_seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 938 | seg.inner.filesize = aligned_size; |
| 939 | |
| 940 | try MachO.copyRangeAllOverlappingAlloc( |
| 941 | self.base.base.allocator, |
| 942 | self.file, |
| 943 | dwarf_seg.inner.fileoff, |
| 944 | dwarf_seg.inner.fileoff + diff, |
| 945 | try math.cast(usize, dwarf_seg.inner.filesize), |
| 946 | ); |
| 947 | |
| 948 | const old_seg_fileoff = dwarf_seg.inner.fileoff; |
| 949 | dwarf_seg.inner.fileoff += diff; |
| 950 | |
| 951 | log.debug(" (moving __DWARF segment from 0x{x} to 0x{x})", .{ old_seg_fileoff, dwarf_seg.inner.fileoff }); |
| 952 | |
| 953 | for (dwarf_seg.sections.items) |*sect| { |
| 954 | const old_offset = sect.offset; |
| 955 | sect.offset += diff; |
| 956 | |
| 957 | log.debug(" (moving {s},{s} from 0x{x} to 0x{x})", .{ |
| 958 | sect.segName(), |
| 959 | sect.sectName(), |
| 960 | old_offset, |
| 961 | sect.offset, |
| 962 | }); |
| 963 | } |
| 964 | } |
| 839 | 965 | |
| 840 | 966 | log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize }); |
| 841 | 967 | |
| 842 | 968 | try self.file.pwriteAll(self.base.strtab.items, symtab.stroff); |
| 843 | 969 | |
| 844 | | if (symtab.strsize > self.base.strtab.items.len) { |
| 845 | | // This is potentially the last section, so we need to pad it out. |
| 846 | | try self.file.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1); |
| 847 | | } |
| 848 | 970 | self.load_commands_dirty = true; |
| 849 | 971 | } |
| 850 | 972 | |
| ... | ... | @@ -1088,8 +1210,14 @@ pub fn commitDeclDebugInfo( |
| 1088 | 1210 | new_offset, |
| 1089 | 1211 | }); |
| 1090 | 1212 | |
| 1091 | | const amt = try self.file.copyRangeAll(debug_line_sect.offset, self.file, new_offset, existing_size); |
| 1092 | | if (amt != existing_size) return error.InputOutput; |
| 1213 | try MachO.copyRangeAllOverlappingAlloc( |
| 1214 | self.base.base.allocator, |
| 1215 | self.file, |
| 1216 | debug_line_sect.offset, |
| 1217 | new_offset, |
| 1218 | existing_size, |
| 1219 | ); |
| 1220 | |
| 1093 | 1221 | debug_line_sect.offset = @intCast(u32, new_offset); |
| 1094 | 1222 | debug_line_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff; |
| 1095 | 1223 | } |
| ... | ... | @@ -1390,8 +1518,14 @@ fn writeDeclDebugInfo(self: *DebugSymbols, text_block: *TextBlock, dbg_info_buf: |
| 1390 | 1518 | new_offset, |
| 1391 | 1519 | }); |
| 1392 | 1520 | |
| 1393 | | const amt = try self.file.copyRangeAll(debug_info_sect.offset, self.file, new_offset, existing_size); |
| 1394 | | if (amt != existing_size) return error.InputOutput; |
| 1521 | try MachO.copyRangeAllOverlappingAlloc( |
| 1522 | self.base.base.allocator, |
| 1523 | self.file, |
| 1524 | debug_info_sect.offset, |
| 1525 | new_offset, |
| 1526 | existing_size, |
| 1527 | ); |
| 1528 | |
| 1395 | 1529 | debug_info_sect.offset = @intCast(u32, new_offset); |
| 1396 | 1530 | debug_info_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff; |
| 1397 | 1531 | } |