authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-27 09:30:03+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-31 10:19:04+01:00
logbd99a87dc224b7d84e764fc2a8a8f4e3068078b3
tree2500fcf9f2e04b1ab192814bfed4b7884a0b42a6
parent0ff56e8bb14273fa8abe4503855e9f53d699c8cd

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.

2 files changed, 62 insertions(+), 0 deletions(-)

src/link/MachO.zig+22
......@@ -3,6 +3,7 @@ const MachO = @This();
33const std = @import("std");
44const Allocator = std.mem.Allocator;
55const assert = std.debug.assert;
6const fmt = std.fmt;
67const fs = std.fs;
78const log = std.log.scoped(.link);
89const macho = std.macho;
......@@ -21,6 +22,7 @@ const File = link.File;
2122const Cache = @import("../Cache.zig");
2223const target_util = @import("../target.zig");
2324
25const DebugSymbols = @import("MachO/DebugSymbols.zig");
2426const Trie = @import("MachO/Trie.zig");
2527const CodeSignature = @import("MachO/CodeSignature.zig");
2628
......@@ -31,6 +33,9 @@ pub const base_tag: File.Tag = File.Tag.macho;
3133
3234base: File,
3335
36/// Debug symbols bundle (or dSym).
37d_sym: ?DebugSymbols = null,
38
3439/// Page size is dependent on the target cpu architecture.
3540/// For x86_64 that's 4KB, whereas for aarch64, that's 16KB.
3641page_size: u16,
......@@ -264,6 +269,20 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
264269
265270 self.base.file = file;
266271
272 // Create dSym bundle.
273 const d_sym_path = try fmt.allocPrint(allocator, "{}.dSym/Contents/Resources/DWARF/", .{sub_path});
274 defer allocator.free(d_sym_path);
275 var d_sym_bundle = try options.emit.?.directory.handle.makeOpenPath(d_sym_path, .{});
276 defer d_sym_bundle.close();
277 const d_sym_file = try d_sym_bundle.createFile(sub_path, .{
278 .truncate = false,
279 .read = true,
280 });
281 self.d_sym = .{
282 .base = self,
283 .file = d_sym_file,
284 };
285
267286 // Index 0 is always a null symbol.
268287 try self.local_symbols.append(allocator, .{
269288 .n_strx = 0,
......@@ -943,6 +962,9 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 {
943962}
944963
945964pub fn deinit(self: *MachO) void {
965 if (self.d_sym) |*ds| {
966 ds.deinit(self.base.allocator);
967 }
946968 self.binding_info_table.deinit(self.base.allocator);
947969 self.lazy_binding_info_table.deinit(self.base.allocator);
948970 self.pie_fixups.deinit(self.base.allocator);
src/link/MachO/DebugSymbols.zig created+40
......@@ -0,0 +1,40 @@
1const DebugSymbols = @This();
2
3const std = @import("std");
4const fs = std.fs;
5const macho = std.macho;
6const mem = std.mem;
7const DW = std.dwarf;
8const leb = std.leb;
9const Allocator = mem.Allocator;
10
11const MachO = @import("../MachO.zig");
12
13usingnamespace @import("commands.zig");
14
15base: *MachO,
16file: fs.File,
17
18/// Mach header
19header: ?macho.mach_header_64 = null,
20
21/// Table of all load commands
22load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
23/// __PAGEZERO segment
24pagezero_segment_cmd_index: ?u16 = null,
25/// __TEXT segment
26text_segment_cmd_index: ?u16 = null,
27/// __DWARF segment
28dwarf_segment_cmd_index: ?u16 = null,
29/// __DATA segment
30data_segment_cmd_index: ?u16 = null,
31/// __LINKEDIT segment
32linkedit_segment_cmd_index: ?u16 = null,
33/// Symbol table
34symtab_cmd_index: ?u16 = null,
35/// UUID load command
36uuid_cmd_index: ?u16 = null,
37
38pub fn deinit(self: *DebugSymbols, allocator: *Allocator) void {
39 self.file.close();
40}