authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-29 20:33:54+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-01-29 20:33:54+01:00
log3e939e61538706f37abb76a97af0ee77c15b24fc
tree115e68db5a398834f7bf3034275ad5e54a27da04
parentf93a36c091a151ed02602d2f330f7206eb9f95a3
parent78740e55406ebf82371f385bbbf54f224949b8cb
signaturebadge-check Signed by PGP key B5690EEEBB952194

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

macho: reinstate DWARF in self-hosted x86_64-macho

9 files changed, 278 insertions(+), 283 deletions(-)

src/link/Dwarf.zig-1
...@@ -1468,7 +1468,6 @@ pub fn commitDeclState(...@@ -1468,7 +1468,6 @@ pub fn commitDeclState(
1468 .target = reloc.target,1468 .target = reloc.target,
1469 .offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off,1469 .offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off,
1470 .addend = 0,1470 .addend = 0,
1471 .prev_vaddr = 0,
1472 });1471 });
1473 },1472 },
1474 .elf => {}, // TODO1473 .elf => {}, // TODO
src/link/MachO.zig+45-37
...@@ -256,32 +256,39 @@ pub fn createEmpty(...@@ -256,32 +256,39 @@ pub fn createEmpty(
256 .program_code_size_hint = options.program_code_size_hint,256 .program_code_size_hint = options.program_code_size_hint,
257 });257 });
258258
259 // TODO init dwarf259 switch (comp.config.debug_format) {
260260 .strip => {},
261 // if (comp.config.debug_format != .strip) {261 .dwarf => if (!self.base.isRelocatable()) {
262 // // Create dSYM bundle.262 // Create dSYM bundle.
263 // log.debug("creating {s}.dSYM bundle", .{emit.sub_path});263 log.debug("creating {s}.dSYM bundle", .{emit.sub_path});
264264
265 // const d_sym_path = try std.fmt.allocPrint(265 const sep = fs.path.sep_str;
266 // arena,266 const d_sym_path = try std.fmt.allocPrint(
267 // "{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF",267 arena,
268 // .{emit.sub_path},268 "{s}.dSYM" ++ sep ++ "Contents" ++ sep ++ "Resources" ++ sep ++ "DWARF",
269 // );269 .{emit.sub_path},
270270 );
271 // var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{});271
272 // defer d_sym_bundle.close();272 var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{});
273273 defer d_sym_bundle.close();
274 // const d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{274
275 // .truncate = false,275 const d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{
276 // .read = true,276 .truncate = false,
277 // });277 .read = true,
278278 });
279 // self.d_sym = .{279
280 // .allocator = gpa,280 self.d_sym = .{
281 // .dwarf = link.File.Dwarf.init(&self.base, .dwarf32),281 .allocator = gpa,
282 // .file = d_sym_file,282 .dwarf = link.File.Dwarf.init(&self.base, .dwarf32),
283 // };283 .file = d_sym_file,
284 // }284 };
285 try self.d_sym.?.initMetadata(self);
286 } else {
287 try self.reportUnexpectedError("TODO: implement generating and emitting __DWARF in .o file", .{});
288 return error.Unexpected;
289 },
290 .code_view => unreachable,
291 }
285 }292 }
286 }293 }
287294
...@@ -692,6 +699,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node...@@ -692,6 +699,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
692 const ncmds, const sizeofcmds, const uuid_cmd_offset = try self.writeLoadCommands();699 const ncmds, const sizeofcmds, const uuid_cmd_offset = try self.writeLoadCommands();
693 try self.writeHeader(ncmds, sizeofcmds);700 try self.writeHeader(ncmds, sizeofcmds);
694 try self.writeUuid(uuid_cmd_offset, self.requiresCodeSig());701 try self.writeUuid(uuid_cmd_offset, self.requiresCodeSig());
702 if (self.getDebugSymbols()) |dsym| try dsym.flushModule(self);
695703
696 if (codesig) |*csig| {704 if (codesig) |*csig| {
697 try self.writeCodeSignature(csig); // code signing always comes last705 try self.writeCodeSignature(csig); // code signing always comes last
...@@ -731,9 +739,6 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -731,9 +739,6 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
731 try argv.append("-r");739 try argv.append("-r");
732 }740 }
733741
734 try argv.append("-o");
735 try argv.append(full_out_path);
736
737 if (self.base.isRelocatable()) {742 if (self.base.isRelocatable()) {
738 for (comp.objects) |obj| {743 for (comp.objects) |obj| {
739 try argv.append(obj.path);744 try argv.append(obj.path);
...@@ -2047,7 +2052,11 @@ pub fn sortSections(self: *MachO) !void {...@@ -2047,7 +2052,11 @@ pub fn sortSections(self: *MachO) !void {
2047 for (&[_]*?u8{2052 for (&[_]*?u8{
2048 &self.data_sect_index,2053 &self.data_sect_index,
2049 &self.got_sect_index,2054 &self.got_sect_index,
2055 &self.zig_text_sect_index,
2050 &self.zig_got_sect_index,2056 &self.zig_got_sect_index,
2057 &self.zig_const_sect_index,
2058 &self.zig_data_sect_index,
2059 &self.zig_bss_sect_index,
2051 &self.stubs_sect_index,2060 &self.stubs_sect_index,
2052 &self.stubs_helper_sect_index,2061 &self.stubs_helper_sect_index,
2053 &self.la_symbol_ptr_sect_index,2062 &self.la_symbol_ptr_sect_index,
...@@ -2901,16 +2910,16 @@ pub fn writeSymtab(self: *MachO, off: u32) !u32 {...@@ -2901,16 +2910,16 @@ pub fn writeSymtab(self: *MachO, off: u32) !u32 {
2901 try self.strtab.ensureUnusedCapacity(gpa, cmd.strsize - 1);2910 try self.strtab.ensureUnusedCapacity(gpa, cmd.strsize - 1);
29022911
2903 if (self.getZigObject()) |zo| {2912 if (self.getZigObject()) |zo| {
2904 zo.writeSymtab(self);2913 zo.writeSymtab(self, self);
2905 }2914 }
2906 for (self.objects.items) |index| {2915 for (self.objects.items) |index| {
2907 try self.getFile(index).?.writeSymtab(self);2916 try self.getFile(index).?.writeSymtab(self, self);
2908 }2917 }
2909 for (self.dylibs.items) |index| {2918 for (self.dylibs.items) |index| {
2910 try self.getFile(index).?.writeSymtab(self);2919 try self.getFile(index).?.writeSymtab(self, self);
2911 }2920 }
2912 if (self.getInternalObject()) |internal| {2921 if (self.getInternalObject()) |internal| {
2913 internal.writeSymtab(self);2922 internal.writeSymtab(self, self);
2914 }2923 }
29152924
2916 assert(self.strtab.items.len == cmd.strsize);2925 assert(self.strtab.items.len == cmd.strsize);
...@@ -3176,7 +3185,7 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex)...@@ -3176,7 +3185,7 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex)
31763185
3177pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: InternPool.DeclIndex) !void {3186pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: InternPool.DeclIndex) !void {
3178 if (self.llvm_object) |_| return;3187 if (self.llvm_object) |_| return;
3179 return self.getZigObject().?.updateDeclLineNumber(module, decl_index);3188 return self.getZigObject().?.updateDeclLineNumber(self, module, decl_index);
3180}3189}
31813190
3182pub fn updateExports(3191pub fn updateExports(
...@@ -3909,9 +3918,8 @@ fn reportDuplicates(self: *MachO, dupes: anytype) error{ HasDuplicates, OutOfMem...@@ -3909,9 +3918,8 @@ fn reportDuplicates(self: *MachO, dupes: anytype) error{ HasDuplicates, OutOfMem
3909}3918}
39103919
3911pub fn getDebugSymbols(self: *MachO) ?*DebugSymbols {3920pub fn getDebugSymbols(self: *MachO) ?*DebugSymbols {
3912 if (self.d_sym) |*ds| {3921 if (self.d_sym) |*ds| return ds;
3913 return ds;3922 return null;
3914 } else return null;
3915}3923}
39163924
3917pub fn ptraceAttach(self: *MachO, pid: std.os.pid_t) !void {3925pub fn ptraceAttach(self: *MachO, pid: std.os.pid_t) !void {
src/link/MachO/DebugSymbols.zig+117-153
...@@ -3,6 +3,7 @@ dwarf: Dwarf,...@@ -3,6 +3,7 @@ dwarf: Dwarf,
3file: fs.File,3file: fs.File,
44
5symtab_cmd: macho.symtab_command = .{},5symtab_cmd: macho.symtab_command = .{},
6uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 },
67
7segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},8segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},
8sections: std.ArrayListUnmanaged(macho.section_64) = .{},9sections: std.ArrayListUnmanaged(macho.section_64) = .{},
...@@ -22,9 +23,12 @@ debug_aranges_section_dirty: bool = false,...@@ -22,9 +23,12 @@ debug_aranges_section_dirty: bool = false,
22debug_info_header_dirty: bool = false,23debug_info_header_dirty: bool = false,
23debug_line_header_dirty: bool = false,24debug_line_header_dirty: bool = false,
2425
25strtab: StringTable = .{},
26relocs: std.ArrayListUnmanaged(Reloc) = .{},26relocs: std.ArrayListUnmanaged(Reloc) = .{},
2727
28/// Output synthetic sections
29symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
30strtab: std.ArrayListUnmanaged(u8) = .{},
31
28pub const Reloc = struct {32pub const Reloc = struct {
29 type: enum {33 type: enum {
30 direct_load,34 direct_load,
...@@ -33,18 +37,17 @@ pub const Reloc = struct {...@@ -33,18 +37,17 @@ pub const Reloc = struct {
33 target: u32,37 target: u32,
34 offset: u64,38 offset: u64,
35 addend: u32,39 addend: u32,
36 prev_vaddr: u64,
37};40};
3841
39/// You must call this function *after* `MachO.populateMissingMetadata()`42/// You must call this function *after* `ZigObject.initMetadata()`
40/// has been called to get a viable debug symbols output.43/// has been called to get a viable debug symbols output.
41pub fn populateMissingMetadata(self: *DebugSymbols, macho_file: *MachO) !void {44pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {
42 const target = macho_file.base.comp.root_mod.resolved_target.result;45 try self.strtab.append(self.allocator, 0);
4346
44 if (self.dwarf_segment_cmd_index == null) {47 if (self.dwarf_segment_cmd_index == null) {
45 self.dwarf_segment_cmd_index = @as(u8, @intCast(self.segments.items.len));48 self.dwarf_segment_cmd_index = @as(u8, @intCast(self.segments.items.len));
4649
47 const page_size = MachO.getPageSize(target.cpu.arch);50 const page_size = macho_file.getPageSize();
48 const off = @as(u64, @intCast(page_size));51 const off = @as(u64, @intCast(page_size));
49 const ideal_size: u16 = 200 + 128 + 160 + 250;52 const ideal_size: u16 = 200 + 128 + 160 + 250;
50 const needed_size = mem.alignForward(u64, padToIdeal(ideal_size), page_size);53 const needed_size = mem.alignForward(u64, padToIdeal(ideal_size), page_size);
...@@ -203,35 +206,24 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -203,35 +206,24 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
203 // and it corresponds to the Zig source code.206 // and it corresponds to the Zig source code.
204 const zcu = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented;207 const zcu = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented;
205208
209 try self.dwarf.flushModule(zcu);
210
206 for (self.relocs.items) |*reloc| {211 for (self.relocs.items) |*reloc| {
207 const sym = switch (reloc.type) {212 const sym = macho_file.getSymbol(reloc.target);
208 .direct_load => macho_file.getSymbol(.{ .sym_index = reloc.target }),213 const sym_name = sym.getName(macho_file);
209 .got_load => blk: {214 const addr = switch (reloc.type) {
210 const got_index = macho_file.got_table.lookup.get(.{ .sym_index = reloc.target }).?;215 .direct_load => sym.getAddress(.{}, macho_file),
211 const got_entry = macho_file.got_table.entries.items[got_index];216 .got_load => sym.getGotAddress(macho_file),
212 break :blk macho_file.getSymbol(got_entry);
213 },
214 };
215 if (sym.n_value == reloc.prev_vaddr) continue;
216
217 const sym_name = switch (reloc.type) {
218 .direct_load => macho_file.getSymbolName(.{ .sym_index = reloc.target }),
219 .got_load => blk: {
220 const got_index = macho_file.got_table.lookup.get(.{ .sym_index = reloc.target }).?;
221 const got_entry = macho_file.got_table.entries.items[got_index];
222 break :blk macho_file.getSymbolName(got_entry);
223 },
224 };217 };
225 const sect = &self.sections.items[self.debug_info_section_index.?];218 const sect = &self.sections.items[self.debug_info_section_index.?];
226 const file_offset = sect.offset + reloc.offset;219 const file_offset = sect.offset + reloc.offset;
227 log.debug("resolving relocation: {d}@{x} ('{s}') at offset {x}", .{220 log.debug("resolving relocation: {d}@{x} ('{s}') at offset {x}", .{
228 reloc.target,221 reloc.target,
229 sym.n_value,222 addr,
230 sym_name,223 sym_name,
231 file_offset,224 file_offset,
232 });225 });
233 try self.file.pwriteAll(mem.asBytes(&sym.n_value), file_offset);226 try self.file.pwriteAll(mem.asBytes(&addr), file_offset);
234 reloc.prev_vaddr = sym.n_value;
235 }227 }
236228
237 if (self.debug_abbrev_section_dirty) {229 if (self.debug_abbrev_section_dirty) {
...@@ -242,7 +234,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -242,7 +234,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
242 if (self.debug_info_header_dirty) {234 if (self.debug_info_header_dirty) {
243 // Currently only one compilation unit is supported, so the address range is simply235 // Currently only one compilation unit is supported, so the address range is simply
244 // identical to the main program header virtual address and memory size.236 // identical to the main program header virtual address and memory size.
245 const text_section = macho_file.sections.items(.header)[macho_file.text_section_index.?];237 const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?];
246 const low_pc = text_section.addr;238 const low_pc = text_section.addr;
247 const high_pc = text_section.addr + text_section.size;239 const high_pc = text_section.addr + text_section.size;
248 try self.dwarf.writeDbgInfoHeader(zcu, low_pc, high_pc);240 try self.dwarf.writeDbgInfoHeader(zcu, low_pc, high_pc);
...@@ -252,7 +244,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -252,7 +244,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
252 if (self.debug_aranges_section_dirty) {244 if (self.debug_aranges_section_dirty) {
253 // Currently only one compilation unit is supported, so the address range is simply245 // Currently only one compilation unit is supported, so the address range is simply
254 // identical to the main program header virtual address and memory size.246 // identical to the main program header virtual address and memory size.
255 const text_section = macho_file.sections.items(.header)[macho_file.text_section_index.?];247 const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?];
256 try self.dwarf.writeDbgAranges(text_section.addr, text_section.size);248 try self.dwarf.writeDbgAranges(text_section.addr, text_section.size);
257 self.debug_aranges_section_dirty = false;249 self.debug_aranges_section_dirty = false;
258 }250 }
...@@ -276,17 +268,8 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -276,17 +268,8 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
276 try self.writeLinkeditSegmentData(macho_file);268 try self.writeLinkeditSegmentData(macho_file);
277269
278 // Write load commands270 // Write load commands
279 var lc_buffer = std.ArrayList(u8).init(self.allocator);271 const ncmds, const sizeofcmds = try self.writeLoadCommands(macho_file);
280 defer lc_buffer.deinit();272 try self.writeHeader(macho_file, ncmds, sizeofcmds);
281 const lc_writer = lc_buffer.writer();
282
283 try self.writeSegmentHeaders(macho_file, lc_writer);
284 try lc_writer.writeStruct(self.symtab_cmd);
285 try lc_writer.writeStruct(macho_file.uuid_cmd);
286
287 const ncmds = load_commands.calcNumOfLCs(lc_buffer.items);
288 try self.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64));
289 try self.writeHeader(macho_file, ncmds, @as(u32, @intCast(lc_buffer.items.len)));
290273
291 assert(!self.debug_abbrev_section_dirty);274 assert(!self.debug_abbrev_section_dirty);
292 assert(!self.debug_aranges_section_dirty);275 assert(!self.debug_aranges_section_dirty);
...@@ -299,8 +282,9 @@ pub fn deinit(self: *DebugSymbols) void {...@@ -299,8 +282,9 @@ pub fn deinit(self: *DebugSymbols) void {
299 self.segments.deinit(gpa);282 self.segments.deinit(gpa);
300 self.sections.deinit(gpa);283 self.sections.deinit(gpa);
301 self.dwarf.deinit();284 self.dwarf.deinit();
302 self.strtab.deinit(gpa);
303 self.relocs.deinit(gpa);285 self.relocs.deinit(gpa);
286 self.symtab.deinit(gpa);
287 self.strtab.deinit(gpa);
304}288}
305289
306pub fn swapRemoveRelocs(self: *DebugSymbols, target: u32) void {290pub fn swapRemoveRelocs(self: *DebugSymbols, target: u32) void {
...@@ -324,7 +308,7 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {...@@ -324,7 +308,7 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
324 // however at the cost of having LINKEDIT preceed DWARF in dSYM binary which we308 // however at the cost of having LINKEDIT preceed DWARF in dSYM binary which we
325 // do not want as we want to be able to incrementally move DWARF sections in the309 // do not want as we want to be able to incrementally move DWARF sections in the
326 // file as we please.310 // file as we please.
327 const last_seg = macho_file.getLinkeditSegmentPtr();311 const last_seg = macho_file.getLinkeditSegment();
328 break :blk last_seg.vmaddr + last_seg.vmsize;312 break :blk last_seg.vmaddr + last_seg.vmsize;
329 };313 };
330 const dwarf_segment = self.getDwarfSegmentPtr();314 const dwarf_segment = self.getDwarfSegmentPtr();
...@@ -334,8 +318,7 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {...@@ -334,8 +318,7 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
334 file_size = @max(file_size, header.offset + header.size);318 file_size = @max(file_size, header.offset + header.size);
335 }319 }
336320
337 const target = macho_file.base.comp.root_mod.resolved_target.result;321 const page_size = macho_file.getPageSize();
338 const page_size = MachO.getPageSize(target.cpu.arch);
339 const aligned_size = mem.alignForward(u64, file_size, page_size);322 const aligned_size = mem.alignForward(u64, file_size, page_size);
340 dwarf_segment.vmaddr = base_vmaddr;323 dwarf_segment.vmaddr = base_vmaddr;
341 dwarf_segment.filesize = aligned_size;324 dwarf_segment.filesize = aligned_size;
...@@ -355,54 +338,70 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {...@@ -355,54 +338,70 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
355 log.debug("found __LINKEDIT segment free space at 0x{x}", .{linkedit.fileoff});338 log.debug("found __LINKEDIT segment free space at 0x{x}", .{linkedit.fileoff});
356}339}
357340
358fn writeSegmentHeaders(self: *DebugSymbols, macho_file: *MachO, writer: anytype) !void {341fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } {
359 // Write segment/section headers from the binary file first.342 const gpa = self.allocator;
360 const end = macho_file.linkedit_segment_cmd_index.?;343 const needed_size = load_commands.calcLoadCommandsSizeDsym(macho_file, self);
361 for (macho_file.segments.items[0..end], 0..) |seg, i| {344 const buffer = try gpa.alloc(u8, needed_size);
362 const indexes = macho_file.getSectionIndexes(@as(u8, @intCast(i)));345 defer gpa.free(buffer);
363 var out_seg = seg;346
364 out_seg.fileoff = 0;347 var stream = std.io.fixedBufferStream(buffer);
365 out_seg.filesize = 0;348 var cwriter = std.io.countingWriter(stream.writer());
366 out_seg.cmdsize = @sizeOf(macho.segment_command_64);349 const writer = cwriter.writer();
367 out_seg.nsects = 0;
368
369 // Update section headers count; any section with size of 0 is excluded
370 // since it doesn't have any data in the final binary file.
371 for (macho_file.sections.items(.header)[indexes.start..indexes.end]) |header| {
372 if (header.size == 0) continue;
373 out_seg.cmdsize += @sizeOf(macho.section_64);
374 out_seg.nsects += 1;
375 }
376350
377 if (out_seg.nsects == 0 and351 var ncmds: usize = 0;
378 (mem.eql(u8, out_seg.segName(), "__DATA_CONST") or
379 mem.eql(u8, out_seg.segName(), "__DATA"))) continue;
380352
381 try writer.writeStruct(out_seg);353 // UUID comes first presumably to speed up lookup by the consumer like lldb.
382 for (macho_file.sections.items(.header)[indexes.start..indexes.end]) |header| {354 @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);
383 if (header.size == 0) continue;355 try writer.writeStruct(self.uuid_cmd);
384 var out_header = header;356 ncmds += 1;
385 out_header.offset = 0;357
386 try writer.writeStruct(out_header);358 // Segment and section load commands
359 {
360 // Write segment/section headers from the binary file first.
361 const slice = macho_file.sections.slice();
362 var sect_id: usize = 0;
363 for (macho_file.segments.items, 0..) |seg, seg_id| {
364 if (seg_id == macho_file.linkedit_seg_index.?) break;
365 var out_seg = seg;
366 out_seg.fileoff = 0;
367 out_seg.filesize = 0;
368 try writer.writeStruct(out_seg);
369 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
370 var out_header = header;
371 out_header.offset = 0;
372 try writer.writeStruct(out_header);
373 }
374 sect_id += seg.nsects;
387 }375 }
388 }376 ncmds += macho_file.segments.items.len - 1;
389 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.377
390 for (self.segments.items, 0..) |seg, i| {378 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
391 const indexes = self.getSectionIndexes(@as(u8, @intCast(i)));379 sect_id = 0;
392 try writer.writeStruct(seg);380 for (self.segments.items) |seg| {
393 for (self.sections.items[indexes.start..indexes.end]) |header| {381 try writer.writeStruct(seg);
394 try writer.writeStruct(header);382 for (self.sections.items[sect_id..][0..seg.nsects]) |header| {
383 try writer.writeStruct(header);
384 }
385 sect_id += seg.nsects;
395 }386 }
387 ncmds += self.segments.items.len;
396 }388 }
397}
398389
399fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: u32, sizeofcmds: u32) !void {390 try writer.writeStruct(self.symtab_cmd);
400 const target = macho_file.base.comp.root_mod.resolved_target.result;391 ncmds += 1;
392
393 assert(cwriter.bytes_written == needed_size);
401394
395 try self.file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
396
397 return .{ ncmds, buffer.len };
398}
399
400fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
402 var header: macho.mach_header_64 = .{};401 var header: macho.mach_header_64 = .{};
403 header.filetype = macho.MH_DSYM;402 header.filetype = macho.MH_DSYM;
404403
405 switch (target.cpu.arch) {404 switch (macho_file.getTarget().cpu.arch) {
406 .aarch64 => {405 .aarch64 => {
407 header.cputype = macho.CPU_TYPE_ARM64;406 header.cputype = macho.CPU_TYPE_ARM64;
408 header.cpusubtype = macho.CPU_SUBTYPE_ARM_ALL;407 header.cpusubtype = macho.CPU_SUBTYPE_ARM_ALL;
...@@ -414,8 +413,8 @@ fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: u32, sizeofcmds:...@@ -414,8 +413,8 @@ fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: u32, sizeofcmds:
414 else => return error.UnsupportedCpuArchitecture,413 else => return error.UnsupportedCpuArchitecture,
415 }414 }
416415
417 header.ncmds = ncmds;416 header.ncmds = @intCast(ncmds);
418 header.sizeofcmds = sizeofcmds;417 header.sizeofcmds = @intCast(sizeofcmds);
419418
420 log.debug("writing Mach-O header {}", .{header});419 log.debug("writing Mach-O header {}", .{header});
421420
...@@ -437,91 +436,56 @@ fn writeLinkeditSegmentData(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -437,91 +436,56 @@ fn writeLinkeditSegmentData(self: *DebugSymbols, macho_file: *MachO) !void {
437 const tracy = trace(@src());436 const tracy = trace(@src());
438 defer tracy.end();437 defer tracy.end();
439438
440 try self.writeSymtab(macho_file);439 const page_size = macho_file.getPageSize();
441 try self.writeStrtab();
442
443 const target = macho_file.base.comp.root_mod.resolved_target.result;
444 const page_size = MachO.getPageSize(target.cpu.arch);
445 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];440 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
441
442 var off = math.cast(u32, seg.fileoff) orelse return error.Overflow;
443 off = try self.writeSymtab(off, macho_file);
444 off = mem.alignForward(u32, off, @alignOf(u64));
445 off = try self.writeStrtab(off);
446 seg.filesize = off - seg.fileoff;
447
446 const aligned_size = mem.alignForward(u64, seg.filesize, page_size);448 const aligned_size = mem.alignForward(u64, seg.filesize, page_size);
447 seg.vmsize = aligned_size;449 seg.vmsize = aligned_size;
448}450}
449451
450fn writeSymtab(self: *DebugSymbols, macho_file: *MachO) !void {452pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 {
451 const tracy = trace(@src());453 const tracy = trace(@src());
452 defer tracy.end();454 defer tracy.end();
453
454 const gpa = self.allocator;455 const gpa = self.allocator;
456 const cmd = &self.symtab_cmd;
457 cmd.nsyms = macho_file.symtab_cmd.nsyms;
458 cmd.strsize = macho_file.symtab_cmd.strsize;
459 cmd.symoff = off;
455460
456 var locals = std.ArrayList(macho.nlist_64).init(gpa);461 try self.symtab.resize(gpa, cmd.nsyms);
457 defer locals.deinit();462 try self.strtab.ensureUnusedCapacity(gpa, cmd.strsize - 1);
458
459 for (macho_file.locals.items, 0..) |sym, sym_id| {
460 if (sym.n_strx == 0) continue; // no name, skip
461 const sym_loc = MachO.SymbolWithLoc{ .sym_index = @as(u32, @intCast(sym_id)) };
462 if (macho_file.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip
463 if (macho_file.getGlobal(macho_file.getSymbolName(sym_loc)) != null) continue; // global symbol is either an export or import, skip
464 var out_sym = sym;
465 out_sym.n_strx = try self.strtab.insert(gpa, macho_file.getSymbolName(sym_loc));
466 try locals.append(out_sym);
467 }
468463
469 var exports = std.ArrayList(macho.nlist_64).init(gpa);464 if (macho_file.getZigObject()) |zo| {
470 defer exports.deinit();465 zo.writeSymtab(macho_file, self);
471466 }
472 for (macho_file.globals.items) |global| {467 for (macho_file.objects.items) |index| {
473 const sym = macho_file.getSymbol(global);468 try macho_file.getFile(index).?.writeSymtab(macho_file, self);
474 if (sym.undf()) continue; // import, skip469 }
475 var out_sym = sym;470 for (macho_file.dylibs.items) |index| {
476 out_sym.n_strx = try self.strtab.insert(gpa, macho_file.getSymbolName(global));471 try macho_file.getFile(index).?.writeSymtab(macho_file, self);
477 try exports.append(out_sym);472 }
473 if (macho_file.getInternalObject()) |internal| {
474 internal.writeSymtab(macho_file, self);
478 }475 }
479476
480 const nlocals = locals.items.len;477 assert(self.strtab.items.len == cmd.strsize);
481 const nexports = exports.items.len;
482 const nsyms = nlocals + nexports;
483
484 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
485 const offset = mem.alignForward(u64, seg.fileoff, @alignOf(macho.nlist_64));
486 const needed_size = nsyms * @sizeOf(macho.nlist_64);
487 seg.filesize = offset + needed_size - seg.fileoff;
488
489 self.symtab_cmd.symoff = @as(u32, @intCast(offset));
490 self.symtab_cmd.nsyms = @as(u32, @intCast(nsyms));
491
492 const locals_off = @as(u32, @intCast(offset));
493 const locals_size = nlocals * @sizeOf(macho.nlist_64);
494 const exports_off = locals_off + locals_size;
495 const exports_size = nexports * @sizeOf(macho.nlist_64);
496478
497 log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off });479 try self.file.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff);
498 try self.file.pwriteAll(mem.sliceAsBytes(locals.items), locals_off);
499480
500 log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off });481 return off + cmd.nsyms * @sizeOf(macho.nlist_64);
501 try self.file.pwriteAll(mem.sliceAsBytes(exports.items), exports_off);
502}482}
503483
504fn writeStrtab(self: *DebugSymbols) !void {484pub fn writeStrtab(self: *DebugSymbols, off: u32) !u32 {
505 const tracy = trace(@src());485 const cmd = &self.symtab_cmd;
506 defer tracy.end();486 cmd.stroff = off;
507487 try self.file.pwriteAll(self.strtab.items, cmd.stroff);
508 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];488 return off + cmd.strsize;
509 const symtab_size = @as(u32, @intCast(self.symtab_cmd.nsyms * @sizeOf(macho.nlist_64)));
510 const offset = mem.alignForward(u64, self.symtab_cmd.symoff + symtab_size, @alignOf(u64));
511 const needed_size = mem.alignForward(u64, self.strtab.buffer.items.len, @alignOf(u64));
512
513 seg.filesize = offset + needed_size - seg.fileoff;
514 self.symtab_cmd.stroff = @as(u32, @intCast(offset));
515 self.symtab_cmd.strsize = @as(u32, @intCast(needed_size));
516
517 log.debug("writing string table from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
518
519 try self.file.pwriteAll(self.strtab.buffer.items, offset);
520
521 if (self.strtab.buffer.items.len < needed_size) {
522 // Ensure we are always padded to the actual length of the file.
523 try self.file.pwriteAll(&[_]u8{0}, offset + needed_size);
524 }
525}489}
526490
527pub fn getSectionIndexes(self: *DebugSymbols, segment_index: u8) struct { start: u8, end: u8 } {491pub fn getSectionIndexes(self: *DebugSymbols, segment_index: u8) struct { start: u8, end: u8 } {
...@@ -561,7 +525,7 @@ const assert = std.debug.assert;...@@ -561,7 +525,7 @@ const assert = std.debug.assert;
561const fs = std.fs;525const fs = std.fs;
562const link = @import("../../link.zig");526const link = @import("../../link.zig");
563const load_commands = @import("load_commands.zig");527const load_commands = @import("load_commands.zig");
564const log = std.log.scoped(.dsym);528const log = std.log.scoped(.link_dsym);
565const macho = std.macho;529const macho = std.macho;
566const makeStaticString = MachO.makeStaticString;530const makeStaticString = MachO.makeStaticString;
567const math = std.math;531const math = std.math;
src/link/MachO/Dylib.zig+5-5
...@@ -576,7 +576,7 @@ pub fn calcSymtabSize(self: *Dylib, macho_file: *MachO) !void {...@@ -576,7 +576,7 @@ pub fn calcSymtabSize(self: *Dylib, macho_file: *MachO) !void {
576 }576 }
577}577}
578578
579pub fn writeSymtab(self: Dylib, macho_file: *MachO) void {579pub fn writeSymtab(self: Dylib, macho_file: *MachO, ctx: anytype) void {
580 const tracy = trace(@src());580 const tracy = trace(@src());
581 defer tracy.end();581 defer tracy.end();
582582
...@@ -585,10 +585,10 @@ pub fn writeSymtab(self: Dylib, macho_file: *MachO) void {...@@ -585,10 +585,10 @@ pub fn writeSymtab(self: Dylib, macho_file: *MachO) void {
585 const file = global.getFile(macho_file) orelse continue;585 const file = global.getFile(macho_file) orelse continue;
586 if (file.getIndex() != self.index) continue;586 if (file.getIndex() != self.index) continue;
587 const idx = global.getOutputSymtabIndex(macho_file) orelse continue;587 const idx = global.getOutputSymtabIndex(macho_file) orelse continue;
588 const n_strx = @as(u32, @intCast(macho_file.strtab.items.len));588 const n_strx = @as(u32, @intCast(ctx.strtab.items.len));
589 macho_file.strtab.appendSliceAssumeCapacity(global.getName(macho_file));589 ctx.strtab.appendSliceAssumeCapacity(global.getName(macho_file));
590 macho_file.strtab.appendAssumeCapacity(0);590 ctx.strtab.appendAssumeCapacity(0);
591 const out_sym = &macho_file.symtab.items[idx];591 const out_sym = &ctx.symtab.items[idx];
592 out_sym.n_strx = n_strx;592 out_sym.n_strx = n_strx;
593 global.setOutputSym(macho_file, out_sym);593 global.setOutputSym(macho_file, out_sym);
594 }594 }
src/link/MachO/InternalObject.zig+5-5
...@@ -139,15 +139,15 @@ pub fn calcSymtabSize(self: *InternalObject, macho_file: *MachO) !void {...@@ -139,15 +139,15 @@ pub fn calcSymtabSize(self: *InternalObject, macho_file: *MachO) !void {
139 }139 }
140}140}
141141
142pub fn writeSymtab(self: InternalObject, macho_file: *MachO) void {142pub fn writeSymtab(self: InternalObject, macho_file: *MachO, ctx: anytype) void {
143 for (self.symbols.items) |sym_index| {143 for (self.symbols.items) |sym_index| {
144 const sym = macho_file.getSymbol(sym_index);144 const sym = macho_file.getSymbol(sym_index);
145 if (sym.getFile(macho_file)) |file| if (file.getIndex() != self.index) continue;145 if (sym.getFile(macho_file)) |file| if (file.getIndex() != self.index) continue;
146 const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;146 const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
147 const n_strx = @as(u32, @intCast(macho_file.strtab.items.len));147 const n_strx = @as(u32, @intCast(ctx.strtab.items.len));
148 macho_file.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));148 ctx.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
149 macho_file.strtab.appendAssumeCapacity(0);149 ctx.strtab.appendAssumeCapacity(0);
150 const out_sym = &macho_file.symtab.items[idx];150 const out_sym = &ctx.symtab.items[idx];
151 out_sym.n_strx = n_strx;151 out_sym.n_strx = n_strx;
152 sym.setOutputSym(macho_file, out_sym);152 sym.setOutputSym(macho_file, out_sym);
153 }153 }
src/link/MachO/Object.zig+51-51
...@@ -1320,7 +1320,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {...@@ -1320,7 +1320,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {
1320 }1320 }
1321}1321}
13221322
1323pub fn writeSymtab(self: Object, macho_file: *MachO) error{Overflow}!void {1323pub fn writeSymtab(self: Object, macho_file: *MachO, ctx: anytype) error{Overflow}!void {
1324 const tracy = trace(@src());1324 const tracy = trace(@src());
1325 defer tracy.end();1325 defer tracy.end();
13261326
...@@ -1329,19 +1329,19 @@ pub fn writeSymtab(self: Object, macho_file: *MachO) error{Overflow}!void {...@@ -1329,19 +1329,19 @@ pub fn writeSymtab(self: Object, macho_file: *MachO) error{Overflow}!void {
1329 const file = sym.getFile(macho_file) orelse continue;1329 const file = sym.getFile(macho_file) orelse continue;
1330 if (file.getIndex() != self.index) continue;1330 if (file.getIndex() != self.index) continue;
1331 const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;1331 const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
1332 const n_strx = @as(u32, @intCast(macho_file.strtab.items.len));1332 const n_strx = @as(u32, @intCast(ctx.strtab.items.len));
1333 macho_file.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));1333 ctx.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
1334 macho_file.strtab.appendAssumeCapacity(0);1334 ctx.strtab.appendAssumeCapacity(0);
1335 const out_sym = &macho_file.symtab.items[idx];1335 const out_sym = &ctx.symtab.items[idx];
1336 out_sym.n_strx = n_strx;1336 out_sym.n_strx = n_strx;
1337 sym.setOutputSym(macho_file, out_sym);1337 sym.setOutputSym(macho_file, out_sym);
1338 }1338 }
13391339
1340 if (macho_file.base.comp.config.debug_format != .strip and self.hasDebugInfo())1340 if (macho_file.base.comp.config.debug_format != .strip and self.hasDebugInfo())
1341 try self.writeStabs(macho_file);1341 try self.writeStabs(macho_file, ctx);
1342}1342}
13431343
1344pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void {1344pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{Overflow}!void {
1345 const writeFuncStab = struct {1345 const writeFuncStab = struct {
1346 inline fn writeFuncStab(1346 inline fn writeFuncStab(
1347 n_strx: u32,1347 n_strx: u32,
...@@ -1349,30 +1349,30 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1349,30 +1349,30 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1349 n_value: u64,1349 n_value: u64,
1350 size: u64,1350 size: u64,
1351 index: u32,1351 index: u32,
1352 ctx: *MachO,1352 context: anytype,
1353 ) void {1353 ) void {
1354 ctx.symtab.items[index] = .{1354 context.symtab.items[index] = .{
1355 .n_strx = 0,1355 .n_strx = 0,
1356 .n_type = macho.N_BNSYM,1356 .n_type = macho.N_BNSYM,
1357 .n_sect = n_sect,1357 .n_sect = n_sect,
1358 .n_desc = 0,1358 .n_desc = 0,
1359 .n_value = n_value,1359 .n_value = n_value,
1360 };1360 };
1361 ctx.symtab.items[index + 1] = .{1361 context.symtab.items[index + 1] = .{
1362 .n_strx = n_strx,1362 .n_strx = n_strx,
1363 .n_type = macho.N_FUN,1363 .n_type = macho.N_FUN,
1364 .n_sect = n_sect,1364 .n_sect = n_sect,
1365 .n_desc = 0,1365 .n_desc = 0,
1366 .n_value = n_value,1366 .n_value = n_value,
1367 };1367 };
1368 ctx.symtab.items[index + 2] = .{1368 context.symtab.items[index + 2] = .{
1369 .n_strx = 0,1369 .n_strx = 0,
1370 .n_type = macho.N_FUN,1370 .n_type = macho.N_FUN,
1371 .n_sect = 0,1371 .n_sect = 0,
1372 .n_desc = 0,1372 .n_desc = 0,
1373 .n_value = size,1373 .n_value = size,
1374 };1374 };
1375 ctx.symtab.items[index + 3] = .{1375 context.symtab.items[index + 3] = .{
1376 .n_strx = 0,1376 .n_strx = 0,
1377 .n_type = macho.N_ENSYM,1377 .n_type = macho.N_ENSYM,
1378 .n_sect = n_sect,1378 .n_sect = n_sect,
...@@ -1392,10 +1392,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1392,10 +1392,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
13921392
1393 // Open scope1393 // Open scope
1394 // N_SO comp_dir1394 // N_SO comp_dir
1395 var n_strx = @as(u32, @intCast(macho_file.strtab.items.len));1395 var n_strx = @as(u32, @intCast(ctx.strtab.items.len));
1396 macho_file.strtab.appendSliceAssumeCapacity(comp_dir);1396 ctx.strtab.appendSliceAssumeCapacity(comp_dir);
1397 macho_file.strtab.appendAssumeCapacity(0);1397 ctx.strtab.appendAssumeCapacity(0);
1398 macho_file.symtab.items[index] = .{1398 ctx.symtab.items[index] = .{
1399 .n_strx = n_strx,1399 .n_strx = n_strx,
1400 .n_type = macho.N_SO,1400 .n_type = macho.N_SO,
1401 .n_sect = 0,1401 .n_sect = 0,
...@@ -1404,10 +1404,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1404,10 +1404,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1404 };1404 };
1405 index += 1;1405 index += 1;
1406 // N_SO tu_name1406 // N_SO tu_name
1407 n_strx = @as(u32, @intCast(macho_file.strtab.items.len));1407 n_strx = @as(u32, @intCast(ctx.strtab.items.len));
1408 macho_file.strtab.appendSliceAssumeCapacity(tu_name);1408 ctx.strtab.appendSliceAssumeCapacity(tu_name);
1409 macho_file.strtab.appendAssumeCapacity(0);1409 ctx.strtab.appendAssumeCapacity(0);
1410 macho_file.symtab.items[index] = .{1410 ctx.symtab.items[index] = .{
1411 .n_strx = n_strx,1411 .n_strx = n_strx,
1412 .n_type = macho.N_SO,1412 .n_type = macho.N_SO,
1413 .n_sect = 0,1413 .n_sect = 0,
...@@ -1416,18 +1416,18 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1416,18 +1416,18 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1416 };1416 };
1417 index += 1;1417 index += 1;
1418 // N_OSO path1418 // N_OSO path
1419 n_strx = @as(u32, @intCast(macho_file.strtab.items.len));1419 n_strx = @as(u32, @intCast(ctx.strtab.items.len));
1420 if (self.archive) |ar| {1420 if (self.archive) |ar| {
1421 macho_file.strtab.appendSliceAssumeCapacity(ar.path);1421 ctx.strtab.appendSliceAssumeCapacity(ar.path);
1422 macho_file.strtab.appendAssumeCapacity('(');1422 ctx.strtab.appendAssumeCapacity('(');
1423 macho_file.strtab.appendSliceAssumeCapacity(self.path);1423 ctx.strtab.appendSliceAssumeCapacity(self.path);
1424 macho_file.strtab.appendAssumeCapacity(')');1424 ctx.strtab.appendAssumeCapacity(')');
1425 macho_file.strtab.appendAssumeCapacity(0);1425 ctx.strtab.appendAssumeCapacity(0);
1426 } else {1426 } else {
1427 macho_file.strtab.appendSliceAssumeCapacity(self.path);1427 ctx.strtab.appendSliceAssumeCapacity(self.path);
1428 macho_file.strtab.appendAssumeCapacity(0);1428 ctx.strtab.appendAssumeCapacity(0);
1429 }1429 }
1430 macho_file.symtab.items[index] = .{1430 ctx.symtab.items[index] = .{
1431 .n_strx = n_strx,1431 .n_strx = n_strx,
1432 .n_type = macho.N_OSO,1432 .n_type = macho.N_OSO,
1433 .n_sect = 0,1433 .n_sect = 0,
...@@ -1448,17 +1448,17 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1448,17 +1448,17 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1448 const sect = macho_file.sections.items(.header)[sym.out_n_sect];1448 const sect = macho_file.sections.items(.header)[sym.out_n_sect];
1449 const sym_n_strx = n_strx: {1449 const sym_n_strx = n_strx: {
1450 const symtab_index = sym.getOutputSymtabIndex(macho_file).?;1450 const symtab_index = sym.getOutputSymtabIndex(macho_file).?;
1451 const osym = macho_file.symtab.items[symtab_index];1451 const osym = ctx.symtab.items[symtab_index];
1452 break :n_strx osym.n_strx;1452 break :n_strx osym.n_strx;
1453 };1453 };
1454 const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.out_n_sect + 1) else 0;1454 const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.out_n_sect + 1) else 0;
1455 const sym_n_value = sym.getAddress(.{}, macho_file);1455 const sym_n_value = sym.getAddress(.{}, macho_file);
1456 const sym_size = sym.getSize(macho_file);1456 const sym_size = sym.getSize(macho_file);
1457 if (sect.isCode()) {1457 if (sect.isCode()) {
1458 writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, macho_file);1458 writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, ctx);
1459 index += 4;1459 index += 4;
1460 } else if (sym.visibility == .global) {1460 } else if (sym.visibility == .global) {
1461 macho_file.symtab.items[index] = .{1461 ctx.symtab.items[index] = .{
1462 .n_strx = sym_n_strx,1462 .n_strx = sym_n_strx,
1463 .n_type = macho.N_GSYM,1463 .n_type = macho.N_GSYM,
1464 .n_sect = sym_n_sect,1464 .n_sect = sym_n_sect,
...@@ -1467,7 +1467,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1467,7 +1467,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1467 };1467 };
1468 index += 1;1468 index += 1;
1469 } else {1469 } else {
1470 macho_file.symtab.items[index] = .{1470 ctx.symtab.items[index] = .{
1471 .n_strx = sym_n_strx,1471 .n_strx = sym_n_strx,
1472 .n_type = macho.N_STSYM,1472 .n_type = macho.N_STSYM,
1473 .n_sect = sym_n_sect,1473 .n_sect = sym_n_sect,
...@@ -1480,7 +1480,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1480,7 +1480,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
14801480
1481 // Close scope1481 // Close scope
1482 // N_SO1482 // N_SO
1483 macho_file.symtab.items[index] = .{1483 ctx.symtab.items[index] = .{
1484 .n_strx = 0,1484 .n_strx = 0,
1485 .n_type = macho.N_SO,1485 .n_type = macho.N_SO,
1486 .n_sect = 0,1486 .n_sect = 0,
...@@ -1493,10 +1493,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1493,10 +1493,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1493 for (self.stab_files.items) |sf| {1493 for (self.stab_files.items) |sf| {
1494 // Open scope1494 // Open scope
1495 // N_SO comp_dir1495 // N_SO comp_dir
1496 var n_strx = @as(u32, @intCast(macho_file.strtab.items.len));1496 var n_strx = @as(u32, @intCast(ctx.strtab.items.len));
1497 macho_file.strtab.appendSliceAssumeCapacity(sf.getCompDir(self));1497 ctx.strtab.appendSliceAssumeCapacity(sf.getCompDir(self));
1498 macho_file.strtab.appendAssumeCapacity(0);1498 ctx.strtab.appendAssumeCapacity(0);
1499 macho_file.symtab.items[index] = .{1499 ctx.symtab.items[index] = .{
1500 .n_strx = n_strx,1500 .n_strx = n_strx,
1501 .n_type = macho.N_SO,1501 .n_type = macho.N_SO,
1502 .n_sect = 0,1502 .n_sect = 0,
...@@ -1505,10 +1505,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1505,10 +1505,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1505 };1505 };
1506 index += 1;1506 index += 1;
1507 // N_SO tu_name1507 // N_SO tu_name
1508 n_strx = @as(u32, @intCast(macho_file.strtab.items.len));1508 n_strx = @as(u32, @intCast(ctx.strtab.items.len));
1509 macho_file.strtab.appendSliceAssumeCapacity(sf.getTuName(self));1509 ctx.strtab.appendSliceAssumeCapacity(sf.getTuName(self));
1510 macho_file.strtab.appendAssumeCapacity(0);1510 ctx.strtab.appendAssumeCapacity(0);
1511 macho_file.symtab.items[index] = .{1511 ctx.symtab.items[index] = .{
1512 .n_strx = n_strx,1512 .n_strx = n_strx,
1513 .n_type = macho.N_SO,1513 .n_type = macho.N_SO,
1514 .n_sect = 0,1514 .n_sect = 0,
...@@ -1517,10 +1517,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1517,10 +1517,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1517 };1517 };
1518 index += 1;1518 index += 1;
1519 // N_OSO path1519 // N_OSO path
1520 n_strx = @as(u32, @intCast(macho_file.strtab.items.len));1520 n_strx = @as(u32, @intCast(ctx.strtab.items.len));
1521 macho_file.strtab.appendSliceAssumeCapacity(sf.getOsoPath(self));1521 ctx.strtab.appendSliceAssumeCapacity(sf.getOsoPath(self));
1522 macho_file.strtab.appendAssumeCapacity(0);1522 ctx.strtab.appendAssumeCapacity(0);
1523 macho_file.symtab.items[index] = .{1523 ctx.symtab.items[index] = .{
1524 .n_strx = n_strx,1524 .n_strx = n_strx,
1525 .n_type = macho.N_OSO,1525 .n_type = macho.N_OSO,
1526 .n_sect = 0,1526 .n_sect = 0,
...@@ -1536,7 +1536,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1536,7 +1536,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1536 if (!sym.flags.output_symtab) continue;1536 if (!sym.flags.output_symtab) continue;
1537 const sym_n_strx = n_strx: {1537 const sym_n_strx = n_strx: {
1538 const symtab_index = sym.getOutputSymtabIndex(macho_file).?;1538 const symtab_index = sym.getOutputSymtabIndex(macho_file).?;
1539 const osym = macho_file.symtab.items[symtab_index];1539 const osym = ctx.symtab.items[symtab_index];
1540 break :n_strx osym.n_strx;1540 break :n_strx osym.n_strx;
1541 };1541 };
1542 const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.out_n_sect + 1) else 0;1542 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...@@ -1544,11 +1544,11 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1544 const sym_size = sym.getSize(macho_file);1544 const sym_size = sym.getSize(macho_file);
1545 switch (stab.tag) {1545 switch (stab.tag) {
1546 .func => {1546 .func => {
1547 writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, macho_file);1547 writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, ctx);
1548 index += 4;1548 index += 4;
1549 },1549 },
1550 .global => {1550 .global => {
1551 macho_file.symtab.items[index] = .{1551 ctx.symtab.items[index] = .{
1552 .n_strx = sym_n_strx,1552 .n_strx = sym_n_strx,
1553 .n_type = macho.N_GSYM,1553 .n_type = macho.N_GSYM,
1554 .n_sect = sym_n_sect,1554 .n_sect = sym_n_sect,
...@@ -1558,7 +1558,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1558,7 +1558,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1558 index += 1;1558 index += 1;
1559 },1559 },
1560 .static => {1560 .static => {
1561 macho_file.symtab.items[index] = .{1561 ctx.symtab.items[index] = .{
1562 .n_strx = sym_n_strx,1562 .n_strx = sym_n_strx,
1563 .n_type = macho.N_STSYM,1563 .n_type = macho.N_STSYM,
1564 .n_sect = sym_n_sect,1564 .n_sect = sym_n_sect,
...@@ -1572,7 +1572,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1572,7 +1572,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
15721572
1573 // Close scope1573 // Close scope
1574 // N_SO1574 // N_SO
1575 macho_file.symtab.items[index] = .{1575 ctx.symtab.items[index] = .{
1576 .n_strx = 0,1576 .n_strx = 0,
1577 .n_type = macho.N_SO,1577 .n_type = macho.N_SO,
1578 .n_sect = 0,1578 .n_sect = 0,
src/link/MachO/ZigObject.zig+31-29
...@@ -310,7 +310,7 @@ pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) !void {...@@ -310,7 +310,7 @@ pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) !void {
310 }310 }
311}311}
312312
313pub fn writeSymtab(self: ZigObject, macho_file: *MachO) void {313pub fn writeSymtab(self: ZigObject, macho_file: *MachO, ctx: anytype) void {
314 const tracy = trace(@src());314 const tracy = trace(@src());
315 defer tracy.end();315 defer tracy.end();
316316
...@@ -319,10 +319,10 @@ pub fn writeSymtab(self: ZigObject, macho_file: *MachO) void {...@@ -319,10 +319,10 @@ pub fn writeSymtab(self: ZigObject, macho_file: *MachO) void {
319 const file = sym.getFile(macho_file) orelse continue;319 const file = sym.getFile(macho_file) orelse continue;
320 if (file.getIndex() != self.index) continue;320 if (file.getIndex() != self.index) continue;
321 const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;321 const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
322 const n_strx = @as(u32, @intCast(macho_file.strtab.items.len));322 const n_strx = @as(u32, @intCast(ctx.strtab.items.len));
323 macho_file.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));323 ctx.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
324 macho_file.strtab.appendAssumeCapacity(0);324 ctx.strtab.appendAssumeCapacity(0);
325 const out_sym = &macho_file.symtab.items[idx];325 const out_sym = &ctx.symtab.items[idx];
326 out_sym.n_strx = n_strx;326 out_sym.n_strx = n_strx;
327 sym.setOutputSym(macho_file, out_sym);327 sym.setOutputSym(macho_file, out_sym);
328 }328 }
...@@ -531,7 +531,7 @@ pub fn updateFunc(...@@ -531,7 +531,7 @@ pub fn updateFunc(
531 var code_buffer = std.ArrayList(u8).init(gpa);531 var code_buffer = std.ArrayList(u8).init(gpa);
532 defer code_buffer.deinit();532 defer code_buffer.deinit();
533533
534 var decl_state: ?Dwarf.DeclState = null; // TODO: Dwarf534 var decl_state: ?Dwarf.DeclState = if (macho_file.getDebugSymbols()) |d_sym| try d_sym.dwarf.initDeclState(mod, decl_index) else null;
535 defer if (decl_state) |*ds| ds.deinit();535 defer if (decl_state) |*ds| ds.deinit();
536536
537 const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none;537 const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none;
...@@ -557,16 +557,16 @@ pub fn updateFunc(...@@ -557,16 +557,16 @@ pub fn updateFunc(
557 const sect_index = try self.getDeclOutputSection(macho_file, decl, code);557 const sect_index = try self.getDeclOutputSection(macho_file, decl, code);
558 try self.updateDeclCode(macho_file, decl_index, sym_index, sect_index, code);558 try self.updateDeclCode(macho_file, decl_index, sym_index, sect_index, code);
559559
560 // if (decl_state) |*ds| {560 if (decl_state) |*ds| {
561 // const sym = elf_file.symbol(sym_index);561 const sym = macho_file.getSymbol(sym_index);
562 // try self.dwarf.?.commitDeclState(562 try macho_file.getDebugSymbols().?.dwarf.commitDeclState(
563 // mod,563 mod,
564 // decl_index,564 decl_index,
565 // sym.value,565 sym.getAddress(.{}, macho_file),
566 // sym.atom(elf_file).?.size,566 sym.getAtom(macho_file).?.size,
567 // ds,567 ds,
568 // );568 );
569 // }569 }
570570
571 // Since we updated the vaddr and the size, each corresponding export571 // Since we updated the vaddr and the size, each corresponding export
572 // symbol also needs to be updated.572 // symbol also needs to be updated.
...@@ -606,7 +606,7 @@ pub fn updateDecl(...@@ -606,7 +606,7 @@ pub fn updateDecl(
606 var code_buffer = std.ArrayList(u8).init(gpa);606 var code_buffer = std.ArrayList(u8).init(gpa);
607 defer code_buffer.deinit();607 defer code_buffer.deinit();
608608
609 var decl_state: ?Dwarf.DeclState = null; // TODO: Dwarf609 var decl_state: ?Dwarf.DeclState = if (macho_file.getDebugSymbols()) |d_sym| try d_sym.dwarf.initDeclState(mod, decl_index) else null;
610 defer if (decl_state) |*ds| ds.deinit();610 defer if (decl_state) |*ds| ds.deinit();
611611
612 const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;612 const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
...@@ -638,15 +638,16 @@ pub fn updateDecl(...@@ -638,15 +638,16 @@ pub fn updateDecl(
638 try self.updateDeclCode(macho_file, decl_index, sym_index, sect_index, code);638 try self.updateDeclCode(macho_file, decl_index, sym_index, sect_index, code);
639 }639 }
640640
641 // if (decl_state) |*ds| {641 if (decl_state) |*ds| {
642 // try self.d_sym.?.dwarf.commitDeclState(642 const sym = macho_file.getSymbol(sym_index);
643 // mod,643 try macho_file.getDebugSymbols().?.dwarf.commitDeclState(
644 // decl_index,644 mod,
645 // addr,645 decl_index,
646 // self.getAtom(atom_index).size,646 sym.getAddress(.{}, macho_file),
647 // ds,647 sym.getAtom(macho_file).?.size,
648 // );648 ds,
649 // }649 );
650 }
650651
651 // Since we updated the vaddr and the size, each corresponding export symbol also652 // Since we updated the vaddr and the size, each corresponding export symbol also
652 // needs to be updated.653 // needs to be updated.
...@@ -1220,13 +1221,14 @@ fn updateLazySymbol(...@@ -1220,13 +1221,14 @@ fn updateLazySymbol(
1220/// Must be called only after a successful call to `updateDecl`.1221/// Must be called only after a successful call to `updateDecl`.
1221pub fn updateDeclLineNumber(1222pub fn updateDeclLineNumber(
1222 self: *ZigObject,1223 self: *ZigObject,
1224 macho_file: *MachO,
1223 mod: *Module,1225 mod: *Module,
1224 decl_index: InternPool.DeclIndex,1226 decl_index: InternPool.DeclIndex,
1225) !void {1227) !void {
1226 _ = self;1228 _ = self;
1227 _ = mod;1229 if (macho_file.getDebugSymbols()) |d_sym| {
1228 _ = decl_index;1230 try d_sym.dwarf.updateDeclLineNumber(mod, decl_index);
1229 // TODO: Dwarf1231 }
1230}1232}
12311233
1232pub fn deleteDeclExport(1234pub fn deleteDeclExport(
src/link/MachO/file.zig+2-2
...@@ -90,9 +90,9 @@ pub const File = union(enum) {...@@ -90,9 +90,9 @@ pub const File = union(enum) {
90 };90 };
91 }91 }
9292
93 pub fn writeSymtab(file: File, macho_file: *MachO) !void {93 pub fn writeSymtab(file: File, macho_file: *MachO, ctx: anytype) !void {
94 return switch (file) {94 return switch (file) {
95 inline else => |x| x.writeSymtab(macho_file),95 inline else => |x| x.writeSymtab(macho_file, ctx),
96 };96 };
97 }97 }
9898
src/link/MachO/load_commands.zig+22
...@@ -5,6 +5,7 @@ const macho = std.macho;...@@ -5,6 +5,7 @@ const macho = std.macho;
5const mem = std.mem;5const mem = std.mem;
66
7const Allocator = mem.Allocator;7const Allocator = mem.Allocator;
8const DebugSymbols = @import("DebugSymbols.zig");
8const Dylib = @import("Dylib.zig");9const Dylib = @import("Dylib.zig");
9const MachO = @import("../MachO.zig");10const MachO = @import("../MachO.zig");
1011
...@@ -97,6 +98,27 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) u32 {...@@ -97,6 +98,27 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) u32 {
97 return @as(u32, @intCast(sizeofcmds));98 return @as(u32, @intCast(sizeofcmds));
98}99}
99100
101pub fn calcLoadCommandsSizeDsym(macho_file: *MachO, dsym: *const DebugSymbols) u32 {
102 var sizeofcmds: u64 = 0;
103
104 // LC_SEGMENT_64
105 sizeofcmds += @sizeOf(macho.segment_command_64) * (macho_file.segments.items.len - 1);
106 for (macho_file.segments.items) |seg| {
107 sizeofcmds += seg.nsects * @sizeOf(macho.section_64);
108 }
109 sizeofcmds += @sizeOf(macho.segment_command_64) * dsym.segments.items.len;
110 for (dsym.segments.items) |seg| {
111 sizeofcmds += seg.nsects * @sizeOf(macho.section_64);
112 }
113
114 // LC_SYMTAB
115 sizeofcmds += @sizeOf(macho.symtab_command);
116 // LC_UUID
117 sizeofcmds += @sizeOf(macho.uuid_command);
118
119 return @as(u32, @intCast(sizeofcmds));
120}
121
100pub fn calcLoadCommandsSizeObject(macho_file: *MachO) u32 {122pub fn calcLoadCommandsSizeObject(macho_file: *MachO) u32 {
101 var sizeofcmds: u64 = 0;123 var sizeofcmds: u64 = 0;
102124