diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 8e730a6eb1..17afe328fe 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -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 diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 1f634e45c2..c2a098b9f5 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -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 { diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 74a4afeb54..10f6717118 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -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; diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig index abad323213..32f7a018a2 100644 --- a/src/link/MachO/Dylib.zig +++ b/src/link/MachO/Dylib.zig @@ -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); } diff --git a/src/link/MachO/InternalObject.zig b/src/link/MachO/InternalObject.zig index bf770f02f0..30b750260c 100644 --- a/src/link/MachO/InternalObject.zig +++ b/src/link/MachO/InternalObject.zig @@ -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); } diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 5f98d490aa..d6c5010b31 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -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, diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 3b40b52ce3..f903c997fb 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -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( diff --git a/src/link/MachO/file.zig b/src/link/MachO/file.zig index 67b2b9106e..cb3bbe283a 100644 --- a/src/link/MachO/file.zig +++ b/src/link/MachO/file.zig @@ -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), }; } diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 7d045779fe..cf8dca92e0 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -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;