mirror of
https://github.com/ziglang/zig.git
synced 2026-02-18 07:18:38 +00:00
Merge pull request #18875 from ziglang/macho-zo-dwarf
macho: emit DWARF for ZigObject relocatable
This commit is contained in:
commit
d12c8db642
@ -25,6 +25,15 @@ cd $ZIGDIR
|
||||
git fetch --unshallow || true
|
||||
git fetch --tags
|
||||
|
||||
# Test building from source without LLVM.
|
||||
git clean -fd
|
||||
rm -rf zig-out
|
||||
cc -o bootstrap bootstrap.c
|
||||
./bootstrap
|
||||
./zig2 build -Dno-lib
|
||||
# In order to run these behavior tests we need to move the `@cImport` ones to somewhere else.
|
||||
# ./zig-out/bin/zig test test/behavior.zig
|
||||
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
@ -764,7 +764,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
|
||||
builtin.zig_backend == .stage2_arm or
|
||||
builtin.zig_backend == .stage2_aarch64 or
|
||||
builtin.zig_backend == .stage2_x86 or
|
||||
(builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) or
|
||||
(builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or
|
||||
builtin.zig_backend == .stage2_riscv64 or
|
||||
builtin.zig_backend == .stage2_sparc64 or
|
||||
builtin.zig_backend == .stage2_spirv64)
|
||||
|
||||
@ -6278,7 +6278,7 @@ fn canBuildLibCompilerRt(target: std.Target, use_llvm: bool) bool {
|
||||
}
|
||||
return switch (target_util.zigBackend(target, use_llvm)) {
|
||||
.stage2_llvm => true,
|
||||
.stage2_x86_64 => if (target.ofmt == .elf) true else build_options.have_llvm,
|
||||
.stage2_x86_64 => if (target.ofmt == .elf or target.ofmt == .macho) true else build_options.have_llvm,
|
||||
else => build_options.have_llvm,
|
||||
};
|
||||
}
|
||||
@ -6296,7 +6296,7 @@ fn canBuildZigLibC(target: std.Target, use_llvm: bool) bool {
|
||||
}
|
||||
return switch (target_util.zigBackend(target, use_llvm)) {
|
||||
.stage2_llvm => true,
|
||||
.stage2_x86_64 => if (target.ofmt == .elf) true else build_options.have_llvm,
|
||||
.stage2_x86_64 => if (target.ofmt == .elf or target.ofmt == .macho) true else build_options.have_llvm,
|
||||
else => build_options.have_llvm,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1282,10 +1282,17 @@ pub fn commitDeclState(
|
||||
try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
|
||||
},
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
const debug_line_sect = d_sym.getSectionPtr(d_sym.debug_line_section_index.?);
|
||||
const file_pos = debug_line_sect.offset + src_fn.off;
|
||||
try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len);
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
const debug_line_sect = &macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?];
|
||||
const file_pos = debug_line_sect.offset + src_fn.off;
|
||||
try pwriteDbgLineNops(macho_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
const debug_line_sect = d_sym.getSectionPtr(d_sym.debug_line_section_index.?);
|
||||
const file_pos = debug_line_sect.offset + src_fn.off;
|
||||
try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len);
|
||||
}
|
||||
},
|
||||
.wasm => {
|
||||
const wasm_file = self.bin_file.cast(File.Wasm).?;
|
||||
@ -1351,18 +1358,33 @@ pub fn commitDeclState(
|
||||
},
|
||||
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
const sect_index = d_sym.debug_line_section_index.?;
|
||||
try d_sym.growSection(sect_index, needed_size, true);
|
||||
const sect = d_sym.getSection(sect_index);
|
||||
const file_pos = sect.offset + src_fn.off;
|
||||
try pwriteDbgLineNops(
|
||||
d_sym.file,
|
||||
file_pos,
|
||||
prev_padding_size,
|
||||
dbg_line_buffer.items,
|
||||
next_padding_size,
|
||||
);
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
const sect_index = macho_file.debug_line_sect_index.?;
|
||||
try macho_file.growSection(sect_index, needed_size);
|
||||
const sect = macho_file.sections.items(.header)[sect_index];
|
||||
const file_pos = sect.offset + src_fn.off;
|
||||
try pwriteDbgLineNops(
|
||||
macho_file.base.file.?,
|
||||
file_pos,
|
||||
prev_padding_size,
|
||||
dbg_line_buffer.items,
|
||||
next_padding_size,
|
||||
);
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
const sect_index = d_sym.debug_line_section_index.?;
|
||||
try d_sym.growSection(sect_index, needed_size, true, macho_file);
|
||||
const sect = d_sym.getSection(sect_index);
|
||||
const file_pos = sect.offset + src_fn.off;
|
||||
try pwriteDbgLineNops(
|
||||
d_sym.file,
|
||||
file_pos,
|
||||
prev_padding_size,
|
||||
dbg_line_buffer.items,
|
||||
next_padding_size,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
.wasm => {
|
||||
@ -1459,16 +1481,21 @@ pub fn commitDeclState(
|
||||
while (decl_state.exprloc_relocs.popOrNull()) |reloc| {
|
||||
switch (self.bin_file.tag) {
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
try d_sym.relocs.append(d_sym.allocator, .{
|
||||
.type = switch (reloc.type) {
|
||||
.direct_load => .direct_load,
|
||||
.got_load => .got_load,
|
||||
},
|
||||
.target = reloc.target,
|
||||
.offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off,
|
||||
.addend = 0,
|
||||
});
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
// TODO
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
try d_sym.relocs.append(d_sym.allocator, .{
|
||||
.type = switch (reloc.type) {
|
||||
.direct_load => .direct_load,
|
||||
.got_load => .got_load,
|
||||
},
|
||||
.target = reloc.target,
|
||||
.offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off,
|
||||
.addend = 0,
|
||||
});
|
||||
}
|
||||
},
|
||||
.elf => {}, // TODO
|
||||
else => unreachable,
|
||||
@ -1511,10 +1538,17 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32)
|
||||
try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
|
||||
},
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
|
||||
const file_pos = debug_info_sect.offset + atom.off;
|
||||
try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false);
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
const debug_info_sect = macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?];
|
||||
const file_pos = debug_info_sect.offset + atom.off;
|
||||
try pwriteDbgInfoNops(macho_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
|
||||
const file_pos = debug_info_sect.offset + atom.off;
|
||||
try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false);
|
||||
}
|
||||
},
|
||||
.wasm => {
|
||||
const wasm_file = self.bin_file.cast(File.Wasm).?;
|
||||
@ -1597,19 +1631,35 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons
|
||||
},
|
||||
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
const sect_index = d_sym.debug_info_section_index.?;
|
||||
try d_sym.growSection(sect_index, needed_size, true);
|
||||
const sect = d_sym.getSection(sect_index);
|
||||
const file_pos = sect.offset + atom.off;
|
||||
try pwriteDbgInfoNops(
|
||||
d_sym.file,
|
||||
file_pos,
|
||||
prev_padding_size,
|
||||
dbg_info_buf,
|
||||
next_padding_size,
|
||||
trailing_zero,
|
||||
);
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
const sect_index = macho_file.debug_info_sect_index.?;
|
||||
try macho_file.growSection(sect_index, needed_size);
|
||||
const sect = macho_file.sections.items(.header)[sect_index];
|
||||
const file_pos = sect.offset + atom.off;
|
||||
try pwriteDbgInfoNops(
|
||||
macho_file.base.file.?,
|
||||
file_pos,
|
||||
prev_padding_size,
|
||||
dbg_info_buf,
|
||||
next_padding_size,
|
||||
trailing_zero,
|
||||
);
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
const sect_index = d_sym.debug_info_section_index.?;
|
||||
try d_sym.growSection(sect_index, needed_size, true, macho_file);
|
||||
const sect = d_sym.getSection(sect_index);
|
||||
const file_pos = sect.offset + atom.off;
|
||||
try pwriteDbgInfoNops(
|
||||
d_sym.file,
|
||||
file_pos,
|
||||
prev_padding_size,
|
||||
dbg_info_buf,
|
||||
next_padding_size,
|
||||
trailing_zero,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
.wasm => {
|
||||
@ -1670,10 +1720,17 @@ pub fn updateDeclLineNumber(self: *Dwarf, mod: *Module, decl_index: InternPool.D
|
||||
try elf_file.base.file.?.pwriteAll(&data, file_pos);
|
||||
},
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
const sect = d_sym.getSection(d_sym.debug_line_section_index.?);
|
||||
const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff();
|
||||
try d_sym.file.pwriteAll(&data, file_pos);
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
const sect = macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?];
|
||||
const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff();
|
||||
try macho_file.base.file.?.pwriteAll(&data, file_pos);
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
const sect = d_sym.getSection(d_sym.debug_line_section_index.?);
|
||||
const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff();
|
||||
try d_sym.file.pwriteAll(&data, file_pos);
|
||||
}
|
||||
},
|
||||
.wasm => {
|
||||
const wasm_file = self.bin_file.cast(File.Wasm).?;
|
||||
@ -1877,12 +1934,21 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {
|
||||
try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
|
||||
},
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
const sect_index = d_sym.debug_abbrev_section_index.?;
|
||||
try d_sym.growSection(sect_index, needed_size, false);
|
||||
const sect = d_sym.getSection(sect_index);
|
||||
const file_pos = sect.offset + abbrev_offset;
|
||||
try d_sym.file.pwriteAll(&abbrev_buf, file_pos);
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
const sect_index = macho_file.debug_abbrev_sect_index.?;
|
||||
try macho_file.growSection(sect_index, needed_size);
|
||||
const sect = macho_file.sections.items(.header)[sect_index];
|
||||
const file_pos = sect.offset + abbrev_offset;
|
||||
try macho_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
const sect_index = d_sym.debug_abbrev_section_index.?;
|
||||
try d_sym.growSection(sect_index, needed_size, false, macho_file);
|
||||
const sect = d_sym.getSection(sect_index);
|
||||
const file_pos = sect.offset + abbrev_offset;
|
||||
try d_sym.file.pwriteAll(&abbrev_buf, file_pos);
|
||||
}
|
||||
},
|
||||
.wasm => {
|
||||
const wasm_file = self.bin_file.cast(File.Wasm).?;
|
||||
@ -1967,10 +2033,17 @@ pub fn writeDbgInfoHeader(self: *Dwarf, zcu: *Module, low_pc: u64, high_pc: u64)
|
||||
try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
|
||||
},
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
const debug_info_sect = d_sym.getSection(d_sym.debug_info_section_index.?);
|
||||
const file_pos = debug_info_sect.offset;
|
||||
try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false);
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
const debug_info_sect = macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?];
|
||||
const file_pos = debug_info_sect.offset;
|
||||
try pwriteDbgInfoNops(macho_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
const debug_info_sect = d_sym.getSection(d_sym.debug_info_section_index.?);
|
||||
const file_pos = debug_info_sect.offset;
|
||||
try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false);
|
||||
}
|
||||
},
|
||||
.wasm => {
|
||||
const wasm_file = self.bin_file.cast(File.Wasm).?;
|
||||
@ -2292,12 +2365,21 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
|
||||
try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);
|
||||
},
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
const sect_index = d_sym.debug_aranges_section_index.?;
|
||||
try d_sym.growSection(sect_index, needed_size, false);
|
||||
const sect = d_sym.getSection(sect_index);
|
||||
const file_pos = sect.offset;
|
||||
try d_sym.file.pwriteAll(di_buf.items, file_pos);
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
const sect_index = macho_file.debug_aranges_sect_index.?;
|
||||
try macho_file.growSection(sect_index, needed_size);
|
||||
const sect = macho_file.sections.items(.header)[sect_index];
|
||||
const file_pos = sect.offset;
|
||||
try macho_file.base.file.?.pwriteAll(di_buf.items, file_pos);
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
const sect_index = d_sym.debug_aranges_section_index.?;
|
||||
try d_sym.growSection(sect_index, needed_size, false, macho_file);
|
||||
const sect = d_sym.getSection(sect_index);
|
||||
const file_pos = sect.offset;
|
||||
try d_sym.file.pwriteAll(di_buf.items, file_pos);
|
||||
}
|
||||
},
|
||||
.wasm => {
|
||||
const wasm_file = self.bin_file.cast(File.Wasm).?;
|
||||
@ -2432,16 +2514,29 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
|
||||
try elf_file.base.file.?.pwriteAll(buffer, file_pos + delta);
|
||||
},
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
const sect_index = d_sym.debug_line_section_index.?;
|
||||
const needed_size: u32 = @intCast(d_sym.getSection(sect_index).size + delta);
|
||||
try d_sym.growSection(sect_index, needed_size, true);
|
||||
const file_pos = d_sym.getSection(sect_index).offset + first_fn.off;
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
const sect_index = macho_file.debug_line_sect_index.?;
|
||||
const needed_size: u32 = @intCast(macho_file.sections.items(.header)[sect_index].size + delta);
|
||||
try macho_file.growSection(sect_index, needed_size);
|
||||
const file_pos = macho_file.sections.items(.header)[sect_index].offset + first_fn.off;
|
||||
|
||||
const amt = try d_sym.file.preadAll(buffer, file_pos);
|
||||
if (amt != buffer.len) return error.InputOutput;
|
||||
const amt = try macho_file.base.file.?.preadAll(buffer, file_pos);
|
||||
if (amt != buffer.len) return error.InputOutput;
|
||||
|
||||
try d_sym.file.pwriteAll(buffer, file_pos + delta);
|
||||
try macho_file.base.file.?.pwriteAll(buffer, file_pos + delta);
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
const sect_index = d_sym.debug_line_section_index.?;
|
||||
const needed_size: u32 = @intCast(d_sym.getSection(sect_index).size + delta);
|
||||
try d_sym.growSection(sect_index, needed_size, true, macho_file);
|
||||
const file_pos = d_sym.getSection(sect_index).offset + first_fn.off;
|
||||
|
||||
const amt = try d_sym.file.preadAll(buffer, file_pos);
|
||||
if (amt != buffer.len) return error.InputOutput;
|
||||
|
||||
try d_sym.file.pwriteAll(buffer, file_pos + delta);
|
||||
}
|
||||
},
|
||||
.wasm => {
|
||||
const wasm_file = self.bin_file.cast(File.Wasm).?;
|
||||
@ -2487,10 +2582,17 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
|
||||
try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
|
||||
},
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
const debug_line_sect = d_sym.getSection(d_sym.debug_line_section_index.?);
|
||||
const file_pos = debug_line_sect.offset;
|
||||
try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt);
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
const debug_line_sect = macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?];
|
||||
const file_pos = debug_line_sect.offset;
|
||||
try pwriteDbgLineNops(macho_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
const debug_line_sect = d_sym.getSection(d_sym.debug_line_section_index.?);
|
||||
const file_pos = debug_line_sect.offset;
|
||||
try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt);
|
||||
}
|
||||
},
|
||||
.wasm => {
|
||||
const wasm_file = self.bin_file.cast(File.Wasm).?;
|
||||
@ -2608,9 +2710,15 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
|
||||
break :pos debug_info_sect.sh_offset;
|
||||
},
|
||||
.macho => pos: {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
|
||||
break :pos debug_info_sect.offset;
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
const debug_info_sect = &macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?];
|
||||
break :pos debug_info_sect.offset;
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
|
||||
break :pos debug_info_sect.offset;
|
||||
}
|
||||
},
|
||||
// for wasm, the offset is always 0 as we write to memory first
|
||||
.wasm => 0,
|
||||
@ -2628,8 +2736,13 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
|
||||
try elf_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
|
||||
},
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
try d_sym.file.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
try macho_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
try d_sym.file.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
|
||||
}
|
||||
},
|
||||
.wasm => {
|
||||
const wasm_file = self.bin_file.cast(File.Wasm).?;
|
||||
@ -2653,8 +2766,13 @@ fn addDIFile(self: *Dwarf, mod: *Module, decl_index: InternPool.DeclIndex) !u28
|
||||
elf_file.markDirty(elf_file.debug_line_section_index.?);
|
||||
},
|
||||
.macho => {
|
||||
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
|
||||
d_sym.markDirty(d_sym.debug_line_section_index.?);
|
||||
const macho_file = self.bin_file.cast(File.MachO).?;
|
||||
if (macho_file.base.isRelocatable()) {
|
||||
macho_file.markDirty(macho_file.debug_line_sect_index.?);
|
||||
} else {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
d_sym.markDirty(d_sym.debug_line_section_index.?, macho_file);
|
||||
}
|
||||
},
|
||||
.wasm => {},
|
||||
else => unreachable,
|
||||
|
||||
@ -103,6 +103,14 @@ zig_const_sect_index: ?u8 = null,
|
||||
zig_data_sect_index: ?u8 = null,
|
||||
zig_bss_sect_index: ?u8 = null,
|
||||
|
||||
/// Tracked DWARF section headers that apply only when we emit relocatable.
|
||||
/// For executable and loadable images, DWARF is tracked directly by dSYM bundle object.
|
||||
debug_info_sect_index: ?u8 = null,
|
||||
debug_abbrev_sect_index: ?u8 = null,
|
||||
debug_str_sect_index: ?u8 = null,
|
||||
debug_aranges_sect_index: ?u8 = null,
|
||||
debug_line_sect_index: ?u8 = null,
|
||||
|
||||
has_tlv: bool = false,
|
||||
binds_to_weak: bool = false,
|
||||
weak_defines: bool = false,
|
||||
@ -255,44 +263,15 @@ pub fn createEmpty(
|
||||
)}),
|
||||
} });
|
||||
self.zig_object = index;
|
||||
try self.getZigObject().?.init(self);
|
||||
const zo = self.getZigObject().?;
|
||||
try zo.init(self);
|
||||
|
||||
try self.initMetadata(.{
|
||||
.emit = emit,
|
||||
.zo = zo,
|
||||
.symbol_count_hint = options.symbol_count_hint,
|
||||
.program_code_size_hint = options.program_code_size_hint,
|
||||
});
|
||||
|
||||
switch (comp.config.debug_format) {
|
||||
.strip => {},
|
||||
.dwarf => if (!self.base.isRelocatable()) {
|
||||
// Create dSYM bundle.
|
||||
log.debug("creating {s}.dSYM bundle", .{emit.sub_path});
|
||||
|
||||
const sep = fs.path.sep_str;
|
||||
const d_sym_path = try std.fmt.allocPrint(
|
||||
arena,
|
||||
"{s}.dSYM" ++ sep ++ "Contents" ++ sep ++ "Resources" ++ sep ++ "DWARF",
|
||||
.{emit.sub_path},
|
||||
);
|
||||
|
||||
var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{});
|
||||
defer d_sym_bundle.close();
|
||||
|
||||
const d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{
|
||||
.truncate = false,
|
||||
.read = true,
|
||||
});
|
||||
|
||||
self.d_sym = .{
|
||||
.allocator = gpa,
|
||||
.dwarf = link.File.Dwarf.init(&self.base, .dwarf32),
|
||||
.file = d_sym_file,
|
||||
};
|
||||
try self.d_sym.?.initMetadata(self);
|
||||
} else {
|
||||
@panic("TODO: implement generating and emitting __DWARF in .o file");
|
||||
},
|
||||
.code_view => unreachable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -978,7 +957,6 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {
|
||||
|
||||
const gpa = self.base.comp.gpa;
|
||||
const file = try std.fs.cwd().openFile(path, .{});
|
||||
errdefer file.close();
|
||||
const handle = try self.addFileHandle(file);
|
||||
const mtime: u64 = mtime: {
|
||||
const stat = file.stat() catch break :mtime 0;
|
||||
@ -1015,7 +993,6 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar
|
||||
const gpa = self.base.comp.gpa;
|
||||
|
||||
const file = try std.fs.cwd().openFile(lib.path, .{});
|
||||
errdefer file.close();
|
||||
const handle = try self.addFileHandle(file);
|
||||
|
||||
var archive = Archive{};
|
||||
@ -2015,6 +1992,11 @@ pub fn sortSections(self: *MachO) !void {
|
||||
&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.*];
|
||||
@ -2314,11 +2296,11 @@ fn allocateSections(self: *MachO) !void {
|
||||
// Must move the entire section.
|
||||
const new_offset = self.findFreeSpace(existing_size, page_size);
|
||||
|
||||
log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{
|
||||
log.debug("moving '{s},{s}' from 0x{x} to 0x{x}", .{
|
||||
header.segName(),
|
||||
header.sectName(),
|
||||
header.offset,
|
||||
new_offset,
|
||||
new_offset + existing_size,
|
||||
});
|
||||
|
||||
try self.copyRangeAllZeroOut(header.offset, new_offset, existing_size);
|
||||
@ -3152,7 +3134,7 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex)
|
||||
|
||||
pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: InternPool.DeclIndex) !void {
|
||||
if (self.llvm_object) |_| return;
|
||||
return self.getZigObject().?.updateDeclLineNumber(self, module, decl_index);
|
||||
return self.getZigObject().?.updateDeclLineNumber(module, decl_index);
|
||||
}
|
||||
|
||||
pub fn updateExports(
|
||||
@ -3221,7 +3203,7 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
|
||||
for (self.sections.items(.header)) |header| {
|
||||
if (header.isZerofill()) continue;
|
||||
const increased_size = padToIdeal(header.size);
|
||||
const test_end = header.offset + increased_size;
|
||||
const test_end = header.offset +| increased_size;
|
||||
if (end > header.offset and start < test_end) {
|
||||
return test_end;
|
||||
}
|
||||
@ -3249,7 +3231,7 @@ fn detectAllocCollisionVirtual(self: *MachO, start: u64, size: u64) ?u64 {
|
||||
|
||||
for (self.sections.items(.header)) |header| {
|
||||
const increased_size = padToIdeal(header.size);
|
||||
const test_end = header.addr + increased_size;
|
||||
const test_end = header.addr +| increased_size;
|
||||
if (end > header.addr and start < test_end) {
|
||||
return test_end;
|
||||
}
|
||||
@ -3266,27 +3248,39 @@ fn detectAllocCollisionVirtual(self: *MachO, start: u64, size: u64) ?u64 {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn allocatedSize(self: *MachO, start: u64) u64 {
|
||||
pub fn allocatedSize(self: *MachO, start: u64) u64 {
|
||||
if (start == 0) return 0;
|
||||
|
||||
var min_pos: u64 = std.math.maxInt(u64);
|
||||
|
||||
for (self.sections.items(.header)) |header| {
|
||||
if (header.offset <= start) continue;
|
||||
if (header.offset < min_pos) min_pos = header.offset;
|
||||
}
|
||||
|
||||
for (self.segments.items) |seg| {
|
||||
if (seg.fileoff <= start) continue;
|
||||
if (seg.fileoff < min_pos) min_pos = seg.fileoff;
|
||||
}
|
||||
|
||||
return min_pos - start;
|
||||
}
|
||||
|
||||
fn allocatedSizeVirtual(self: *MachO, start: u64) u64 {
|
||||
pub fn allocatedSizeVirtual(self: *MachO, start: u64) u64 {
|
||||
if (start == 0) return 0;
|
||||
|
||||
var min_pos: u64 = std.math.maxInt(u64);
|
||||
|
||||
for (self.sections.items(.header)) |header| {
|
||||
if (header.addr <= start) continue;
|
||||
if (header.addr < min_pos) min_pos = header.addr;
|
||||
}
|
||||
|
||||
for (self.segments.items) |seg| {
|
||||
if (seg.vmaddr <= start) continue;
|
||||
if (seg.vmaddr < min_pos) min_pos = seg.vmaddr;
|
||||
}
|
||||
|
||||
return min_pos - start;
|
||||
}
|
||||
|
||||
@ -3325,6 +3319,8 @@ fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64
|
||||
}
|
||||
|
||||
const InitMetadataOptions = struct {
|
||||
emit: Compilation.Emit,
|
||||
zo: *ZigObject,
|
||||
symbol_count_hint: u64,
|
||||
program_code_size_hint: u64,
|
||||
};
|
||||
@ -3393,6 +3389,31 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
|
||||
.prot = macho.PROT.READ | macho.PROT.WRITE,
|
||||
});
|
||||
}
|
||||
|
||||
if (options.zo.dwarf) |_| {
|
||||
// Create dSYM bundle.
|
||||
log.debug("creating {s}.dSYM bundle", .{options.emit.sub_path});
|
||||
|
||||
const gpa = self.base.comp.gpa;
|
||||
const sep = fs.path.sep_str;
|
||||
const d_sym_path = try std.fmt.allocPrint(
|
||||
gpa,
|
||||
"{s}.dSYM" ++ sep ++ "Contents" ++ sep ++ "Resources" ++ sep ++ "DWARF",
|
||||
.{options.emit.sub_path},
|
||||
);
|
||||
defer gpa.free(d_sym_path);
|
||||
|
||||
var d_sym_bundle = try options.emit.directory.handle.makeOpenPath(d_sym_path, .{});
|
||||
defer d_sym_bundle.close();
|
||||
|
||||
const d_sym_file = try d_sym_bundle.createFile(options.emit.sub_path, .{
|
||||
.truncate = false,
|
||||
.read = true,
|
||||
});
|
||||
|
||||
self.d_sym = .{ .allocator = gpa, .file = d_sym_file };
|
||||
try self.d_sym.?.initMetadata(self);
|
||||
}
|
||||
}
|
||||
|
||||
const appendSect = struct {
|
||||
@ -3470,6 +3491,44 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
|
||||
appendSect(self, self.zig_bss_sect_index.?, self.zig_bss_seg_index.?);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
|
||||
@ -3491,11 +3550,11 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
|
||||
const alignment = self.getPageSize();
|
||||
const new_offset = self.findFreeSpace(needed_size, alignment);
|
||||
|
||||
log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{
|
||||
log.debug("moving '{s},{s}' from 0x{x} to 0x{x}", .{
|
||||
sect.segName(),
|
||||
sect.sectName(),
|
||||
sect.offset,
|
||||
new_offset,
|
||||
new_offset + existing_size,
|
||||
});
|
||||
|
||||
try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);
|
||||
@ -3557,6 +3616,22 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void
|
||||
sect.size = needed_size;
|
||||
}
|
||||
|
||||
pub fn markDirty(self: *MachO, sect_index: u8) void {
|
||||
if (self.getZigObject()) |zo| {
|
||||
if (self.debug_info_sect_index.? == sect_index) {
|
||||
zo.debug_info_header_dirty = true;
|
||||
} else if (self.debug_line_sect_index.? == sect_index) {
|
||||
zo.debug_line_header_dirty = true;
|
||||
} else if (self.debug_abbrev_sect_index.? == sect_index) {
|
||||
zo.debug_abbrev_dirty = true;
|
||||
} else if (self.debug_str_sect_index.? == sect_index) {
|
||||
zo.debug_strtab_dirty = true;
|
||||
} else if (self.debug_aranges_sect_index.? == sect_index) {
|
||||
zo.debug_aranges_dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getTarget(self: MachO) std.Target {
|
||||
return self.base.comp.root_mod.resolved_target.result;
|
||||
}
|
||||
@ -3632,6 +3707,21 @@ pub fn isZigSection(self: MachO, sect_id: u8) bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn isDebugSection(self: MachO, sect_id: u8) bool {
|
||||
inline for (&[_]?u8{
|
||||
self.debug_info_sect_index,
|
||||
self.debug_abbrev_sect_index,
|
||||
self.debug_str_sect_index,
|
||||
self.debug_aranges_sect_index,
|
||||
self.debug_line_sect_index,
|
||||
}) |maybe_index| {
|
||||
if (maybe_index) |index| {
|
||||
if (index == sect_id) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn addSegment(self: *MachO, name: []const u8, opts: struct {
|
||||
vmaddr: u64 = 0,
|
||||
vmsize: u64 = 0,
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
allocator: Allocator,
|
||||
dwarf: Dwarf,
|
||||
file: fs.File,
|
||||
|
||||
symtab_cmd: macho.symtab_command = .{},
|
||||
@ -17,12 +16,6 @@ debug_str_section_index: ?u8 = null,
|
||||
debug_aranges_section_index: ?u8 = null,
|
||||
debug_line_section_index: ?u8 = null,
|
||||
|
||||
debug_string_table_dirty: bool = false,
|
||||
debug_abbrev_section_dirty: bool = false,
|
||||
debug_aranges_section_dirty: bool = false,
|
||||
debug_info_header_dirty: bool = false,
|
||||
debug_line_header_dirty: bool = false,
|
||||
|
||||
relocs: std.ArrayListUnmanaged(Reloc) = .{},
|
||||
|
||||
/// Output synthetic sections
|
||||
@ -44,7 +37,7 @@ pub const Reloc = struct {
|
||||
pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {
|
||||
try self.strtab.append(self.allocator, 0);
|
||||
|
||||
if (self.dwarf_segment_cmd_index == null) {
|
||||
{
|
||||
self.dwarf_segment_cmd_index = @as(u8, @intCast(self.segments.items.len));
|
||||
|
||||
const page_size = macho_file.getPageSize();
|
||||
@ -63,46 +56,19 @@ pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {
|
||||
});
|
||||
}
|
||||
|
||||
if (self.debug_str_section_index == null) {
|
||||
assert(self.dwarf.strtab.buffer.items.len == 0);
|
||||
try self.dwarf.strtab.buffer.append(self.allocator, 0);
|
||||
self.debug_str_section_index = try self.allocateSection(
|
||||
"__debug_str",
|
||||
@as(u32, @intCast(self.dwarf.strtab.buffer.items.len)),
|
||||
0,
|
||||
);
|
||||
self.debug_string_table_dirty = true;
|
||||
}
|
||||
self.debug_str_section_index = try self.allocateSection("__debug_str", 200, 0);
|
||||
self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0);
|
||||
self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0);
|
||||
self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4);
|
||||
self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0);
|
||||
|
||||
if (self.debug_info_section_index == null) {
|
||||
self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0);
|
||||
self.debug_info_header_dirty = true;
|
||||
}
|
||||
|
||||
if (self.debug_abbrev_section_index == null) {
|
||||
self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0);
|
||||
self.debug_abbrev_section_dirty = true;
|
||||
}
|
||||
|
||||
if (self.debug_aranges_section_index == null) {
|
||||
self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4);
|
||||
self.debug_aranges_section_dirty = true;
|
||||
}
|
||||
|
||||
if (self.debug_line_section_index == null) {
|
||||
self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0);
|
||||
self.debug_line_header_dirty = true;
|
||||
}
|
||||
|
||||
if (self.linkedit_segment_cmd_index == null) {
|
||||
self.linkedit_segment_cmd_index = @as(u8, @intCast(self.segments.items.len));
|
||||
try self.segments.append(self.allocator, .{
|
||||
.segname = makeStaticString("__LINKEDIT"),
|
||||
.maxprot = macho.PROT.READ,
|
||||
.initprot = macho.PROT.READ,
|
||||
.cmdsize = @sizeOf(macho.segment_command_64),
|
||||
});
|
||||
}
|
||||
self.linkedit_segment_cmd_index = @as(u8, @intCast(self.segments.items.len));
|
||||
try self.segments.append(self.allocator, .{
|
||||
.segname = makeStaticString("__LINKEDIT"),
|
||||
.maxprot = macho.PROT.READ,
|
||||
.initprot = macho.PROT.READ,
|
||||
.cmdsize = @sizeOf(macho.segment_command_64),
|
||||
});
|
||||
}
|
||||
|
||||
fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u8 {
|
||||
@ -133,7 +99,13 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn growSection(self: *DebugSymbols, sect_index: u8, needed_size: u32, requires_file_copy: bool) !void {
|
||||
pub fn growSection(
|
||||
self: *DebugSymbols,
|
||||
sect_index: u8,
|
||||
needed_size: u32,
|
||||
requires_file_copy: bool,
|
||||
macho_file: *MachO,
|
||||
) !void {
|
||||
const sect = self.getSectionPtr(sect_index);
|
||||
|
||||
if (needed_size > self.allocatedSize(sect.offset)) {
|
||||
@ -162,20 +134,22 @@ pub fn growSection(self: *DebugSymbols, sect_index: u8, needed_size: u32, requir
|
||||
}
|
||||
|
||||
sect.size = needed_size;
|
||||
self.markDirty(sect_index);
|
||||
self.markDirty(sect_index, macho_file);
|
||||
}
|
||||
|
||||
pub fn markDirty(self: *DebugSymbols, sect_index: u8) void {
|
||||
if (self.debug_info_section_index.? == sect_index) {
|
||||
self.debug_info_header_dirty = true;
|
||||
} else if (self.debug_line_section_index.? == sect_index) {
|
||||
self.debug_line_header_dirty = true;
|
||||
} else if (self.debug_abbrev_section_index.? == sect_index) {
|
||||
self.debug_abbrev_section_dirty = true;
|
||||
} else if (self.debug_str_section_index.? == sect_index) {
|
||||
self.debug_string_table_dirty = true;
|
||||
} else if (self.debug_aranges_section_index.? == sect_index) {
|
||||
self.debug_aranges_section_dirty = true;
|
||||
pub fn markDirty(self: *DebugSymbols, sect_index: u8, macho_file: *MachO) void {
|
||||
if (macho_file.getZigObject()) |zo| {
|
||||
if (self.debug_info_section_index.? == sect_index) {
|
||||
zo.debug_info_header_dirty = true;
|
||||
} else if (self.debug_line_section_index.? == sect_index) {
|
||||
zo.debug_line_header_dirty = true;
|
||||
} else if (self.debug_abbrev_section_index.? == sect_index) {
|
||||
zo.debug_abbrev_dirty = true;
|
||||
} else if (self.debug_str_section_index.? == sect_index) {
|
||||
zo.debug_strtab_dirty = true;
|
||||
} else if (self.debug_aranges_section_index.? == sect_index) {
|
||||
zo.debug_aranges_dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,13 +175,6 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64
|
||||
}
|
||||
|
||||
pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
|
||||
const comp = macho_file.base.comp;
|
||||
// TODO This linker code currently assumes there is only 1 compilation unit
|
||||
// and it corresponds to the Zig source code.
|
||||
const zcu = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented;
|
||||
|
||||
try self.dwarf.flushModule(zcu);
|
||||
|
||||
for (self.relocs.items) |*reloc| {
|
||||
const sym = macho_file.getSymbol(reloc.target);
|
||||
const sym_name = sym.getName(macho_file);
|
||||
@ -226,54 +193,12 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
|
||||
try self.file.pwriteAll(mem.asBytes(&addr), file_offset);
|
||||
}
|
||||
|
||||
if (self.debug_abbrev_section_dirty) {
|
||||
try self.dwarf.writeDbgAbbrev();
|
||||
self.debug_abbrev_section_dirty = false;
|
||||
}
|
||||
|
||||
if (self.debug_info_header_dirty) {
|
||||
// Currently only one compilation unit is supported, so the address range is simply
|
||||
// identical to the main program header virtual address and memory size.
|
||||
const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?];
|
||||
const low_pc = text_section.addr;
|
||||
const high_pc = text_section.addr + text_section.size;
|
||||
try self.dwarf.writeDbgInfoHeader(zcu, low_pc, high_pc);
|
||||
self.debug_info_header_dirty = false;
|
||||
}
|
||||
|
||||
if (self.debug_aranges_section_dirty) {
|
||||
// Currently only one compilation unit is supported, so the address range is simply
|
||||
// identical to the main program header virtual address and memory size.
|
||||
const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?];
|
||||
try self.dwarf.writeDbgAranges(text_section.addr, text_section.size);
|
||||
self.debug_aranges_section_dirty = false;
|
||||
}
|
||||
|
||||
if (self.debug_line_header_dirty) {
|
||||
try self.dwarf.writeDbgLineHeader();
|
||||
self.debug_line_header_dirty = false;
|
||||
}
|
||||
|
||||
{
|
||||
const sect_index = self.debug_str_section_index.?;
|
||||
if (self.debug_string_table_dirty or self.dwarf.strtab.buffer.items.len != self.getSection(sect_index).size) {
|
||||
const needed_size = @as(u32, @intCast(self.dwarf.strtab.buffer.items.len));
|
||||
try self.growSection(sect_index, needed_size, false);
|
||||
try self.file.pwriteAll(self.dwarf.strtab.buffer.items, self.getSection(sect_index).offset);
|
||||
self.debug_string_table_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
self.finalizeDwarfSegment(macho_file);
|
||||
try self.writeLinkeditSegmentData(macho_file);
|
||||
|
||||
// Write load commands
|
||||
const ncmds, const sizeofcmds = try self.writeLoadCommands(macho_file);
|
||||
try self.writeHeader(macho_file, ncmds, sizeofcmds);
|
||||
|
||||
assert(!self.debug_abbrev_section_dirty);
|
||||
assert(!self.debug_aranges_section_dirty);
|
||||
assert(!self.debug_string_table_dirty);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *DebugSymbols) void {
|
||||
@ -281,7 +206,6 @@ pub fn deinit(self: *DebugSymbols) void {
|
||||
self.file.close();
|
||||
self.segments.deinit(gpa);
|
||||
self.sections.deinit(gpa);
|
||||
self.dwarf.deinit();
|
||||
self.relocs.deinit(gpa);
|
||||
self.symtab.deinit(gpa);
|
||||
self.strtab.deinit(gpa);
|
||||
@ -534,7 +458,6 @@ const padToIdeal = MachO.padToIdeal;
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Dwarf = @import("../Dwarf.zig");
|
||||
const MachO = @import("../MachO.zig");
|
||||
const StringTable = @import("../StringTable.zig");
|
||||
const Type = @import("../../type.zig").Type;
|
||||
|
||||
@ -46,16 +46,38 @@ tlv_initializers: TlvInitializerTable = .{},
|
||||
/// A table of relocations.
|
||||
relocs: RelocationTable = .{},
|
||||
|
||||
dwarf: ?Dwarf = null,
|
||||
|
||||
dynamic_relocs: MachO.DynamicRelocs = .{},
|
||||
output_symtab_ctx: MachO.SymtabCtx = .{},
|
||||
output_ar_state: Archive.ArState = .{},
|
||||
|
||||
debug_strtab_dirty: bool = false,
|
||||
debug_abbrev_dirty: bool = false,
|
||||
debug_aranges_dirty: bool = false,
|
||||
debug_info_header_dirty: bool = false,
|
||||
debug_line_header_dirty: bool = false,
|
||||
|
||||
pub fn init(self: *ZigObject, macho_file: *MachO) !void {
|
||||
const comp = macho_file.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
|
||||
try self.atoms.append(gpa, 0); // null input section
|
||||
try self.strtab.buffer.append(gpa, 0);
|
||||
|
||||
switch (comp.config.debug_format) {
|
||||
.strip => {},
|
||||
.dwarf => |v| {
|
||||
assert(v == .@"32");
|
||||
self.dwarf = Dwarf.init(&macho_file.base, .dwarf32);
|
||||
self.debug_strtab_dirty = true;
|
||||
self.debug_abbrev_dirty = true;
|
||||
self.debug_aranges_dirty = true;
|
||||
self.debug_info_header_dirty = true;
|
||||
self.debug_line_header_dirty = true;
|
||||
},
|
||||
.code_view => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(self: *ZigObject, allocator: Allocator) void {
|
||||
@ -101,6 +123,10 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
|
||||
tlv_init.deinit(allocator);
|
||||
}
|
||||
self.tlv_initializers.deinit(allocator);
|
||||
|
||||
if (self.dwarf) |*dw| {
|
||||
dw.deinit();
|
||||
}
|
||||
}
|
||||
|
||||
fn addNlist(self: *ZigObject, allocator: Allocator) !Symbol.Index {
|
||||
@ -407,6 +433,66 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO) !void {
|
||||
if (metadata.text_state != .unused) metadata.text_state = .flushed;
|
||||
if (metadata.const_state != .unused) metadata.const_state = .flushed;
|
||||
}
|
||||
|
||||
if (self.dwarf) |*dw| {
|
||||
const zcu = macho_file.base.comp.module.?;
|
||||
try dw.flushModule(zcu);
|
||||
|
||||
if (self.debug_abbrev_dirty) {
|
||||
try dw.writeDbgAbbrev();
|
||||
self.debug_abbrev_dirty = false;
|
||||
}
|
||||
|
||||
if (self.debug_info_header_dirty) {
|
||||
// Currently only one compilation unit is supported, so the address range is simply
|
||||
// identical to the main program header virtual address and memory size.
|
||||
const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?];
|
||||
const low_pc = text_section.addr;
|
||||
const high_pc = text_section.addr + text_section.size;
|
||||
try dw.writeDbgInfoHeader(zcu, low_pc, high_pc);
|
||||
self.debug_info_header_dirty = false;
|
||||
}
|
||||
|
||||
if (self.debug_aranges_dirty) {
|
||||
// Currently only one compilation unit is supported, so the address range is simply
|
||||
// identical to the main program header virtual address and memory size.
|
||||
const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?];
|
||||
try dw.writeDbgAranges(text_section.addr, text_section.size);
|
||||
self.debug_aranges_dirty = false;
|
||||
}
|
||||
|
||||
if (self.debug_line_header_dirty) {
|
||||
try dw.writeDbgLineHeader();
|
||||
self.debug_line_header_dirty = false;
|
||||
}
|
||||
|
||||
if (!macho_file.base.isRelocatable()) {
|
||||
const d_sym = macho_file.getDebugSymbols().?;
|
||||
const sect_index = d_sym.debug_str_section_index.?;
|
||||
if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != d_sym.getSection(sect_index).size) {
|
||||
const needed_size = @as(u32, @intCast(dw.strtab.buffer.items.len));
|
||||
try d_sym.growSection(sect_index, needed_size, false, macho_file);
|
||||
try d_sym.file.pwriteAll(dw.strtab.buffer.items, d_sym.getSection(sect_index).offset);
|
||||
self.debug_strtab_dirty = false;
|
||||
}
|
||||
} else {
|
||||
const sect_index = macho_file.debug_str_sect_index.?;
|
||||
if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != macho_file.sections.items(.header)[sect_index].size) {
|
||||
const needed_size = @as(u32, @intCast(dw.strtab.buffer.items.len));
|
||||
try macho_file.growSection(sect_index, needed_size);
|
||||
try macho_file.base.file.?.pwriteAll(dw.strtab.buffer.items, macho_file.sections.items(.header)[sect_index].offset);
|
||||
self.debug_strtab_dirty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The point of flushModule() is to commit changes, so in theory, nothing should
|
||||
// be dirty after this. However, it is possible for some things to remain
|
||||
// dirty because they fail to be written in the event of compile errors,
|
||||
// such as debug_line_header_dirty and debug_info_header_dirty.
|
||||
assert(!self.debug_abbrev_dirty);
|
||||
assert(!self.debug_aranges_dirty);
|
||||
assert(!self.debug_strtab_dirty);
|
||||
}
|
||||
|
||||
pub fn getDeclVAddr(
|
||||
@ -572,7 +658,7 @@ pub fn updateFunc(
|
||||
var code_buffer = std.ArrayList(u8).init(gpa);
|
||||
defer code_buffer.deinit();
|
||||
|
||||
var decl_state: ?Dwarf.DeclState = if (macho_file.getDebugSymbols()) |d_sym| try d_sym.dwarf.initDeclState(mod, decl_index) else null;
|
||||
var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
|
||||
defer if (decl_state) |*ds| ds.deinit();
|
||||
|
||||
const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none;
|
||||
@ -600,7 +686,7 @@ pub fn updateFunc(
|
||||
|
||||
if (decl_state) |*ds| {
|
||||
const sym = macho_file.getSymbol(sym_index);
|
||||
try macho_file.getDebugSymbols().?.dwarf.commitDeclState(
|
||||
try self.dwarf.?.commitDeclState(
|
||||
mod,
|
||||
decl_index,
|
||||
sym.getAddress(.{}, macho_file),
|
||||
@ -647,7 +733,7 @@ pub fn updateDecl(
|
||||
var code_buffer = std.ArrayList(u8).init(gpa);
|
||||
defer code_buffer.deinit();
|
||||
|
||||
var decl_state: ?Dwarf.DeclState = if (macho_file.getDebugSymbols()) |d_sym| try d_sym.dwarf.initDeclState(mod, decl_index) else null;
|
||||
var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
|
||||
defer if (decl_state) |*ds| ds.deinit();
|
||||
|
||||
const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
|
||||
@ -681,7 +767,7 @@ pub fn updateDecl(
|
||||
|
||||
if (decl_state) |*ds| {
|
||||
const sym = macho_file.getSymbol(sym_index);
|
||||
try macho_file.getDebugSymbols().?.dwarf.commitDeclState(
|
||||
try self.dwarf.?.commitDeclState(
|
||||
mod,
|
||||
decl_index,
|
||||
sym.getAddress(.{}, macho_file),
|
||||
@ -1257,15 +1343,9 @@ fn updateLazySymbol(
|
||||
}
|
||||
|
||||
/// Must be called only after a successful call to `updateDecl`.
|
||||
pub fn updateDeclLineNumber(
|
||||
self: *ZigObject,
|
||||
macho_file: *MachO,
|
||||
mod: *Module,
|
||||
decl_index: InternPool.DeclIndex,
|
||||
) !void {
|
||||
_ = self;
|
||||
if (macho_file.getDebugSymbols()) |d_sym| {
|
||||
try d_sym.dwarf.updateDeclLineNumber(mod, decl_index);
|
||||
pub fn updateDeclLineNumber(self: *ZigObject, mod: *Module, decl_index: InternPool.DeclIndex) !void {
|
||||
if (self.dwarf) |*dw| {
|
||||
try dw.updateDeclLineNumber(mod, decl_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -193,8 +193,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
|
||||
// Update file offsets of contributing objects
|
||||
const total_size: usize = blk: {
|
||||
var pos: usize = Archive.SARMAG;
|
||||
pos += @sizeOf(Archive.ar_hdr) + Archive.SYMDEF.len + 1;
|
||||
pos = mem.alignForward(usize, pos, ptr_width);
|
||||
pos += @sizeOf(Archive.ar_hdr);
|
||||
pos += mem.alignForward(usize, Archive.SYMDEF.len + 1, ptr_width);
|
||||
pos += ar_symtab.size(format);
|
||||
|
||||
for (files.items) |index| {
|
||||
@ -209,10 +209,10 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
|
||||
.object => |x| x.path,
|
||||
else => unreachable,
|
||||
};
|
||||
pos = mem.alignForward(usize, pos, ptr_width);
|
||||
pos = mem.alignForward(usize, pos, 2);
|
||||
state.file_off = pos;
|
||||
pos += @sizeOf(Archive.ar_hdr) + path.len + 1;
|
||||
pos = mem.alignForward(usize, pos, ptr_width);
|
||||
pos += @sizeOf(Archive.ar_hdr);
|
||||
pos += mem.alignForward(usize, path.len + 1, ptr_width);
|
||||
pos += math.cast(usize, state.size) orelse return error.Overflow;
|
||||
}
|
||||
|
||||
@ -236,7 +236,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
|
||||
|
||||
// Write object files
|
||||
for (files.items) |index| {
|
||||
const aligned = mem.alignForward(usize, buffer.items.len, ptr_width);
|
||||
const aligned = mem.alignForward(usize, buffer.items.len, 2);
|
||||
const padding = aligned - buffer.items.len;
|
||||
if (padding > 0) {
|
||||
try writer.writeByteNTimes(0, padding);
|
||||
@ -402,7 +402,7 @@ fn calcSectionSizes(macho_file: *MachO) !void {
|
||||
const atom = macho_file.getAtom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
const header = &macho_file.sections.items(.header)[atom.out_n_sect];
|
||||
if (!macho_file.isZigSection(atom.out_n_sect)) continue;
|
||||
if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue;
|
||||
header.nreloc += atom.calcNumRelocs(macho_file);
|
||||
}
|
||||
}
|
||||
@ -436,18 +436,20 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void {
|
||||
|
||||
fn allocateSections(macho_file: *MachO) !void {
|
||||
const slice = macho_file.sections.slice();
|
||||
|
||||
const last_index = for (0..slice.items(.header).len) |i| {
|
||||
if (macho_file.isZigSection(@intCast(i))) break i;
|
||||
} else slice.items(.header).len;
|
||||
|
||||
for (slice.items(.header)[0..last_index]) |*header| {
|
||||
for (slice.items(.header)) |*header| {
|
||||
const needed_size = header.size;
|
||||
header.size = 0;
|
||||
const alignment = try math.powi(u32, 2, header.@"align");
|
||||
if (!header.isZerofill()) {
|
||||
header.offset = math.cast(u32, macho_file.findFreeSpace(header.size, alignment)) orelse
|
||||
return error.Overflow;
|
||||
if (needed_size > macho_file.allocatedSize(header.offset)) {
|
||||
header.offset = math.cast(u32, macho_file.findFreeSpace(needed_size, alignment)) orelse
|
||||
return error.Overflow;
|
||||
}
|
||||
}
|
||||
header.addr = macho_file.findFreeSpaceVirtual(header.size, alignment);
|
||||
if (needed_size > macho_file.allocatedSizeVirtual(header.addr)) {
|
||||
header.addr = macho_file.findFreeSpaceVirtual(needed_size, alignment);
|
||||
}
|
||||
header.size = needed_size;
|
||||
}
|
||||
}
|
||||
|
||||
@ -539,7 +541,7 @@ fn writeAtoms(macho_file: *MachO) !void {
|
||||
for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| {
|
||||
if (atoms.items.len == 0) continue;
|
||||
if (header.isZerofill()) continue;
|
||||
if (macho_file.isZigSection(@intCast(i))) continue;
|
||||
if (macho_file.isZigSection(@intCast(i)) or macho_file.isDebugSection(@intCast(i))) continue;
|
||||
|
||||
const size = math.cast(usize, header.size) orelse return error.Overflow;
|
||||
const code = try gpa.alloc(u8, size);
|
||||
@ -580,7 +582,7 @@ fn writeAtoms(macho_file: *MachO) !void {
|
||||
|
||||
for (macho_file.sections.items(.header), 0..) |header, n_sect| {
|
||||
if (header.isZerofill()) continue;
|
||||
if (!macho_file.isZigSection(@intCast(n_sect))) continue;
|
||||
if (!macho_file.isZigSection(@intCast(n_sect)) and !macho_file.isDebugSection(@intCast(n_sect))) continue;
|
||||
const gop = try relocs.getOrPut(@intCast(n_sect));
|
||||
if (gop.found_existing) continue;
|
||||
gop.value_ptr.* = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc);
|
||||
@ -591,7 +593,7 @@ fn writeAtoms(macho_file: *MachO) !void {
|
||||
if (!atom.flags.alive) continue;
|
||||
const header = macho_file.sections.items(.header)[atom.out_n_sect];
|
||||
if (header.isZerofill()) continue;
|
||||
if (!macho_file.isZigSection(atom.out_n_sect)) continue;
|
||||
if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue;
|
||||
if (atom.getRelocs(macho_file).len == 0) continue;
|
||||
const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
|
||||
const code = try gpa.alloc(u8, atom_size);
|
||||
|
||||
@ -20,8 +20,11 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
|
||||
};
|
||||
|
||||
// Exercise linker with self-hosted backend (no LLVM)
|
||||
macho_step.dependOn(testEmptyZig(b, .{ .use_llvm = false, .target = x86_64_target }));
|
||||
macho_step.dependOn(testHelloZig(b, .{ .use_llvm = false, .target = x86_64_target }));
|
||||
macho_step.dependOn(testRelocatableZig(b, .{ .use_llvm = false, .strip = true, .target = x86_64_target }));
|
||||
macho_step.dependOn(testLinkingStaticLib(b, .{ .use_llvm = false, .target = x86_64_target }));
|
||||
macho_step.dependOn(testReexportsZig(b, .{ .use_llvm = false, .target = x86_64_target }));
|
||||
macho_step.dependOn(testRelocatableZig(b, .{ .use_llvm = false, .target = x86_64_target }));
|
||||
|
||||
// Exercise linker with LLVM backend
|
||||
macho_step.dependOn(testDeadStrip(b, .{ .target = default_target }));
|
||||
@ -33,6 +36,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
|
||||
macho_step.dependOn(testHelloZig(b, .{ .target = default_target }));
|
||||
macho_step.dependOn(testLargeBss(b, .{ .target = default_target }));
|
||||
macho_step.dependOn(testLayout(b, .{ .target = default_target }));
|
||||
macho_step.dependOn(testLinkingStaticLib(b, .{ .target = default_target }));
|
||||
macho_step.dependOn(testLinksection(b, .{ .target = default_target }));
|
||||
macho_step.dependOn(testMhExecuteHeader(b, .{ .target = default_target }));
|
||||
macho_step.dependOn(testNoDeadStrip(b, .{ .target = default_target }));
|
||||
@ -843,6 +847,45 @@ fn testLinkDirectlyCppTbd(b: *Build, opts: Options) *Step {
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "linking-static-lib", opts);
|
||||
|
||||
const obj = addObject(b, opts, .{
|
||||
.name = "bobj",
|
||||
.zig_source_bytes = "export var bar: i32 = -42;",
|
||||
.strip = true, // TODO for self-hosted, we don't really emit any valid DWARF yet since we only export a global
|
||||
});
|
||||
|
||||
const lib = addStaticLibrary(b, opts, .{
|
||||
.name = "alib",
|
||||
.zig_source_bytes =
|
||||
\\export fn foo() i32 {
|
||||
\\ return 42;
|
||||
\\}
|
||||
,
|
||||
});
|
||||
lib.addObject(obj);
|
||||
|
||||
const exe = addExecutable(b, opts, .{
|
||||
.name = "testlib",
|
||||
.zig_source_bytes =
|
||||
\\const std = @import("std");
|
||||
\\extern fn foo() i32;
|
||||
\\extern var bar: i32;
|
||||
\\pub fn main() void {
|
||||
\\ std.debug.print("{d}\n", .{foo() + bar});
|
||||
\\}
|
||||
,
|
||||
});
|
||||
exe.linkLibrary(lib);
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdErrEqual("0\n");
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testLinksection(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "macho-linksection", opts);
|
||||
|
||||
@ -1243,14 +1286,7 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step {
|
||||
const run = addRunArtifact(exe);
|
||||
run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") });
|
||||
run.addCheck(.{ .expect_stderr_match = b.dupe("decrFoo=0") });
|
||||
if (opts.use_llvm) {
|
||||
// TODO: enable this once self-hosted can print panics and stack traces
|
||||
run.addCheck(.{ .expect_stderr_match = b.dupe("panic: Oh no!") });
|
||||
}
|
||||
if (builtin.os.tag == .macos) {
|
||||
const signal: u32 = if (opts.use_llvm) std.os.darwin.SIG.ABRT else std.os.darwin.SIG.TRAP;
|
||||
run.addCheck(.{ .expect_term = .{ .Signal = signal } });
|
||||
}
|
||||
run.addCheck(.{ .expect_stderr_match = b.dupe("panic: Oh no!") });
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
return test_step;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user