From cf9434191004e57e1cd3a75dcd91d5ad7e378c63 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sun, 27 Dec 2020 09:47:56 +0100 Subject: [PATCH] macho: write Mach-O dSym header --- src/link/MachO.zig | 6 +++++ src/link/MachO/DebugSymbols.zig | 45 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 5d5a5d76b2..c8449fbe1a 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -299,6 +299,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio } try self.populateMissingMetadata(); + try self.d_sym.?.populateMissingMetadata(allocator); return self; } @@ -352,6 +353,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { try self.writeStringTable(); try self.updateLinkeditSegmentSizes(); + if (self.d_sym) |*ds| { + // Flush debug symbols bundle. + try ds.flush(); + } + if (target.cpu.arch == .aarch64) { // Preallocate space for the code signature. // We need to do this at this stage so that we have the load commands with proper values diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 1e30bdf564..b485e391af 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -1,7 +1,9 @@ const DebugSymbols = @This(); const std = @import("std"); +const assert = std.debug.assert; const fs = std.fs; +const log = std.log.scoped(.link); const macho = std.macho; const mem = std.mem; const DW = std.dwarf; @@ -35,6 +37,49 @@ symtab_cmd_index: ?u16 = null, /// UUID load command uuid_cmd_index: ?u16 = null, +header_dirty: bool = false, +load_commands_dirty: bool = false, + +/// You must call this function *after* `MachO.populateMissingMetadata()` +/// has been called to get a viable debug symbols output. +pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void { + if (self.header == null) { + const base_header = self.base.header.?; + var header: macho.mach_header_64 = undefined; + header.magic = macho.MH_MAGIC_64; + header.cputype = base_header.cputype; + header.cpusubtype = base_header.cpusubtype; + header.filetype = macho.MH_DSYM; + // These will get populated at the end of flushing the results to file. + header.ncmds = 0; + header.sizeofcmds = 0; + header.flags = 0; + header.reserved = 0; + self.header = header; + self.header_dirty = true; + } +} + +pub fn flush(self: *DebugSymbols) !void { + try self.writeHeader(); + assert(!self.header_dirty); + assert(!self.load_commands_dirty); +} + pub fn deinit(self: *DebugSymbols, allocator: *Allocator) void { self.file.close(); } + +fn writeHeader(self: *DebugSymbols) !void { + if (!self.header_dirty) return; + + self.header.?.ncmds = @intCast(u32, self.load_commands.items.len); + var sizeofcmds: u32 = 0; + for (self.load_commands.items) |cmd| { + sizeofcmds += cmd.cmdsize(); + } + self.header.?.sizeofcmds = sizeofcmds; + log.debug("writing Mach-O dSym header {}", .{self.header.?}); + try self.file.pwriteAll(mem.asBytes(&self.header.?), 0); + self.header_dirty = false; +}