| ... | ... | @@ -94,6 +94,15 @@ pub const abbrev_base_type = 4; |
| 94 | 94 | pub const abbrev_pad1 = 5; |
| 95 | 95 | pub const abbrev_parameter = 6; |
| 96 | 96 | |
| 97 | /// The reloc offset for the virtual address of a function in its Line Number Program. |
| 98 | /// Size is a virtual address integer. |
| 99 | pub const dbg_line_vaddr_reloc_index = 3; |
| 100 | /// The reloc offset for the virtual address of a function in its .debug_info TAG_subprogram. |
| 101 | /// Size is a virtual address integer. |
| 102 | pub const dbg_info_low_pc_reloc_index = 1; |
| 103 | |
| 104 | pub const min_nop_size = 2; |
| 105 | |
| 97 | 106 | /// You must call this function *after* `MachO.populateMissingMetadata()` |
| 98 | 107 | /// has been called to get a viable debug symbols output. |
| 99 | 108 | pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void { |
| ... | ... | @@ -469,7 +478,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: *Allocator, options: link.Opt |
| 469 | 478 | |
| 470 | 479 | if (di_buf.items.len > first_dbg_info_decl.dbg_info_off) { |
| 471 | 480 | // Move the first N decls to the end to make more padding for the header. |
| 472 | | @panic("TODO: handle __zdebug_info header exceeding its padding"); |
| 481 | @panic("TODO: handle __debug_info header exceeding its padding"); |
| 473 | 482 | } |
| 474 | 483 | const jmp_amt = first_dbg_info_decl.dbg_info_off - di_buf.items.len; |
| 475 | 484 | try self.pwriteDbgInfoNops(0, di_buf.items, jmp_amt, false, debug_info_sect.offset); |
| ... | ... | @@ -648,16 +657,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: *Allocator, options: link.Opt |
| 648 | 657 | } |
| 649 | 658 | |
| 650 | 659 | try self.writeStringTable(); |
| 651 | | |
| 652 | | { |
| 653 | | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; |
| 654 | | var file_size: u64 = 0; |
| 655 | | for (dwarf_segment.sections.items) |sect| { |
| 656 | | file_size += sect.size; |
| 657 | | } |
| 658 | | dwarf_segment.inner.filesize = file_size; |
| 659 | | } |
| 660 | | |
| 660 | self.updateDwarfSegment(); |
| 661 | 661 | try self.writeLoadCommands(allocator); |
| 662 | 662 | try self.writeHeader(); |
| 663 | 663 | |
| ... | ... | @@ -676,6 +676,7 @@ pub fn deinit(self: *DebugSymbols, allocator: *Allocator) void { |
| 676 | 676 | for (self.load_commands.items) |*lc| { |
| 677 | 677 | lc.deinit(allocator); |
| 678 | 678 | } |
| 679 | self.load_commands.deinit(allocator); |
| 679 | 680 | self.file.close(); |
| 680 | 681 | } |
| 681 | 682 | |
| ... | ... | @@ -724,6 +725,21 @@ fn copySegmentCommand(self: *DebugSymbols, allocator: *Allocator, base_cmd: Segm |
| 724 | 725 | return cmd; |
| 725 | 726 | } |
| 726 | 727 | |
| 728 | fn updateDwarfSegment(self: *DebugSymbols) void { |
| 729 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; |
| 730 | var file_size: u64 = 0; |
| 731 | for (dwarf_segment.sections.items) |sect| { |
| 732 | file_size += sect.size; |
| 733 | } |
| 734 | if (file_size != dwarf_segment.inner.filesize) { |
| 735 | dwarf_segment.inner.filesize = file_size; |
| 736 | if (dwarf_segment.inner.vmsize < dwarf_segment.inner.filesize) { |
| 737 | dwarf_segment.inner.vmsize = mem.alignForwardGeneric(u64, dwarf_segment.inner.filesize, page_size); |
| 738 | } |
| 739 | self.load_commands_dirty = true; |
| 740 | } |
| 741 | } |
| 742 | |
| 727 | 743 | /// Writes all load commands and section headers. |
| 728 | 744 | fn writeLoadCommands(self: *DebugSymbols, allocator: *Allocator) !void { |
| 729 | 745 | if (!self.load_commands_dirty) return; |
| ... | ... | @@ -823,7 +839,7 @@ fn relocateSymbolTable(self: *DebugSymbols) !void { |
| 823 | 839 | const new_symoff = self.findFreeSpaceLinkedit(needed_size, @alignOf(macho.nlist_64)); |
| 824 | 840 | const existing_size = symtab.nsyms * @sizeOf(macho.nlist_64); |
| 825 | 841 | |
| 826 | | assert(new_symoff + existing_size <= self.linkedit_off + self.linkedit_size); |
| 842 | assert(new_symoff + existing_size <= self.linkedit_off + self.linkedit_size); // TODO expand LINKEDIT segment. |
| 827 | 843 | log.debug("relocating dSym symbol table from 0x{x}-0x{x} to 0x{x}-0x{x}", .{ |
| 828 | 844 | symtab.symoff, |
| 829 | 845 | symtab.symoff + existing_size, |
| ... | ... | @@ -850,7 +866,7 @@ pub fn writeLocalSymbol(self: *DebugSymbols, index: usize) !void { |
| 850 | 866 | try self.file.pwriteAll(mem.asBytes(&self.base.local_symbols.items[index]), off); |
| 851 | 867 | } |
| 852 | 868 | |
| 853 | | pub fn writeStringTable(self: *DebugSymbols) !void { |
| 869 | fn writeStringTable(self: *DebugSymbols) !void { |
| 854 | 870 | if (!self.string_table_dirty) return; |
| 855 | 871 | |
| 856 | 872 | const tracy = trace(@src()); |
| ... | ... | @@ -989,10 +1005,7 @@ pub fn writeDeclDebugInfo(self: *DebugSymbols, text_block: *TextBlock, dbg_info_ |
| 989 | 1005 | const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null); |
| 990 | 1006 | const existing_size = last_decl.dbg_info_off; |
| 991 | 1007 | |
| 992 | | // TODO |
| 993 | | assert(dwarf_segment.inner.fileoff + dwarf_segment.inner.filesize >= new_offset + needed_size); |
| 994 | | |
| 995 | | log.debug("moving _debug_info section: {} bytes from 0x{x} to 0x{x}", .{ |
| 1008 | log.debug("moving __debug_info section: {} bytes from 0x{x} to 0x{x}", .{ |
| 996 | 1009 | existing_size, |
| 997 | 1010 | debug_info_sect.offset, |
| 998 | 1011 | new_offset, |
| ... | ... | @@ -1042,13 +1055,6 @@ fn makeDebugString(self: *DebugSymbols, allocator: *Allocator, bytes: []const u8 |
| 1042 | 1055 | return @intCast(u32, result); |
| 1043 | 1056 | } |
| 1044 | 1057 | |
| 1045 | | /// The reloc offset for the virtual address of a function in its Line Number Program. |
| 1046 | | /// Size is a virtual address integer. |
| 1047 | | pub const dbg_line_vaddr_reloc_index = 3; |
| 1048 | | /// The reloc offset for the virtual address of a function in its .debug_info TAG_subprogram. |
| 1049 | | /// Size is a virtual address integer. |
| 1050 | | pub const dbg_info_low_pc_reloc_index = 1; |
| 1051 | | |
| 1052 | 1058 | /// The reloc offset for the line offset of a function from the previous function's line. |
| 1053 | 1059 | /// It's a fixed-size 4-byte ULEB128. |
| 1054 | 1060 | pub fn getRelocDbgLineOff() usize { |
| ... | ... | @@ -1081,8 +1087,6 @@ fn dbgInfoNeededHeaderBytes(self: DebugSymbols) u32 { |
| 1081 | 1087 | return 120; |
| 1082 | 1088 | } |
| 1083 | 1089 | |
| 1084 | | pub const min_nop_size = 2; |
| 1085 | | |
| 1086 | 1090 | /// Writes to the file a buffer, prefixed and suffixed by the specified number of |
| 1087 | 1091 | /// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes |
| 1088 | 1092 | /// are less than 126,976 bytes (if this limit is ever reached, this function can be |