Merge pull request #18722 from ziglang/macho-debug-info

macho: reinstate DWARF in self-hosted x86_64-macho
This commit is contained in:
Jakub Konka 2024-01-29 20:33:54 +01:00 committed by GitHub
commit 3e939e6153
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 274 additions and 279 deletions

View File

@ -1468,7 +1468,6 @@ pub fn commitDeclState(
.target = reloc.target,
.offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off,
.addend = 0,
.prev_vaddr = 0,
});
},
.elf => {}, // TODO

View File

@ -256,32 +256,39 @@ pub fn createEmpty(
.program_code_size_hint = options.program_code_size_hint,
});
// TODO init dwarf
switch (comp.config.debug_format) {
.strip => {},
.dwarf => if (!self.base.isRelocatable()) {
// Create dSYM bundle.
log.debug("creating {s}.dSYM bundle", .{emit.sub_path});
// if (comp.config.debug_format != .strip) {
// // 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},
);
// const d_sym_path = try std.fmt.allocPrint(
// arena,
// "{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF",
// .{emit.sub_path},
// );
var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{});
defer d_sym_bundle.close();
// 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,
});
// 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,
// };
// }
self.d_sym = .{
.allocator = gpa,
.dwarf = link.File.Dwarf.init(&self.base, .dwarf32),
.file = d_sym_file,
};
try self.d_sym.?.initMetadata(self);
} else {
try self.reportUnexpectedError("TODO: implement generating and emitting __DWARF in .o file", .{});
return error.Unexpected;
},
.code_view => unreachable,
}
}
}
@ -692,6 +699,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
const ncmds, const sizeofcmds, const uuid_cmd_offset = try self.writeLoadCommands();
try self.writeHeader(ncmds, sizeofcmds);
try self.writeUuid(uuid_cmd_offset, self.requiresCodeSig());
if (self.getDebugSymbols()) |dsym| try dsym.flushModule(self);
if (codesig) |*csig| {
try self.writeCodeSignature(csig); // code signing always comes last
@ -731,9 +739,6 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
try argv.append("-r");
}
try argv.append("-o");
try argv.append(full_out_path);
if (self.base.isRelocatable()) {
for (comp.objects) |obj| {
try argv.append(obj.path);
@ -2047,7 +2052,11 @@ pub fn sortSections(self: *MachO) !void {
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,
@ -2901,16 +2910,16 @@ pub fn writeSymtab(self: *MachO, off: u32) !u32 {
try self.strtab.ensureUnusedCapacity(gpa, cmd.strsize - 1);
if (self.getZigObject()) |zo| {
zo.writeSymtab(self);
zo.writeSymtab(self, self);
}
for (self.objects.items) |index| {
try self.getFile(index).?.writeSymtab(self);
try self.getFile(index).?.writeSymtab(self, self);
}
for (self.dylibs.items) |index| {
try self.getFile(index).?.writeSymtab(self);
try self.getFile(index).?.writeSymtab(self, self);
}
if (self.getInternalObject()) |internal| {
internal.writeSymtab(self);
internal.writeSymtab(self, self);
}
assert(self.strtab.items.len == cmd.strsize);
@ -3176,7 +3185,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(module, decl_index);
return self.getZigObject().?.updateDeclLineNumber(self, module, decl_index);
}
pub fn updateExports(
@ -3909,9 +3918,8 @@ fn reportDuplicates(self: *MachO, dupes: anytype) error{ HasDuplicates, OutOfMem
}
pub fn getDebugSymbols(self: *MachO) ?*DebugSymbols {
if (self.d_sym) |*ds| {
return ds;
} else return null;
if (self.d_sym) |*ds| return ds;
return null;
}
pub fn ptraceAttach(self: *MachO, pid: std.os.pid_t) !void {

View File

@ -3,6 +3,7 @@ dwarf: Dwarf,
file: fs.File,
symtab_cmd: macho.symtab_command = .{},
uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 },
segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},
sections: std.ArrayListUnmanaged(macho.section_64) = .{},
@ -22,9 +23,12 @@ debug_aranges_section_dirty: bool = false,
debug_info_header_dirty: bool = false,
debug_line_header_dirty: bool = false,
strtab: StringTable = .{},
relocs: std.ArrayListUnmanaged(Reloc) = .{},
/// Output synthetic sections
symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
strtab: std.ArrayListUnmanaged(u8) = .{},
pub const Reloc = struct {
type: enum {
direct_load,
@ -33,18 +37,17 @@ pub const Reloc = struct {
target: u32,
offset: u64,
addend: u32,
prev_vaddr: u64,
};
/// You must call this function *after* `MachO.populateMissingMetadata()`
/// You must call this function *after* `ZigObject.initMetadata()`
/// has been called to get a viable debug symbols output.
pub fn populateMissingMetadata(self: *DebugSymbols, macho_file: *MachO) !void {
const target = macho_file.base.comp.root_mod.resolved_target.result;
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.getPageSize(target.cpu.arch);
const page_size = macho_file.getPageSize();
const off = @as(u64, @intCast(page_size));
const ideal_size: u16 = 200 + 128 + 160 + 250;
const needed_size = mem.alignForward(u64, padToIdeal(ideal_size), page_size);
@ -203,35 +206,24 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
// and it corresponds to the Zig source code.
const zcu = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented;
for (self.relocs.items) |*reloc| {
const sym = switch (reloc.type) {
.direct_load => macho_file.getSymbol(.{ .sym_index = reloc.target }),
.got_load => blk: {
const got_index = macho_file.got_table.lookup.get(.{ .sym_index = reloc.target }).?;
const got_entry = macho_file.got_table.entries.items[got_index];
break :blk macho_file.getSymbol(got_entry);
},
};
if (sym.n_value == reloc.prev_vaddr) continue;
try self.dwarf.flushModule(zcu);
const sym_name = switch (reloc.type) {
.direct_load => macho_file.getSymbolName(.{ .sym_index = reloc.target }),
.got_load => blk: {
const got_index = macho_file.got_table.lookup.get(.{ .sym_index = reloc.target }).?;
const got_entry = macho_file.got_table.entries.items[got_index];
break :blk macho_file.getSymbolName(got_entry);
},
for (self.relocs.items) |*reloc| {
const sym = macho_file.getSymbol(reloc.target);
const sym_name = sym.getName(macho_file);
const addr = switch (reloc.type) {
.direct_load => sym.getAddress(.{}, macho_file),
.got_load => sym.getGotAddress(macho_file),
};
const sect = &self.sections.items[self.debug_info_section_index.?];
const file_offset = sect.offset + reloc.offset;
log.debug("resolving relocation: {d}@{x} ('{s}') at offset {x}", .{
reloc.target,
sym.n_value,
addr,
sym_name,
file_offset,
});
try self.file.pwriteAll(mem.asBytes(&sym.n_value), file_offset);
reloc.prev_vaddr = sym.n_value;
try self.file.pwriteAll(mem.asBytes(&addr), file_offset);
}
if (self.debug_abbrev_section_dirty) {
@ -242,7 +234,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
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.text_section_index.?];
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);
@ -252,7 +244,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
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.text_section_index.?];
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;
}
@ -276,17 +268,8 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
try self.writeLinkeditSegmentData(macho_file);
// Write load commands
var lc_buffer = std.ArrayList(u8).init(self.allocator);
defer lc_buffer.deinit();
const lc_writer = lc_buffer.writer();
try self.writeSegmentHeaders(macho_file, lc_writer);
try lc_writer.writeStruct(self.symtab_cmd);
try lc_writer.writeStruct(macho_file.uuid_cmd);
const ncmds = load_commands.calcNumOfLCs(lc_buffer.items);
try self.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64));
try self.writeHeader(macho_file, ncmds, @as(u32, @intCast(lc_buffer.items.len)));
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);
@ -299,8 +282,9 @@ pub fn deinit(self: *DebugSymbols) void {
self.segments.deinit(gpa);
self.sections.deinit(gpa);
self.dwarf.deinit();
self.strtab.deinit(gpa);
self.relocs.deinit(gpa);
self.symtab.deinit(gpa);
self.strtab.deinit(gpa);
}
pub fn swapRemoveRelocs(self: *DebugSymbols, target: u32) void {
@ -324,7 +308,7 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
// however at the cost of having LINKEDIT preceed DWARF in dSYM binary which we
// do not want as we want to be able to incrementally move DWARF sections in the
// file as we please.
const last_seg = macho_file.getLinkeditSegmentPtr();
const last_seg = macho_file.getLinkeditSegment();
break :blk last_seg.vmaddr + last_seg.vmsize;
};
const dwarf_segment = self.getDwarfSegmentPtr();
@ -334,8 +318,7 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
file_size = @max(file_size, header.offset + header.size);
}
const target = macho_file.base.comp.root_mod.resolved_target.result;
const page_size = MachO.getPageSize(target.cpu.arch);
const page_size = macho_file.getPageSize();
const aligned_size = mem.alignForward(u64, file_size, page_size);
dwarf_segment.vmaddr = base_vmaddr;
dwarf_segment.filesize = aligned_size;
@ -355,54 +338,70 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
log.debug("found __LINKEDIT segment free space at 0x{x}", .{linkedit.fileoff});
}
fn writeSegmentHeaders(self: *DebugSymbols, macho_file: *MachO, writer: anytype) !void {
// Write segment/section headers from the binary file first.
const end = macho_file.linkedit_segment_cmd_index.?;
for (macho_file.segments.items[0..end], 0..) |seg, i| {
const indexes = macho_file.getSectionIndexes(@as(u8, @intCast(i)));
var out_seg = seg;
out_seg.fileoff = 0;
out_seg.filesize = 0;
out_seg.cmdsize = @sizeOf(macho.segment_command_64);
out_seg.nsects = 0;
fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } {
const gpa = self.allocator;
const needed_size = load_commands.calcLoadCommandsSizeDsym(macho_file, self);
const buffer = try gpa.alloc(u8, needed_size);
defer gpa.free(buffer);
// Update section headers count; any section with size of 0 is excluded
// since it doesn't have any data in the final binary file.
for (macho_file.sections.items(.header)[indexes.start..indexes.end]) |header| {
if (header.size == 0) continue;
out_seg.cmdsize += @sizeOf(macho.section_64);
out_seg.nsects += 1;
var stream = std.io.fixedBufferStream(buffer);
var cwriter = std.io.countingWriter(stream.writer());
const writer = cwriter.writer();
var ncmds: usize = 0;
// UUID comes first presumably to speed up lookup by the consumer like lldb.
@memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);
try writer.writeStruct(self.uuid_cmd);
ncmds += 1;
// Segment and section load commands
{
// Write segment/section headers from the binary file first.
const slice = macho_file.sections.slice();
var sect_id: usize = 0;
for (macho_file.segments.items, 0..) |seg, seg_id| {
if (seg_id == macho_file.linkedit_seg_index.?) break;
var out_seg = seg;
out_seg.fileoff = 0;
out_seg.filesize = 0;
try writer.writeStruct(out_seg);
for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
var out_header = header;
out_header.offset = 0;
try writer.writeStruct(out_header);
}
sect_id += seg.nsects;
}
ncmds += macho_file.segments.items.len - 1;
if (out_seg.nsects == 0 and
(mem.eql(u8, out_seg.segName(), "__DATA_CONST") or
mem.eql(u8, out_seg.segName(), "__DATA"))) continue;
try writer.writeStruct(out_seg);
for (macho_file.sections.items(.header)[indexes.start..indexes.end]) |header| {
if (header.size == 0) continue;
var out_header = header;
out_header.offset = 0;
try writer.writeStruct(out_header);
}
}
// Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
for (self.segments.items, 0..) |seg, i| {
const indexes = self.getSectionIndexes(@as(u8, @intCast(i)));
try writer.writeStruct(seg);
for (self.sections.items[indexes.start..indexes.end]) |header| {
try writer.writeStruct(header);
// Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
sect_id = 0;
for (self.segments.items) |seg| {
try writer.writeStruct(seg);
for (self.sections.items[sect_id..][0..seg.nsects]) |header| {
try writer.writeStruct(header);
}
sect_id += seg.nsects;
}
ncmds += self.segments.items.len;
}
try writer.writeStruct(self.symtab_cmd);
ncmds += 1;
assert(cwriter.bytes_written == needed_size);
try self.file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
return .{ ncmds, buffer.len };
}
fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: u32, sizeofcmds: u32) !void {
const target = macho_file.base.comp.root_mod.resolved_target.result;
fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
var header: macho.mach_header_64 = .{};
header.filetype = macho.MH_DSYM;
switch (target.cpu.arch) {
switch (macho_file.getTarget().cpu.arch) {
.aarch64 => {
header.cputype = macho.CPU_TYPE_ARM64;
header.cpusubtype = macho.CPU_SUBTYPE_ARM_ALL;
@ -414,8 +413,8 @@ fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: u32, sizeofcmds:
else => return error.UnsupportedCpuArchitecture,
}
header.ncmds = ncmds;
header.sizeofcmds = sizeofcmds;
header.ncmds = @intCast(ncmds);
header.sizeofcmds = @intCast(sizeofcmds);
log.debug("writing Mach-O header {}", .{header});
@ -437,91 +436,56 @@ fn writeLinkeditSegmentData(self: *DebugSymbols, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
try self.writeSymtab(macho_file);
try self.writeStrtab();
const target = macho_file.base.comp.root_mod.resolved_target.result;
const page_size = MachO.getPageSize(target.cpu.arch);
const page_size = macho_file.getPageSize();
const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
var off = math.cast(u32, seg.fileoff) orelse return error.Overflow;
off = try self.writeSymtab(off, macho_file);
off = mem.alignForward(u32, off, @alignOf(u64));
off = try self.writeStrtab(off);
seg.filesize = off - seg.fileoff;
const aligned_size = mem.alignForward(u64, seg.filesize, page_size);
seg.vmsize = aligned_size;
}
fn writeSymtab(self: *DebugSymbols, macho_file: *MachO) !void {
pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 {
const tracy = trace(@src());
defer tracy.end();
const gpa = self.allocator;
const cmd = &self.symtab_cmd;
cmd.nsyms = macho_file.symtab_cmd.nsyms;
cmd.strsize = macho_file.symtab_cmd.strsize;
cmd.symoff = off;
var locals = std.ArrayList(macho.nlist_64).init(gpa);
defer locals.deinit();
try self.symtab.resize(gpa, cmd.nsyms);
try self.strtab.ensureUnusedCapacity(gpa, cmd.strsize - 1);
for (macho_file.locals.items, 0..) |sym, sym_id| {
if (sym.n_strx == 0) continue; // no name, skip
const sym_loc = MachO.SymbolWithLoc{ .sym_index = @as(u32, @intCast(sym_id)) };
if (macho_file.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip
if (macho_file.getGlobal(macho_file.getSymbolName(sym_loc)) != null) continue; // global symbol is either an export or import, skip
var out_sym = sym;
out_sym.n_strx = try self.strtab.insert(gpa, macho_file.getSymbolName(sym_loc));
try locals.append(out_sym);
if (macho_file.getZigObject()) |zo| {
zo.writeSymtab(macho_file, self);
}
for (macho_file.objects.items) |index| {
try macho_file.getFile(index).?.writeSymtab(macho_file, self);
}
for (macho_file.dylibs.items) |index| {
try macho_file.getFile(index).?.writeSymtab(macho_file, self);
}
if (macho_file.getInternalObject()) |internal| {
internal.writeSymtab(macho_file, self);
}
var exports = std.ArrayList(macho.nlist_64).init(gpa);
defer exports.deinit();
assert(self.strtab.items.len == cmd.strsize);
for (macho_file.globals.items) |global| {
const sym = macho_file.getSymbol(global);
if (sym.undf()) continue; // import, skip
var out_sym = sym;
out_sym.n_strx = try self.strtab.insert(gpa, macho_file.getSymbolName(global));
try exports.append(out_sym);
}
try self.file.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff);
const nlocals = locals.items.len;
const nexports = exports.items.len;
const nsyms = nlocals + nexports;
const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
const offset = mem.alignForward(u64, seg.fileoff, @alignOf(macho.nlist_64));
const needed_size = nsyms * @sizeOf(macho.nlist_64);
seg.filesize = offset + needed_size - seg.fileoff;
self.symtab_cmd.symoff = @as(u32, @intCast(offset));
self.symtab_cmd.nsyms = @as(u32, @intCast(nsyms));
const locals_off = @as(u32, @intCast(offset));
const locals_size = nlocals * @sizeOf(macho.nlist_64);
const exports_off = locals_off + locals_size;
const exports_size = nexports * @sizeOf(macho.nlist_64);
log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off });
try self.file.pwriteAll(mem.sliceAsBytes(locals.items), locals_off);
log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off });
try self.file.pwriteAll(mem.sliceAsBytes(exports.items), exports_off);
return off + cmd.nsyms * @sizeOf(macho.nlist_64);
}
fn writeStrtab(self: *DebugSymbols) !void {
const tracy = trace(@src());
defer tracy.end();
const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
const symtab_size = @as(u32, @intCast(self.symtab_cmd.nsyms * @sizeOf(macho.nlist_64)));
const offset = mem.alignForward(u64, self.symtab_cmd.symoff + symtab_size, @alignOf(u64));
const needed_size = mem.alignForward(u64, self.strtab.buffer.items.len, @alignOf(u64));
seg.filesize = offset + needed_size - seg.fileoff;
self.symtab_cmd.stroff = @as(u32, @intCast(offset));
self.symtab_cmd.strsize = @as(u32, @intCast(needed_size));
log.debug("writing string table from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
try self.file.pwriteAll(self.strtab.buffer.items, offset);
if (self.strtab.buffer.items.len < needed_size) {
// Ensure we are always padded to the actual length of the file.
try self.file.pwriteAll(&[_]u8{0}, offset + needed_size);
}
pub fn writeStrtab(self: *DebugSymbols, off: u32) !u32 {
const cmd = &self.symtab_cmd;
cmd.stroff = off;
try self.file.pwriteAll(self.strtab.items, cmd.stroff);
return off + cmd.strsize;
}
pub fn getSectionIndexes(self: *DebugSymbols, segment_index: u8) struct { start: u8, end: u8 } {
@ -561,7 +525,7 @@ const assert = std.debug.assert;
const fs = std.fs;
const link = @import("../../link.zig");
const load_commands = @import("load_commands.zig");
const log = std.log.scoped(.dsym);
const log = std.log.scoped(.link_dsym);
const macho = std.macho;
const makeStaticString = MachO.makeStaticString;
const math = std.math;

View File

@ -576,7 +576,7 @@ pub fn calcSymtabSize(self: *Dylib, macho_file: *MachO) !void {
}
}
pub fn writeSymtab(self: Dylib, macho_file: *MachO) void {
pub fn writeSymtab(self: Dylib, macho_file: *MachO, ctx: anytype) void {
const tracy = trace(@src());
defer tracy.end();
@ -585,10 +585,10 @@ pub fn writeSymtab(self: Dylib, macho_file: *MachO) void {
const file = global.getFile(macho_file) orelse continue;
if (file.getIndex() != self.index) continue;
const idx = global.getOutputSymtabIndex(macho_file) orelse continue;
const n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
macho_file.strtab.appendSliceAssumeCapacity(global.getName(macho_file));
macho_file.strtab.appendAssumeCapacity(0);
const out_sym = &macho_file.symtab.items[idx];
const n_strx = @as(u32, @intCast(ctx.strtab.items.len));
ctx.strtab.appendSliceAssumeCapacity(global.getName(macho_file));
ctx.strtab.appendAssumeCapacity(0);
const out_sym = &ctx.symtab.items[idx];
out_sym.n_strx = n_strx;
global.setOutputSym(macho_file, out_sym);
}

View File

@ -139,15 +139,15 @@ pub fn calcSymtabSize(self: *InternalObject, macho_file: *MachO) !void {
}
}
pub fn writeSymtab(self: InternalObject, macho_file: *MachO) void {
pub fn writeSymtab(self: InternalObject, macho_file: *MachO, ctx: anytype) void {
for (self.symbols.items) |sym_index| {
const sym = macho_file.getSymbol(sym_index);
if (sym.getFile(macho_file)) |file| if (file.getIndex() != self.index) continue;
const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
const n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
macho_file.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
macho_file.strtab.appendAssumeCapacity(0);
const out_sym = &macho_file.symtab.items[idx];
const n_strx = @as(u32, @intCast(ctx.strtab.items.len));
ctx.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
ctx.strtab.appendAssumeCapacity(0);
const out_sym = &ctx.symtab.items[idx];
out_sym.n_strx = n_strx;
sym.setOutputSym(macho_file, out_sym);
}

View File

@ -1320,7 +1320,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {
}
}
pub fn writeSymtab(self: Object, macho_file: *MachO) error{Overflow}!void {
pub fn writeSymtab(self: Object, macho_file: *MachO, ctx: anytype) error{Overflow}!void {
const tracy = trace(@src());
defer tracy.end();
@ -1329,19 +1329,19 @@ pub fn writeSymtab(self: Object, macho_file: *MachO) error{Overflow}!void {
const file = sym.getFile(macho_file) orelse continue;
if (file.getIndex() != self.index) continue;
const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
const n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
macho_file.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
macho_file.strtab.appendAssumeCapacity(0);
const out_sym = &macho_file.symtab.items[idx];
const n_strx = @as(u32, @intCast(ctx.strtab.items.len));
ctx.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
ctx.strtab.appendAssumeCapacity(0);
const out_sym = &ctx.symtab.items[idx];
out_sym.n_strx = n_strx;
sym.setOutputSym(macho_file, out_sym);
}
if (macho_file.base.comp.config.debug_format != .strip and self.hasDebugInfo())
try self.writeStabs(macho_file);
try self.writeStabs(macho_file, ctx);
}
pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void {
pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{Overflow}!void {
const writeFuncStab = struct {
inline fn writeFuncStab(
n_strx: u32,
@ -1349,30 +1349,30 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
n_value: u64,
size: u64,
index: u32,
ctx: *MachO,
context: anytype,
) void {
ctx.symtab.items[index] = .{
context.symtab.items[index] = .{
.n_strx = 0,
.n_type = macho.N_BNSYM,
.n_sect = n_sect,
.n_desc = 0,
.n_value = n_value,
};
ctx.symtab.items[index + 1] = .{
context.symtab.items[index + 1] = .{
.n_strx = n_strx,
.n_type = macho.N_FUN,
.n_sect = n_sect,
.n_desc = 0,
.n_value = n_value,
};
ctx.symtab.items[index + 2] = .{
context.symtab.items[index + 2] = .{
.n_strx = 0,
.n_type = macho.N_FUN,
.n_sect = 0,
.n_desc = 0,
.n_value = size,
};
ctx.symtab.items[index + 3] = .{
context.symtab.items[index + 3] = .{
.n_strx = 0,
.n_type = macho.N_ENSYM,
.n_sect = n_sect,
@ -1392,10 +1392,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
// Open scope
// N_SO comp_dir
var n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
macho_file.strtab.appendSliceAssumeCapacity(comp_dir);
macho_file.strtab.appendAssumeCapacity(0);
macho_file.symtab.items[index] = .{
var n_strx = @as(u32, @intCast(ctx.strtab.items.len));
ctx.strtab.appendSliceAssumeCapacity(comp_dir);
ctx.strtab.appendAssumeCapacity(0);
ctx.symtab.items[index] = .{
.n_strx = n_strx,
.n_type = macho.N_SO,
.n_sect = 0,
@ -1404,10 +1404,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
};
index += 1;
// N_SO tu_name
n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
macho_file.strtab.appendSliceAssumeCapacity(tu_name);
macho_file.strtab.appendAssumeCapacity(0);
macho_file.symtab.items[index] = .{
n_strx = @as(u32, @intCast(ctx.strtab.items.len));
ctx.strtab.appendSliceAssumeCapacity(tu_name);
ctx.strtab.appendAssumeCapacity(0);
ctx.symtab.items[index] = .{
.n_strx = n_strx,
.n_type = macho.N_SO,
.n_sect = 0,
@ -1416,18 +1416,18 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
};
index += 1;
// N_OSO path
n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
n_strx = @as(u32, @intCast(ctx.strtab.items.len));
if (self.archive) |ar| {
macho_file.strtab.appendSliceAssumeCapacity(ar.path);
macho_file.strtab.appendAssumeCapacity('(');
macho_file.strtab.appendSliceAssumeCapacity(self.path);
macho_file.strtab.appendAssumeCapacity(')');
macho_file.strtab.appendAssumeCapacity(0);
ctx.strtab.appendSliceAssumeCapacity(ar.path);
ctx.strtab.appendAssumeCapacity('(');
ctx.strtab.appendSliceAssumeCapacity(self.path);
ctx.strtab.appendAssumeCapacity(')');
ctx.strtab.appendAssumeCapacity(0);
} else {
macho_file.strtab.appendSliceAssumeCapacity(self.path);
macho_file.strtab.appendAssumeCapacity(0);
ctx.strtab.appendSliceAssumeCapacity(self.path);
ctx.strtab.appendAssumeCapacity(0);
}
macho_file.symtab.items[index] = .{
ctx.symtab.items[index] = .{
.n_strx = n_strx,
.n_type = macho.N_OSO,
.n_sect = 0,
@ -1448,17 +1448,17 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
const sect = macho_file.sections.items(.header)[sym.out_n_sect];
const sym_n_strx = n_strx: {
const symtab_index = sym.getOutputSymtabIndex(macho_file).?;
const osym = macho_file.symtab.items[symtab_index];
const osym = ctx.symtab.items[symtab_index];
break :n_strx osym.n_strx;
};
const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.out_n_sect + 1) else 0;
const sym_n_value = sym.getAddress(.{}, macho_file);
const sym_size = sym.getSize(macho_file);
if (sect.isCode()) {
writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, macho_file);
writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, ctx);
index += 4;
} else if (sym.visibility == .global) {
macho_file.symtab.items[index] = .{
ctx.symtab.items[index] = .{
.n_strx = sym_n_strx,
.n_type = macho.N_GSYM,
.n_sect = sym_n_sect,
@ -1467,7 +1467,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
};
index += 1;
} else {
macho_file.symtab.items[index] = .{
ctx.symtab.items[index] = .{
.n_strx = sym_n_strx,
.n_type = macho.N_STSYM,
.n_sect = sym_n_sect,
@ -1480,7 +1480,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
// Close scope
// N_SO
macho_file.symtab.items[index] = .{
ctx.symtab.items[index] = .{
.n_strx = 0,
.n_type = macho.N_SO,
.n_sect = 0,
@ -1493,10 +1493,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
for (self.stab_files.items) |sf| {
// Open scope
// N_SO comp_dir
var n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
macho_file.strtab.appendSliceAssumeCapacity(sf.getCompDir(self));
macho_file.strtab.appendAssumeCapacity(0);
macho_file.symtab.items[index] = .{
var n_strx = @as(u32, @intCast(ctx.strtab.items.len));
ctx.strtab.appendSliceAssumeCapacity(sf.getCompDir(self));
ctx.strtab.appendAssumeCapacity(0);
ctx.symtab.items[index] = .{
.n_strx = n_strx,
.n_type = macho.N_SO,
.n_sect = 0,
@ -1505,10 +1505,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
};
index += 1;
// N_SO tu_name
n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
macho_file.strtab.appendSliceAssumeCapacity(sf.getTuName(self));
macho_file.strtab.appendAssumeCapacity(0);
macho_file.symtab.items[index] = .{
n_strx = @as(u32, @intCast(ctx.strtab.items.len));
ctx.strtab.appendSliceAssumeCapacity(sf.getTuName(self));
ctx.strtab.appendAssumeCapacity(0);
ctx.symtab.items[index] = .{
.n_strx = n_strx,
.n_type = macho.N_SO,
.n_sect = 0,
@ -1517,10 +1517,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
};
index += 1;
// N_OSO path
n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
macho_file.strtab.appendSliceAssumeCapacity(sf.getOsoPath(self));
macho_file.strtab.appendAssumeCapacity(0);
macho_file.symtab.items[index] = .{
n_strx = @as(u32, @intCast(ctx.strtab.items.len));
ctx.strtab.appendSliceAssumeCapacity(sf.getOsoPath(self));
ctx.strtab.appendAssumeCapacity(0);
ctx.symtab.items[index] = .{
.n_strx = n_strx,
.n_type = macho.N_OSO,
.n_sect = 0,
@ -1536,7 +1536,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
if (!sym.flags.output_symtab) continue;
const sym_n_strx = n_strx: {
const symtab_index = sym.getOutputSymtabIndex(macho_file).?;
const osym = macho_file.symtab.items[symtab_index];
const osym = ctx.symtab.items[symtab_index];
break :n_strx osym.n_strx;
};
const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.out_n_sect + 1) else 0;
@ -1544,11 +1544,11 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
const sym_size = sym.getSize(macho_file);
switch (stab.tag) {
.func => {
writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, macho_file);
writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, ctx);
index += 4;
},
.global => {
macho_file.symtab.items[index] = .{
ctx.symtab.items[index] = .{
.n_strx = sym_n_strx,
.n_type = macho.N_GSYM,
.n_sect = sym_n_sect,
@ -1558,7 +1558,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
index += 1;
},
.static => {
macho_file.symtab.items[index] = .{
ctx.symtab.items[index] = .{
.n_strx = sym_n_strx,
.n_type = macho.N_STSYM,
.n_sect = sym_n_sect,
@ -1572,7 +1572,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
// Close scope
// N_SO
macho_file.symtab.items[index] = .{
ctx.symtab.items[index] = .{
.n_strx = 0,
.n_type = macho.N_SO,
.n_sect = 0,

View File

@ -310,7 +310,7 @@ pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) !void {
}
}
pub fn writeSymtab(self: ZigObject, macho_file: *MachO) void {
pub fn writeSymtab(self: ZigObject, macho_file: *MachO, ctx: anytype) void {
const tracy = trace(@src());
defer tracy.end();
@ -319,10 +319,10 @@ pub fn writeSymtab(self: ZigObject, macho_file: *MachO) void {
const file = sym.getFile(macho_file) orelse continue;
if (file.getIndex() != self.index) continue;
const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
const n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
macho_file.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
macho_file.strtab.appendAssumeCapacity(0);
const out_sym = &macho_file.symtab.items[idx];
const n_strx = @as(u32, @intCast(ctx.strtab.items.len));
ctx.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
ctx.strtab.appendAssumeCapacity(0);
const out_sym = &ctx.symtab.items[idx];
out_sym.n_strx = n_strx;
sym.setOutputSym(macho_file, out_sym);
}
@ -531,7 +531,7 @@ pub fn updateFunc(
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
var decl_state: ?Dwarf.DeclState = null; // TODO: Dwarf
var decl_state: ?Dwarf.DeclState = if (macho_file.getDebugSymbols()) |d_sym| try d_sym.dwarf.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;
@ -557,16 +557,16 @@ pub fn updateFunc(
const sect_index = try self.getDeclOutputSection(macho_file, decl, code);
try self.updateDeclCode(macho_file, decl_index, sym_index, sect_index, code);
// if (decl_state) |*ds| {
// const sym = elf_file.symbol(sym_index);
// try self.dwarf.?.commitDeclState(
// mod,
// decl_index,
// sym.value,
// sym.atom(elf_file).?.size,
// ds,
// );
// }
if (decl_state) |*ds| {
const sym = macho_file.getSymbol(sym_index);
try macho_file.getDebugSymbols().?.dwarf.commitDeclState(
mod,
decl_index,
sym.getAddress(.{}, macho_file),
sym.getAtom(macho_file).?.size,
ds,
);
}
// Since we updated the vaddr and the size, each corresponding export
// symbol also needs to be updated.
@ -606,7 +606,7 @@ pub fn updateDecl(
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
var decl_state: ?Dwarf.DeclState = null; // TODO: Dwarf
var decl_state: ?Dwarf.DeclState = if (macho_file.getDebugSymbols()) |d_sym| try d_sym.dwarf.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;
@ -638,15 +638,16 @@ pub fn updateDecl(
try self.updateDeclCode(macho_file, decl_index, sym_index, sect_index, code);
}
// if (decl_state) |*ds| {
// try self.d_sym.?.dwarf.commitDeclState(
// mod,
// decl_index,
// addr,
// self.getAtom(atom_index).size,
// ds,
// );
// }
if (decl_state) |*ds| {
const sym = macho_file.getSymbol(sym_index);
try macho_file.getDebugSymbols().?.dwarf.commitDeclState(
mod,
decl_index,
sym.getAddress(.{}, macho_file),
sym.getAtom(macho_file).?.size,
ds,
);
}
// Since we updated the vaddr and the size, each corresponding export symbol also
// needs to be updated.
@ -1220,13 +1221,14 @@ 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;
_ = mod;
_ = decl_index;
// TODO: Dwarf
if (macho_file.getDebugSymbols()) |d_sym| {
try d_sym.dwarf.updateDeclLineNumber(mod, decl_index);
}
}
pub fn deleteDeclExport(

View File

@ -90,9 +90,9 @@ pub const File = union(enum) {
};
}
pub fn writeSymtab(file: File, macho_file: *MachO) !void {
pub fn writeSymtab(file: File, macho_file: *MachO, ctx: anytype) !void {
return switch (file) {
inline else => |x| x.writeSymtab(macho_file),
inline else => |x| x.writeSymtab(macho_file, ctx),
};
}

View File

@ -5,6 +5,7 @@ const macho = std.macho;
const mem = std.mem;
const Allocator = mem.Allocator;
const DebugSymbols = @import("DebugSymbols.zig");
const Dylib = @import("Dylib.zig");
const MachO = @import("../MachO.zig");
@ -97,6 +98,27 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) u32 {
return @as(u32, @intCast(sizeofcmds));
}
pub fn calcLoadCommandsSizeDsym(macho_file: *MachO, dsym: *const DebugSymbols) u32 {
var sizeofcmds: u64 = 0;
// LC_SEGMENT_64
sizeofcmds += @sizeOf(macho.segment_command_64) * (macho_file.segments.items.len - 1);
for (macho_file.segments.items) |seg| {
sizeofcmds += seg.nsects * @sizeOf(macho.section_64);
}
sizeofcmds += @sizeOf(macho.segment_command_64) * dsym.segments.items.len;
for (dsym.segments.items) |seg| {
sizeofcmds += seg.nsects * @sizeOf(macho.section_64);
}
// LC_SYMTAB
sizeofcmds += @sizeOf(macho.symtab_command);
// LC_UUID
sizeofcmds += @sizeOf(macho.uuid_command);
return @as(u32, @intCast(sizeofcmds));
}
pub fn calcLoadCommandsSizeObject(macho_file: *MachO) u32 {
var sizeofcmds: u64 = 0;