| ... | @@ -100,11 +100,11 @@ offset_table: std.ArrayListUnmanaged(u64) = .{}, | ... | @@ -100,11 +100,11 @@ offset_table: std.ArrayListUnmanaged(u64) = .{}, |
| 100 | phdr_table_dirty: bool = false, | 100 | phdr_table_dirty: bool = false, |
| 101 | shdr_table_dirty: bool = false, | 101 | shdr_table_dirty: bool = false, |
| 102 | shstrtab_dirty: bool = false, | 102 | shstrtab_dirty: bool = false, |
| 103 | debug_strtab_dirty: bool = false, | | |
| 104 | offset_table_count_dirty: bool = false, | 103 | offset_table_count_dirty: bool = false, |
| | 104 | |
| | 105 | debug_strtab_dirty: bool = false, |
| 105 | debug_abbrev_section_dirty: bool = false, | 106 | debug_abbrev_section_dirty: bool = false, |
| 106 | debug_aranges_section_dirty: bool = false, | 107 | debug_aranges_section_dirty: bool = false, |
| 107 | | | |
| 108 | debug_info_header_dirty: bool = false, | 108 | debug_info_header_dirty: bool = false, |
| 109 | debug_line_header_dirty: bool = false, | 109 | debug_line_header_dirty: bool = false, |
| 110 | | 110 | |
| ... | @@ -749,127 +749,129 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -749,127 +749,129 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 749 | try self.writeSymbol(0); | 749 | try self.writeSymbol(0); |
| 750 | } | 750 | } |
| 751 | | 751 | |
| 752 | if (self.debug_str_section_index == null) { | 752 | if (self.dwarf) |dw| { |
| 753 | self.debug_str_section_index = @intCast(u16, self.sections.items.len); | 753 | if (self.debug_str_section_index == null) { |
| 754 | assert(self.dwarf.?.strtab.items.len == 0); | 754 | self.debug_str_section_index = @intCast(u16, self.sections.items.len); |
| 755 | try self.sections.append(self.base.allocator, .{ | 755 | assert(dw.strtab.items.len == 0); |
| 756 | .sh_name = try self.makeString(".debug_str"), | 756 | try self.sections.append(self.base.allocator, .{ |
| 757 | .sh_type = elf.SHT_PROGBITS, | 757 | .sh_name = try self.makeString(".debug_str"), |
| 758 | .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS, | 758 | .sh_type = elf.SHT_PROGBITS, |
| 759 | .sh_addr = 0, | 759 | .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS, |
| 760 | .sh_offset = 0, | 760 | .sh_addr = 0, |
| 761 | .sh_size = 0, | 761 | .sh_offset = 0, |
| 762 | .sh_link = 0, | 762 | .sh_size = 0, |
| 763 | .sh_info = 0, | 763 | .sh_link = 0, |
| 764 | .sh_addralign = 1, | 764 | .sh_info = 0, |
| 765 | .sh_entsize = 1, | 765 | .sh_addralign = 1, |
| 766 | }); | 766 | .sh_entsize = 1, |
| 767 | self.debug_strtab_dirty = true; | 767 | }); |
| 768 | self.shdr_table_dirty = true; | 768 | self.debug_strtab_dirty = true; |
| 769 | } | 769 | self.shdr_table_dirty = true; |
| | 770 | } |
| 770 | | 771 | |
| 771 | if (self.debug_info_section_index == null) { | 772 | if (self.debug_info_section_index == null) { |
| 772 | self.debug_info_section_index = @intCast(u16, self.sections.items.len); | 773 | self.debug_info_section_index = @intCast(u16, self.sections.items.len); |
| 773 | | 774 | |
| 774 | const file_size_hint = 200; | 775 | const file_size_hint = 200; |
| 775 | const p_align = 1; | 776 | const p_align = 1; |
| 776 | const off = self.findFreeSpace(file_size_hint, p_align); | 777 | const off = self.findFreeSpace(file_size_hint, p_align); |
| 777 | log.debug("found .debug_info free space 0x{x} to 0x{x}", .{ | 778 | log.debug("found .debug_info free space 0x{x} to 0x{x}", .{ |
| 778 | off, | 779 | off, |
| 779 | off + file_size_hint, | 780 | off + file_size_hint, |
| 780 | }); | 781 | }); |
| 781 | try self.sections.append(self.base.allocator, .{ | 782 | try self.sections.append(self.base.allocator, .{ |
| 782 | .sh_name = try self.makeString(".debug_info"), | 783 | .sh_name = try self.makeString(".debug_info"), |
| 783 | .sh_type = elf.SHT_PROGBITS, | 784 | .sh_type = elf.SHT_PROGBITS, |
| 784 | .sh_flags = 0, | 785 | .sh_flags = 0, |
| 785 | .sh_addr = 0, | 786 | .sh_addr = 0, |
| 786 | .sh_offset = off, | 787 | .sh_offset = off, |
| 787 | .sh_size = file_size_hint, | 788 | .sh_size = file_size_hint, |
| 788 | .sh_link = 0, | 789 | .sh_link = 0, |
| 789 | .sh_info = 0, | 790 | .sh_info = 0, |
| 790 | .sh_addralign = p_align, | 791 | .sh_addralign = p_align, |
| 791 | .sh_entsize = 0, | 792 | .sh_entsize = 0, |
| 792 | }); | 793 | }); |
| 793 | self.shdr_table_dirty = true; | 794 | self.shdr_table_dirty = true; |
| 794 | self.debug_info_header_dirty = true; | 795 | self.debug_info_header_dirty = true; |
| 795 | } | 796 | } |
| 796 | | 797 | |
| 797 | if (self.debug_abbrev_section_index == null) { | 798 | if (self.debug_abbrev_section_index == null) { |
| 798 | self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len); | 799 | self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len); |
| 799 | | 800 | |
| 800 | const file_size_hint = 128; | 801 | const file_size_hint = 128; |
| 801 | const p_align = 1; | 802 | const p_align = 1; |
| 802 | const off = self.findFreeSpace(file_size_hint, p_align); | 803 | const off = self.findFreeSpace(file_size_hint, p_align); |
| 803 | log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{ | 804 | log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{ |
| 804 | off, | 805 | off, |
| 805 | off + file_size_hint, | 806 | off + file_size_hint, |
| 806 | }); | 807 | }); |
| 807 | try self.sections.append(self.base.allocator, .{ | 808 | try self.sections.append(self.base.allocator, .{ |
| 808 | .sh_name = try self.makeString(".debug_abbrev"), | 809 | .sh_name = try self.makeString(".debug_abbrev"), |
| 809 | .sh_type = elf.SHT_PROGBITS, | 810 | .sh_type = elf.SHT_PROGBITS, |
| 810 | .sh_flags = 0, | 811 | .sh_flags = 0, |
| 811 | .sh_addr = 0, | 812 | .sh_addr = 0, |
| 812 | .sh_offset = off, | 813 | .sh_offset = off, |
| 813 | .sh_size = file_size_hint, | 814 | .sh_size = file_size_hint, |
| 814 | .sh_link = 0, | 815 | .sh_link = 0, |
| 815 | .sh_info = 0, | 816 | .sh_info = 0, |
| 816 | .sh_addralign = p_align, | 817 | .sh_addralign = p_align, |
| 817 | .sh_entsize = 0, | 818 | .sh_entsize = 0, |
| 818 | }); | 819 | }); |
| 819 | self.shdr_table_dirty = true; | 820 | self.shdr_table_dirty = true; |
| 820 | self.debug_abbrev_section_dirty = true; | 821 | self.debug_abbrev_section_dirty = true; |
| 821 | } | 822 | } |
| 822 | | 823 | |
| 823 | if (self.debug_aranges_section_index == null) { | 824 | if (self.debug_aranges_section_index == null) { |
| 824 | self.debug_aranges_section_index = @intCast(u16, self.sections.items.len); | 825 | self.debug_aranges_section_index = @intCast(u16, self.sections.items.len); |
| 825 | | 826 | |
| 826 | const file_size_hint = 160; | 827 | const file_size_hint = 160; |
| 827 | const p_align = 16; | 828 | const p_align = 16; |
| 828 | const off = self.findFreeSpace(file_size_hint, p_align); | 829 | const off = self.findFreeSpace(file_size_hint, p_align); |
| 829 | log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{ | 830 | log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{ |
| 830 | off, | 831 | off, |
| 831 | off + file_size_hint, | 832 | off + file_size_hint, |
| 832 | }); | 833 | }); |
| 833 | try self.sections.append(self.base.allocator, .{ | 834 | try self.sections.append(self.base.allocator, .{ |
| 834 | .sh_name = try self.makeString(".debug_aranges"), | 835 | .sh_name = try self.makeString(".debug_aranges"), |
| 835 | .sh_type = elf.SHT_PROGBITS, | 836 | .sh_type = elf.SHT_PROGBITS, |
| 836 | .sh_flags = 0, | 837 | .sh_flags = 0, |
| 837 | .sh_addr = 0, | 838 | .sh_addr = 0, |
| 838 | .sh_offset = off, | 839 | .sh_offset = off, |
| 839 | .sh_size = file_size_hint, | 840 | .sh_size = file_size_hint, |
| 840 | .sh_link = 0, | 841 | .sh_link = 0, |
| 841 | .sh_info = 0, | 842 | .sh_info = 0, |
| 842 | .sh_addralign = p_align, | 843 | .sh_addralign = p_align, |
| 843 | .sh_entsize = 0, | 844 | .sh_entsize = 0, |
| 844 | }); | 845 | }); |
| 845 | self.shdr_table_dirty = true; | 846 | self.shdr_table_dirty = true; |
| 846 | self.debug_aranges_section_dirty = true; | 847 | self.debug_aranges_section_dirty = true; |
| 847 | } | 848 | } |
| 848 | | 849 | |
| 849 | if (self.debug_line_section_index == null) { | 850 | if (self.debug_line_section_index == null) { |
| 850 | self.debug_line_section_index = @intCast(u16, self.sections.items.len); | 851 | self.debug_line_section_index = @intCast(u16, self.sections.items.len); |
| 851 | | 852 | |
| 852 | const file_size_hint = 250; | 853 | const file_size_hint = 250; |
| 853 | const p_align = 1; | 854 | const p_align = 1; |
| 854 | const off = self.findFreeSpace(file_size_hint, p_align); | 855 | const off = self.findFreeSpace(file_size_hint, p_align); |
| 855 | log.debug("found .debug_line free space 0x{x} to 0x{x}", .{ | 856 | log.debug("found .debug_line free space 0x{x} to 0x{x}", .{ |
| 856 | off, | 857 | off, |
| 857 | off + file_size_hint, | 858 | off + file_size_hint, |
| 858 | }); | 859 | }); |
| 859 | try self.sections.append(self.base.allocator, .{ | 860 | try self.sections.append(self.base.allocator, .{ |
| 860 | .sh_name = try self.makeString(".debug_line"), | 861 | .sh_name = try self.makeString(".debug_line"), |
| 861 | .sh_type = elf.SHT_PROGBITS, | 862 | .sh_type = elf.SHT_PROGBITS, |
| 862 | .sh_flags = 0, | 863 | .sh_flags = 0, |
| 863 | .sh_addr = 0, | 864 | .sh_addr = 0, |
| 864 | .sh_offset = off, | 865 | .sh_offset = off, |
| 865 | .sh_size = file_size_hint, | 866 | .sh_size = file_size_hint, |
| 866 | .sh_link = 0, | 867 | .sh_link = 0, |
| 867 | .sh_info = 0, | 868 | .sh_info = 0, |
| 868 | .sh_addralign = p_align, | 869 | .sh_addralign = p_align, |
| 869 | .sh_entsize = 0, | 870 | .sh_entsize = 0, |
| 870 | }); | 871 | }); |
| 871 | self.shdr_table_dirty = true; | 872 | self.shdr_table_dirty = true; |
| 872 | self.debug_line_header_dirty = true; | 873 | self.debug_line_header_dirty = true; |
| | 874 | } |
| 873 | } | 875 | } |
| 874 | | 876 | |
| 875 | const shsize: u64 = switch (self.ptr_width) { | 877 | const shsize: u64 = switch (self.ptr_width) { |
| ... | @@ -1001,40 +1003,42 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { | ... | @@ -1001,40 +1003,42 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { |
| 1001 | // mixing local and global symbols within a symbol table. | 1003 | // mixing local and global symbols within a symbol table. |
| 1002 | try self.writeAllGlobalSymbols(); | 1004 | try self.writeAllGlobalSymbols(); |
| 1003 | | 1005 | |
| 1004 | if (self.debug_abbrev_section_dirty) { | 1006 | if (self.dwarf) |*dw| { |
| 1005 | try self.dwarf.?.writeDbgAbbrev(&self.base); | 1007 | if (self.debug_abbrev_section_dirty) { |
| 1006 | if (!self.shdr_table_dirty) { | 1008 | try dw.writeDbgAbbrev(&self.base); |
| 1007 | // Then it won't get written with the others and we need to do it. | 1009 | if (!self.shdr_table_dirty) { |
| 1008 | try self.writeSectHeader(self.debug_abbrev_section_index.?); | 1010 | // Then it won't get written with the others and we need to do it. |
| | 1011 | try self.writeSectHeader(self.debug_abbrev_section_index.?); |
| | 1012 | } |
| | 1013 | self.debug_abbrev_section_dirty = false; |
| 1009 | } | 1014 | } |
| 1010 | self.debug_abbrev_section_dirty = false; | | |
| 1011 | } | | |
| 1012 | | 1015 | |
| 1013 | if (self.debug_info_header_dirty) { | 1016 | if (self.debug_info_header_dirty) { |
| 1014 | // Currently only one compilation unit is supported, so the address range is simply | 1017 | // Currently only one compilation unit is supported, so the address range is simply |
| 1015 | // identical to the main program header virtual address and memory size. | 1018 | // identical to the main program header virtual address and memory size. |
| 1016 | const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | 1019 | const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; |
| 1017 | const low_pc = text_phdr.p_vaddr; | 1020 | const low_pc = text_phdr.p_vaddr; |
| 1018 | const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; | 1021 | const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; |
| 1019 | try self.dwarf.?.writeDbgInfoHeader(&self.base, module, low_pc, high_pc); | 1022 | try dw.writeDbgInfoHeader(&self.base, module, low_pc, high_pc); |
| 1020 | self.debug_info_header_dirty = false; | 1023 | self.debug_info_header_dirty = false; |
| 1021 | } | 1024 | } |
| 1022 | | 1025 | |
| 1023 | if (self.debug_aranges_section_dirty) { | 1026 | if (self.debug_aranges_section_dirty) { |
| 1024 | // Currently only one compilation unit is supported, so the address range is simply | 1027 | // Currently only one compilation unit is supported, so the address range is simply |
| 1025 | // identical to the main program header virtual address and memory size. | 1028 | // identical to the main program header virtual address and memory size. |
| 1026 | const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | 1029 | const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; |
| 1027 | try self.dwarf.?.writeDbgAranges(&self.base, text_phdr.p_vaddr, text_phdr.p_memsz); | 1030 | try dw.writeDbgAranges(&self.base, text_phdr.p_vaddr, text_phdr.p_memsz); |
| 1028 | if (!self.shdr_table_dirty) { | 1031 | if (!self.shdr_table_dirty) { |
| 1029 | // Then it won't get written with the others and we need to do it. | 1032 | // Then it won't get written with the others and we need to do it. |
| 1030 | try self.writeSectHeader(self.debug_aranges_section_index.?); | 1033 | try self.writeSectHeader(self.debug_aranges_section_index.?); |
| | 1034 | } |
| | 1035 | self.debug_aranges_section_dirty = false; |
| 1031 | } | 1036 | } |
| 1032 | self.debug_aranges_section_dirty = false; | | |
| 1033 | } | | |
| 1034 | | 1037 | |
| 1035 | if (self.debug_line_header_dirty) { | 1038 | if (self.debug_line_header_dirty) { |
| 1036 | try self.dwarf.?.writeDbgLineHeader(&self.base, module); | 1039 | try dw.writeDbgLineHeader(&self.base, module); |
| 1037 | self.debug_line_header_dirty = false; | 1040 | self.debug_line_header_dirty = false; |
| | 1041 | } |
| 1038 | } | 1042 | } |
| 1039 | | 1043 | |
| 1040 | if (self.phdr_table_dirty) { | 1044 | if (self.phdr_table_dirty) { |
| ... | @@ -1105,9 +1109,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { | ... | @@ -1105,9 +1109,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { |
| 1105 | } | 1109 | } |
| 1106 | } | 1110 | } |
| 1107 | | 1111 | |
| 1108 | { | 1112 | if (self.dwarf) |dwarf| { |
| 1109 | const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?]; | 1113 | const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?]; |
| 1110 | const dwarf = self.dwarf.?; | | |
| 1111 | if (self.debug_strtab_dirty or dwarf.strtab.items.len != debug_strtab_sect.sh_size) { | 1114 | if (self.debug_strtab_dirty or dwarf.strtab.items.len != debug_strtab_sect.sh_size) { |
| 1112 | const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset); | 1115 | const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset); |
| 1113 | const needed_size = dwarf.strtab.items.len; | 1116 | const needed_size = dwarf.strtab.items.len; |
| ... | @@ -2105,14 +2108,16 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al | ... | @@ -2105,14 +2108,16 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al |
| 2105 | phdr.p_memsz = needed_size; | 2108 | phdr.p_memsz = needed_size; |
| 2106 | phdr.p_filesz = needed_size; | 2109 | phdr.p_filesz = needed_size; |
| 2107 | | 2110 | |
| 2108 | // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address | 2111 | if (self.dwarf) |_| { |
| 2109 | // range of the compilation unit. When we expand the text section, this range changes, | 2112 | // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address |
| 2110 | // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty. | 2113 | // range of the compilation unit. When we expand the text section, this range changes, |
| 2111 | self.debug_info_header_dirty = true; | 2114 | // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty. |
| 2112 | // This becomes dirty for the same reason. We could potentially make this more | 2115 | self.debug_info_header_dirty = true; |
| 2113 | // fine-grained with the addition of support for more compilation units. It is planned to | 2116 | // This becomes dirty for the same reason. We could potentially make this more |
| 2114 | // model each package as a different compilation unit. | 2117 | // fine-grained with the addition of support for more compilation units. It is planned to |
| 2115 | self.debug_aranges_section_dirty = true; | 2118 | // model each package as a different compilation unit. |
| | 2119 | self.debug_aranges_section_dirty = true; |
| | 2120 | } |
| 2116 | | 2121 | |
| 2117 | self.phdr_table_dirty = true; // TODO look into making only the one program header dirty | 2122 | self.phdr_table_dirty = true; // TODO look into making only the one program header dirty |
| 2118 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | 2123 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty |
| ... | @@ -2794,6 +2799,22 @@ fn writeAllGlobalSymbols(self: *Elf) !void { | ... | @@ -2794,6 +2799,22 @@ fn writeAllGlobalSymbols(self: *Elf) !void { |
| 2794 | .p32 => @sizeOf(elf.Elf32_Sym), | 2799 | .p32 => @sizeOf(elf.Elf32_Sym), |
| 2795 | .p64 => @sizeOf(elf.Elf64_Sym), | 2800 | .p64 => @sizeOf(elf.Elf64_Sym), |
| 2796 | }; | 2801 | }; |
| | 2802 | const sym_align: u16 = switch (self.ptr_width) { |
| | 2803 | .p32 => @alignOf(elf.Elf32_Sym), |
| | 2804 | .p64 => @alignOf(elf.Elf64_Sym), |
| | 2805 | }; |
| | 2806 | const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size; |
| | 2807 | if (needed_size > self.allocatedSize(syms_sect.sh_offset)) { |
| | 2808 | // Move all the symbols to a new file location. |
| | 2809 | const new_offset = self.findFreeSpace(needed_size, sym_align); |
| | 2810 | const existing_size = @as(u64, syms_sect.sh_info) * sym_size; |
| | 2811 | const amt = try self.base.file.?.copyRangeAll(syms_sect.sh_offset, self.base.file.?, new_offset, existing_size); |
| | 2812 | if (amt != existing_size) return error.InputOutput; |
| | 2813 | syms_sect.sh_offset = new_offset; |
| | 2814 | } |
| | 2815 | syms_sect.sh_size = needed_size; // anticipating adding the global symbols later |
| | 2816 | self.shdr_table_dirty = true; // TODO look into only writing one section |
| | 2817 | |
| 2797 | const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian(); | 2818 | const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian(); |
| 2798 | const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size; | 2819 | const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size; |
| 2799 | switch (self.ptr_width) { | 2820 | switch (self.ptr_width) { |