From bd99a87dc224b7d84e764fc2a8a8f4e3068078b3 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sun, 27 Dec 2020 09:30:03 +0100 Subject: [PATCH] macho: create dSym bundle next to final artefact macOS requires the debug symbols to either be part of the intermediate object file `whatever.o` or a companion `whatever.dSym` bundle. The former case seems ill-suited for our needs since it subscribes to the old-fashioned compilation strategy using intermediate compilation units; the latter is what we need however on macOS the debug symbols unlike in Elf are not part of the final artefact; rather they sit next to it in its own Mach-O file. --- src/link/MachO.zig | 22 ++++++++++++++++++ src/link/MachO/DebugSymbols.zig | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 src/link/MachO/DebugSymbols.zig diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 5f35b26f22..5d5a5d76b2 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -3,6 +3,7 @@ const MachO = @This(); const std = @import("std"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; +const fmt = std.fmt; const fs = std.fs; const log = std.log.scoped(.link); const macho = std.macho; @@ -21,6 +22,7 @@ const File = link.File; const Cache = @import("../Cache.zig"); const target_util = @import("../target.zig"); +const DebugSymbols = @import("MachO/DebugSymbols.zig"); const Trie = @import("MachO/Trie.zig"); const CodeSignature = @import("MachO/CodeSignature.zig"); @@ -31,6 +33,9 @@ pub const base_tag: File.Tag = File.Tag.macho; base: File, +/// Debug symbols bundle (or dSym). +d_sym: ?DebugSymbols = null, + /// Page size is dependent on the target cpu architecture. /// For x86_64 that's 4KB, whereas for aarch64, that's 16KB. page_size: u16, @@ -264,6 +269,20 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio self.base.file = file; + // Create dSym bundle. + const d_sym_path = try fmt.allocPrint(allocator, "{}.dSym/Contents/Resources/DWARF/", .{sub_path}); + defer allocator.free(d_sym_path); + var d_sym_bundle = try options.emit.?.directory.handle.makeOpenPath(d_sym_path, .{}); + defer d_sym_bundle.close(); + const d_sym_file = try d_sym_bundle.createFile(sub_path, .{ + .truncate = false, + .read = true, + }); + self.d_sym = .{ + .base = self, + .file = d_sym_file, + }; + // Index 0 is always a null symbol. try self.local_symbols.append(allocator, .{ .n_strx = 0, @@ -943,6 +962,9 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 { } pub fn deinit(self: *MachO) void { + if (self.d_sym) |*ds| { + ds.deinit(self.base.allocator); + } self.binding_info_table.deinit(self.base.allocator); self.lazy_binding_info_table.deinit(self.base.allocator); self.pie_fixups.deinit(self.base.allocator); diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig new file mode 100644 index 0000000000..1e30bdf564 --- /dev/null +++ b/src/link/MachO/DebugSymbols.zig @@ -0,0 +1,40 @@ +const DebugSymbols = @This(); + +const std = @import("std"); +const fs = std.fs; +const macho = std.macho; +const mem = std.mem; +const DW = std.dwarf; +const leb = std.leb; +const Allocator = mem.Allocator; + +const MachO = @import("../MachO.zig"); + +usingnamespace @import("commands.zig"); + +base: *MachO, +file: fs.File, + +/// Mach header +header: ?macho.mach_header_64 = null, + +/// Table of all load commands +load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, +/// __PAGEZERO segment +pagezero_segment_cmd_index: ?u16 = null, +/// __TEXT segment +text_segment_cmd_index: ?u16 = null, +/// __DWARF segment +dwarf_segment_cmd_index: ?u16 = null, +/// __DATA segment +data_segment_cmd_index: ?u16 = null, +/// __LINKEDIT segment +linkedit_segment_cmd_index: ?u16 = null, +/// Symbol table +symtab_cmd_index: ?u16 = null, +/// UUID load command +uuid_cmd_index: ?u16 = null, + +pub fn deinit(self: *DebugSymbols, allocator: *Allocator) void { + self.file.close(); +}