aboutsummaryrefslogtreecommitdiff
path: root/src/link/MachO.zig
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2024-08-06 11:22:37 -0400
committerJacob Young <jacobly0@users.noreply.github.com>2024-08-16 15:22:55 -0400
commitef11bc9899002620d67cfce9c79b6c0dc0f5ea61 (patch)
tree7b05fe17340c06e4c40c45ebe249361c0c281c72 /src/link/MachO.zig
parent90989be0e31a91335f8d1c1eafb84c3b34792a8c (diff)
downloadzig-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.zig249
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);