diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2024-08-06 11:22:37 -0400 |
|---|---|---|
| committer | Jacob Young <jacobly0@users.noreply.github.com> | 2024-08-16 15:22:55 -0400 |
| commit | ef11bc9899002620d67cfce9c79b6c0dc0f5ea61 (patch) | |
| tree | 7b05fe17340c06e4c40c45ebe249361c0c281c72 /src/link/MachO.zig | |
| parent | 90989be0e31a91335f8d1c1eafb84c3b34792a8c (diff) | |
| download | zig-ef11bc9899002620d67cfce9c79b6c0dc0f5ea61.tar.gz zig-ef11bc9899002620d67cfce9c79b6c0dc0f5ea61.zip | |
Dwarf: rework self-hosted debug info from scratch
This is in preparation for incremental and actually being able to debug
executables built by the x86_64 backend.
Diffstat (limited to 'src/link/MachO.zig')
| -rw-r--r-- | src/link/MachO.zig | 249 |
1 files changed, 128 insertions, 121 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 7c0b79a0f1..5d6802154f 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -94,6 +94,9 @@ debug_abbrev_sect_index: ?u8 = null, debug_str_sect_index: ?u8 = null, debug_aranges_sect_index: ?u8 = null, debug_line_sect_index: ?u8 = null, +debug_line_str_sect_index: ?u8 = null, +debug_loclists_sect_index: ?u8 = null, +debug_rnglists_sect_index: ?u8 = null, has_tlv: AtomicBool = AtomicBool.init(false), binds_to_weak: AtomicBool = AtomicBool.init(false), @@ -1789,12 +1792,42 @@ pub fn sortSections(self: *MachO) !void { self.sections.appendAssumeCapacity(slice.get(sorted.index)); } + for (&[_]*?u8{ + &self.data_sect_index, + &self.got_sect_index, + &self.zig_text_sect_index, + &self.zig_got_sect_index, + &self.zig_const_sect_index, + &self.zig_data_sect_index, + &self.zig_bss_sect_index, + &self.stubs_sect_index, + &self.stubs_helper_sect_index, + &self.la_symbol_ptr_sect_index, + &self.tlv_ptr_sect_index, + &self.eh_frame_sect_index, + &self.unwind_info_sect_index, + &self.objc_stubs_sect_index, + &self.debug_str_sect_index, + &self.debug_info_sect_index, + &self.debug_abbrev_sect_index, + &self.debug_aranges_sect_index, + &self.debug_line_sect_index, + &self.debug_line_str_sect_index, + &self.debug_loclists_sect_index, + &self.debug_rnglists_sect_index, + }) |maybe_index| { + if (maybe_index.*) |*index| { + index.* = backlinks[index.*]; + } + } + if (self.getZigObject()) |zo| { for (zo.getAtoms()) |atom_index| { const atom = zo.getAtom(atom_index) orelse continue; if (!atom.isAlive()) continue; atom.out_n_sect = backlinks[atom.out_n_sect]; } + if (zo.dwarf) |*dwarf| dwarf.reloadSectionMetadata(); } for (self.objects.items) |index| { @@ -1813,32 +1846,6 @@ pub fn sortSections(self: *MachO) !void { atom.out_n_sect = backlinks[atom.out_n_sect]; } } - - for (&[_]*?u8{ - &self.data_sect_index, - &self.got_sect_index, - &self.zig_text_sect_index, - &self.zig_got_sect_index, - &self.zig_const_sect_index, - &self.zig_data_sect_index, - &self.zig_bss_sect_index, - &self.stubs_sect_index, - &self.stubs_helper_sect_index, - &self.la_symbol_ptr_sect_index, - &self.tlv_ptr_sect_index, - &self.eh_frame_sect_index, - &self.unwind_info_sect_index, - &self.objc_stubs_sect_index, - &self.debug_info_sect_index, - &self.debug_str_sect_index, - &self.debug_line_sect_index, - &self.debug_abbrev_sect_index, - &self.debug_info_sect_index, - }) |maybe_index| { - if (maybe_index.*) |*index| { - index.* = backlinks[index.*]; - } - } } pub fn addAtomsToSections(self: *MachO) !void { @@ -2189,7 +2196,7 @@ fn allocateSections(self: *MachO) !void { header.size = 0; // Must move the entire section. - const new_offset = self.findFreeSpace(existing_size, page_size); + const new_offset = try self.findFreeSpace(existing_size, page_size); log.debug("moving '{s},{s}' from 0x{x} to 0x{x}", .{ header.segName(), @@ -3066,32 +3073,36 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { return actual_size +| (actual_size / ideal_factor); } -fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { +fn detectAllocCollision(self: *MachO, start: u64, size: u64) !?u64 { // Conservatively commit one page size as reserved space for the headers as we // expect it to grow and everything else be moved in flush anyhow. const header_size = self.getPageSize(); if (start < header_size) return header_size; + var at_end = true; const end = start + padToIdeal(size); for (self.sections.items(.header)) |header| { if (header.isZerofill()) continue; const increased_size = padToIdeal(header.size); const test_end = header.offset +| increased_size; - if (end > header.offset and start < test_end) { - return test_end; + if (start < test_end) { + if (end > header.offset) return test_end; + if (test_end < std.math.maxInt(u64)) at_end = false; } } for (self.segments.items) |seg| { const increased_size = padToIdeal(seg.filesize); const test_end = seg.fileoff +| increased_size; - if (end > seg.fileoff and start < test_end) { - return test_end; + if (start < test_end) { + if (end > seg.fileoff) return test_end; + if (test_end < std.math.maxInt(u64)) at_end = false; } } + if (at_end) try self.base.file.?.setEndPos(end); return null; } @@ -3159,9 +3170,9 @@ pub fn allocatedSizeVirtual(self: *MachO, start: u64) u64 { return min_pos - start; } -pub fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 { +pub fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) !u64 { var start: u64 = 0; - while (self.detectAllocCollision(start, object_size)) |item_end| { + while (try self.detectAllocCollision(start, object_size)) |item_end| { start = mem.alignForward(u64, item_end, min_alignment); } return start; @@ -3210,7 +3221,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { { const filesize = options.program_code_size_hint; - const off = self.findFreeSpace(filesize, self.getPageSize()); + const off = try self.findFreeSpace(filesize, self.getPageSize()); self.zig_text_seg_index = try self.addSegment("__TEXT_ZIG", .{ .fileoff = off, .filesize = filesize, @@ -3222,7 +3233,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { { const filesize = options.symbol_count_hint * @sizeOf(u64); - const off = self.findFreeSpace(filesize, self.getPageSize()); + const off = try self.findFreeSpace(filesize, self.getPageSize()); self.zig_got_seg_index = try self.addSegment("__GOT_ZIG", .{ .fileoff = off, .filesize = filesize, @@ -3234,7 +3245,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { { const filesize: u64 = 1024; - const off = self.findFreeSpace(filesize, self.getPageSize()); + const off = try self.findFreeSpace(filesize, self.getPageSize()); self.zig_const_seg_index = try self.addSegment("__CONST_ZIG", .{ .fileoff = off, .filesize = filesize, @@ -3246,7 +3257,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { { const filesize: u64 = 1024; - const off = self.findFreeSpace(filesize, self.getPageSize()); + const off = try self.findFreeSpace(filesize, self.getPageSize()); self.zig_data_seg_index = try self.addSegment("__DATA_ZIG", .{ .fileoff = off, .filesize = filesize, @@ -3265,7 +3276,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { }); } - if (options.zo.dwarf) |_| { + if (options.zo.dwarf) |*dwarf| { // Create dSYM bundle. log.debug("creating {s}.dSYM bundle", .{options.emit.sub_path}); @@ -3288,6 +3299,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { self.d_sym = .{ .allocator = gpa, .file = d_sym_file }; try self.d_sym.?.initMetadata(self); + try dwarf.initMetadata(); } } @@ -3307,7 +3319,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { const sect = &macho_file.sections.items(.header)[sect_id]; const alignment = try math.powi(u32, 2, sect.@"align"); if (!sect.isZerofill()) { - sect.offset = math.cast(u32, macho_file.findFreeSpace(size, alignment)) orelse + sect.offset = math.cast(u32, try macho_file.findFreeSpace(size, alignment)) orelse return error.Overflow; } sect.addr = macho_file.findFreeSpaceVirtual(size, alignment); @@ -3367,43 +3379,34 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { } } - if (self.base.isRelocatable() and options.zo.dwarf != null) { - { - self.debug_str_sect_index = try self.addSection("__DWARF", "__debug_str", .{ - .flags = macho.S_ATTR_DEBUG, - }); - try allocSect(self, self.debug_str_sect_index.?, 200); - } - - { - self.debug_info_sect_index = try self.addSection("__DWARF", "__debug_info", .{ - .flags = macho.S_ATTR_DEBUG, - }); - try allocSect(self, self.debug_info_sect_index.?, 200); - } - - { - self.debug_abbrev_sect_index = try self.addSection("__DWARF", "__debug_abbrev", .{ - .flags = macho.S_ATTR_DEBUG, - }); - try allocSect(self, self.debug_abbrev_sect_index.?, 128); - } - - { - self.debug_aranges_sect_index = try self.addSection("__DWARF", "__debug_aranges", .{ - .alignment = 4, - .flags = macho.S_ATTR_DEBUG, - }); - try allocSect(self, self.debug_aranges_sect_index.?, 160); - } - - { - self.debug_line_sect_index = try self.addSection("__DWARF", "__debug_line", .{ - .flags = macho.S_ATTR_DEBUG, - }); - try allocSect(self, self.debug_line_sect_index.?, 250); - } - } + if (self.base.isRelocatable()) if (options.zo.dwarf) |*dwarf| { + self.debug_str_sect_index = try self.addSection("__DWARF", "__debug_str", .{ + .flags = macho.S_ATTR_DEBUG, + }); + self.debug_info_sect_index = try self.addSection("__DWARF", "__debug_info", .{ + .flags = macho.S_ATTR_DEBUG, + }); + self.debug_abbrev_sect_index = try self.addSection("__DWARF", "__debug_abbrev", .{ + .flags = macho.S_ATTR_DEBUG, + }); + self.debug_aranges_sect_index = try self.addSection("__DWARF", "__debug_aranges", .{ + .alignment = 4, + .flags = macho.S_ATTR_DEBUG, + }); + self.debug_line_sect_index = try self.addSection("__DWARF", "__debug_line", .{ + .flags = macho.S_ATTR_DEBUG, + }); + self.debug_line_str_sect_index = try self.addSection("__DWARF", "__debug_line_str", .{ + .flags = macho.S_ATTR_DEBUG, + }); + self.debug_loclists_sect_index = try self.addSection("__DWARF", "__debug_loclists", .{ + .flags = macho.S_ATTR_DEBUG, + }); + self.debug_rnglists_sect_index = try self.addSection("__DWARF", "__debug_rnglists", .{ + .flags = macho.S_ATTR_DEBUG, + }); + try dwarf.initMetadata(); + }; } pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { @@ -3417,35 +3420,36 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void { const sect = &self.sections.items(.header)[sect_index]; - if (needed_size > self.allocatedSize(sect.offset) and !sect.isZerofill()) { - const existing_size = sect.size; - sect.size = 0; - - // Must move the entire section. - const alignment = self.getPageSize(); - const new_offset = self.findFreeSpace(needed_size, alignment); - - log.debug("moving '{s},{s}' from 0x{x} to 0x{x}", .{ - sect.segName(), - sect.sectName(), - sect.offset, - new_offset, - }); + const seg_id = self.sections.items(.segment_id)[sect_index]; + const seg = &self.segments.items[seg_id]; - try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size); + if (!sect.isZerofill()) { + const allocated_size = self.allocatedSize(sect.offset); + if (sect.offset + allocated_size == std.math.maxInt(u64)) { + try self.base.file.?.setEndPos(sect.offset + needed_size); + } else if (needed_size > allocated_size) { + const existing_size = sect.size; + sect.size = 0; - sect.offset = @intCast(new_offset); - } + // Must move the entire section. + const alignment = self.getPageSize(); + const new_offset = try self.findFreeSpace(needed_size, alignment); - sect.size = needed_size; + log.debug("moving '{s},{s}' from 0x{x} to 0x{x}", .{ + sect.segName(), + sect.sectName(), + sect.offset, + new_offset, + }); - const seg_id = self.sections.items(.segment_id)[sect_index]; - const seg = &self.segments.items[seg_id]; - seg.fileoff = sect.offset; + try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size); - if (!sect.isZerofill()) { + sect.offset = @intCast(new_offset); + } seg.filesize = needed_size; } + sect.size = needed_size; + seg.fileoff = sect.offset; const mem_capacity = self.allocatedSizeVirtual(seg.vmaddr); if (needed_size > mem_capacity) { @@ -3464,30 +3468,34 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void { const sect = &self.sections.items(.header)[sect_index]; - if (needed_size > self.allocatedSize(sect.offset) and !sect.isZerofill()) { - const existing_size = sect.size; - sect.size = 0; - - // Must move the entire section. - const alignment = try math.powi(u32, 2, sect.@"align"); - const new_offset = self.findFreeSpace(needed_size, alignment); - const new_addr = self.findFreeSpaceVirtual(needed_size, alignment); - - log.debug("new '{s},{s}' file offset 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ - sect.segName(), - sect.sectName(), - new_offset, - new_offset + existing_size, - new_addr, - new_addr + existing_size, - }); + if (!sect.isZerofill()) { + const allocated_size = self.allocatedSize(sect.offset); + if (sect.offset + allocated_size == std.math.maxInt(u64)) { + try self.base.file.?.setEndPos(sect.offset + needed_size); + } else if (needed_size > allocated_size) { + const existing_size = sect.size; + sect.size = 0; - try self.copyRangeAll(sect.offset, new_offset, existing_size); + // Must move the entire section. + const alignment = try math.powi(u32, 2, sect.@"align"); + const new_offset = try self.findFreeSpace(needed_size, alignment); + const new_addr = self.findFreeSpaceVirtual(needed_size, alignment); - sect.offset = @intCast(new_offset); - sect.addr = new_addr; - } + log.debug("new '{s},{s}' file offset 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ + sect.segName(), + sect.sectName(), + new_offset, + new_offset + existing_size, + new_addr, + new_addr + existing_size, + }); + try self.copyRangeAll(sect.offset, new_offset, existing_size); + + sect.offset = @intCast(new_offset); + sect.addr = new_addr; + } + } sect.size = needed_size; } @@ -4591,7 +4599,6 @@ const std = @import("std"); const build_options = @import("build_options"); const builtin = @import("builtin"); const assert = std.debug.assert; -const dwarf = std.dwarf; const fs = std.fs; const log = std.log.scoped(.link); const state_log = std.log.scoped(.link_state); |
