authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-12 18:41:16+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-14 19:24:23+01:00
log27cfbf949a25375a6ae7671a00ed3f7bae67d3f9
tree27fcf1fbe7d3e5732f044f0e34dd31edd6f6e65a
parent04f3d9301798e41ac8272822328914073e01a6ab

macho: re-enable creating dSYM bundle

* update number of type abbrevs to match Elf linker * update `DebugSymbols` to write symbol and string tables at the end to match the `MachO` linker * TODO: update segment vm addresses when growing segments in the binary * TODO: store DWARF relocations in linker's interned arena

2 files changed, 368 insertions(+), 233 deletions(-)

src/link/MachO.zig+55-59
...@@ -354,32 +354,31 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {...@@ -354,32 +354,31 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
354 return self;354 return self;
355 }355 }
356356
357 // TODO Migrate DebugSymbols to the merged linker codepaths357 if (!options.strip and options.module != null) {
358 // if (!options.strip and options.module != null) {358 // Create dSYM bundle.
359 // // Create dSYM bundle.359 const dir = options.module.?.zig_cache_artifact_directory;
360 // const dir = options.module.?.zig_cache_artifact_directory;360 log.debug("creating {s}.dSYM bundle in {s}", .{ emit.sub_path, dir.path });
361 // log.debug("creating {s}.dSYM bundle in {s}", .{ sub_path, dir.path });361
362362 const d_sym_path = try fmt.allocPrint(
363 // const d_sym_path = try fmt.allocPrint(363 allocator,
364 // allocator,364 "{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF",
365 // "{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF",365 .{emit.sub_path},
366 // .{sub_path},366 );
367 // );367 defer allocator.free(d_sym_path);
368 // defer allocator.free(d_sym_path);368
369369 var d_sym_bundle = try dir.handle.makeOpenPath(d_sym_path, .{});
370 // var d_sym_bundle = try dir.handle.makeOpenPath(d_sym_path, .{});370 defer d_sym_bundle.close();
371 // defer d_sym_bundle.close();371
372372 const d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{
373 // const d_sym_file = try d_sym_bundle.createFile(sub_path, .{373 .truncate = false,
374 // .truncate = false,374 .read = true,
375 // .read = true,375 });
376 // });376
377377 self.d_sym = .{
378 // self.d_sym = .{378 .base = self,
379 // .base = self,379 .file = d_sym_file,
380 // .file = d_sym_file,380 };
381 // };381 }
382 // }
383382
384 // Index 0 is always a null symbol.383 // Index 0 is always a null symbol.
385 try self.locals.append(allocator, .{384 try self.locals.append(allocator, .{
...@@ -393,8 +392,8 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {...@@ -393,8 +392,8 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
393392
394 try self.populateMissingMetadata();393 try self.populateMissingMetadata();
395394
396 if (self.d_sym) |*ds| {395 if (self.d_sym) |*d_sym| {
397 try ds.populateMissingMetadata(allocator);396 try d_sym.populateMissingMetadata(allocator);
398 }397 }
399398
400 return self;399 return self;
...@@ -1048,9 +1047,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -1048,9 +1047,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
1048 try self.updateSectionOrdinals();1047 try self.updateSectionOrdinals();
1049 try self.writeLinkeditSegment();1048 try self.writeLinkeditSegment();
10501049
1051 if (self.d_sym) |*ds| {1050 if (self.d_sym) |*d_sym| {
1052 // Flush debug symbols bundle.1051 // Flush debug symbols bundle.
1053 try ds.flushModule(self.base.allocator, self.base.options);1052 try d_sym.flushModule(self.base.allocator, self.base.options);
1054 }1053 }
10551054
1056 if (self.requires_adhoc_codesig) {1055 if (self.requires_adhoc_codesig) {
...@@ -3374,8 +3373,8 @@ pub fn deinit(self: *MachO) void {...@@ -3374,8 +3373,8 @@ pub fn deinit(self: *MachO) void {
3374 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);3373 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
3375 }3374 }
33763375
3377 if (self.d_sym) |*ds| {3376 if (self.d_sym) |*d_sym| {
3378 ds.deinit(self.base.allocator);3377 d_sym.deinit(self.base.allocator);
3379 }3378 }
33803379
3381 self.section_ordinals.deinit(self.base.allocator);3380 self.section_ordinals.deinit(self.base.allocator);
...@@ -3497,13 +3496,13 @@ fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection, owns_atom: bool)...@@ -3497,13 +3496,13 @@ fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection, owns_atom: bool)
3497 }3496 }
3498 }3497 }
34993498
3500 if (self.d_sym) |*ds| {3499 if (self.d_sym) |*d_sym| {
3501 if (ds.dbg_info_decl_first == atom) {3500 if (d_sym.dbg_info_decl_first == atom) {
3502 ds.dbg_info_decl_first = atom.dbg_info_next;3501 d_sym.dbg_info_decl_first = atom.dbg_info_next;
3503 }3502 }
3504 if (ds.dbg_info_decl_last == atom) {3503 if (d_sym.dbg_info_decl_last == atom) {
3505 // TODO shrink the .debug_info section size here3504 // TODO shrink the .debug_info section size here
3506 ds.dbg_info_decl_last = atom.dbg_info_prev;3505 d_sym.dbg_info_decl_last = atom.dbg_info_prev;
3507 }3506 }
3508 }3507 }
35093508
...@@ -3675,6 +3674,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -3675,6 +3674,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
36753674
3676 const decl = func.owner_decl;3675 const decl = func.owner_decl;
3677 self.freeUnnamedConsts(decl);3676 self.freeUnnamedConsts(decl);
3677
3678 // TODO clearing the code and relocs buffer should probably be orchestrated3678 // TODO clearing the code and relocs buffer should probably be orchestrated
3679 // in a different, smarter, more automatic way somewhere else, in a more centralised3679 // in a different, smarter, more automatic way somewhere else, in a more centralised
3680 // way than this.3680 // way than this.
...@@ -3686,8 +3686,8 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -3686,8 +3686,8 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
3686 defer code_buffer.deinit();3686 defer code_buffer.deinit();
36873687
3688 var debug_buffers_buf: DebugSymbols.DeclDebugBuffers = undefined;3688 var debug_buffers_buf: DebugSymbols.DeclDebugBuffers = undefined;
3689 const debug_buffers = if (self.d_sym) |*ds| blk: {3689 const debug_buffers = if (self.d_sym) |*d_sym| blk: {
3690 debug_buffers_buf = try ds.initDeclDebugBuffers(self.base.allocator, module, decl);3690 debug_buffers_buf = try d_sym.initDeclDebugBuffers(self.base.allocator, module, decl);
3691 break :blk &debug_buffers_buf;3691 break :blk &debug_buffers_buf;
3692 } else null;3692 } else null;
3693 defer {3693 defer {
...@@ -3725,13 +3725,9 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -3725,13 +3725,9 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
3725 _ = try self.placeDecl(decl, decl.link.macho.code.items.len);3725 _ = try self.placeDecl(decl, decl.link.macho.code.items.len);
37263726
3727 if (debug_buffers) |db| {3727 if (debug_buffers) |db| {
3728 try self.d_sym.?.commitDeclDebugInfo(3728 if (self.d_sym) |*d_sym| {
3729 self.base.allocator,3729 try d_sym.commitDeclDebugInfo(self.base.allocator, module, decl, db);
3730 module,3730 }
3731 decl,
3732 db,
3733 self.base.options.target,
3734 );
3735 }3731 }
37363732
3737 // Since we updated the vaddr and the size, each corresponding export symbol also3733 // Since we updated the vaddr and the size, each corresponding export symbol also
...@@ -3827,8 +3823,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -3827,8 +3823,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
3827 defer code_buffer.deinit();3823 defer code_buffer.deinit();
38283824
3829 var debug_buffers_buf: DebugSymbols.DeclDebugBuffers = undefined;3825 var debug_buffers_buf: DebugSymbols.DeclDebugBuffers = undefined;
3830 const debug_buffers = if (self.d_sym) |*ds| blk: {3826 const debug_buffers = if (self.d_sym) |*d_sym| blk: {
3831 debug_buffers_buf = try ds.initDeclDebugBuffers(self.base.allocator, module, decl);3827 debug_buffers_buf = try d_sym.initDeclDebugBuffers(self.base.allocator, module, decl);
3832 break :blk &debug_buffers_buf;3828 break :blk &debug_buffers_buf;
3833 } else null;3829 } else null;
3834 defer {3830 defer {
...@@ -4125,8 +4121,8 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -4125,8 +4121,8 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
4125}4121}
41264122
4127pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {4123pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {
4128 if (self.d_sym) |*ds| {4124 if (self.d_sym) |*d_sym| {
4129 try ds.updateDeclLineNumber(module, decl);4125 try d_sym.updateDeclLineNumber(module, decl);
4130 }4126 }
4131}4127}
41324128
...@@ -4322,27 +4318,27 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {...@@ -4322,27 +4318,27 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
4322 _ = self.atom_by_index_table.remove(decl.link.macho.local_sym_index);4318 _ = self.atom_by_index_table.remove(decl.link.macho.local_sym_index);
4323 decl.link.macho.local_sym_index = 0;4319 decl.link.macho.local_sym_index = 0;
4324 }4320 }
4325 if (self.d_sym) |*ds| {4321 if (self.d_sym) |*d_sym| {
4326 // TODO make this logic match freeAtom. Maybe abstract the logic4322 // TODO make this logic match freeAtom. Maybe abstract the logic
4327 // out since the same thing is desired for both.4323 // out since the same thing is desired for both.
4328 _ = ds.dbg_line_fn_free_list.remove(&decl.fn_link.macho);4324 _ = d_sym.dbg_line_fn_free_list.remove(&decl.fn_link.macho);
4329 if (decl.fn_link.macho.prev) |prev| {4325 if (decl.fn_link.macho.prev) |prev| {
4330 ds.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};4326 d_sym.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
4331 prev.next = decl.fn_link.macho.next;4327 prev.next = decl.fn_link.macho.next;
4332 if (decl.fn_link.macho.next) |next| {4328 if (decl.fn_link.macho.next) |next| {
4333 next.prev = prev;4329 next.prev = prev;
4334 } else {4330 } else {
4335 ds.dbg_line_fn_last = prev;4331 d_sym.dbg_line_fn_last = prev;
4336 }4332 }
4337 } else if (decl.fn_link.macho.next) |next| {4333 } else if (decl.fn_link.macho.next) |next| {
4338 ds.dbg_line_fn_first = next;4334 d_sym.dbg_line_fn_first = next;
4339 next.prev = null;4335 next.prev = null;
4340 }4336 }
4341 if (ds.dbg_line_fn_first == &decl.fn_link.macho) {4337 if (d_sym.dbg_line_fn_first == &decl.fn_link.macho) {
4342 ds.dbg_line_fn_first = decl.fn_link.macho.next;4338 d_sym.dbg_line_fn_first = decl.fn_link.macho.next;
4343 }4339 }
4344 if (ds.dbg_line_fn_last == &decl.fn_link.macho) {4340 if (d_sym.dbg_line_fn_last == &decl.fn_link.macho) {
4345 ds.dbg_line_fn_last = decl.fn_link.macho.prev;4341 d_sym.dbg_line_fn_last = decl.fn_link.macho.prev;
4346 }4342 }
4347 }4343 }
4348}4344}
src/link/MachO/DebugSymbols.zig+313-174
...@@ -3,7 +3,8 @@ const DebugSymbols = @This();...@@ -3,7 +3,8 @@ const DebugSymbols = @This();
3const std = @import("std");3const std = @import("std");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const fs = std.fs;5const fs = std.fs;
6const log = std.log.scoped(.dsym);6const log = std.log.scoped(.link);
7const leb128 = std.leb;
7const macho = std.macho;8const macho = std.macho;
8const math = std.math;9const math = std.math;
9const mem = std.mem;10const mem = std.mem;
...@@ -22,8 +23,6 @@ const SrcFn = MachO.SrcFn;...@@ -22,8 +23,6 @@ const SrcFn = MachO.SrcFn;
22const makeStaticString = MachO.makeStaticString;23const makeStaticString = MachO.makeStaticString;
23const padToIdeal = MachO.padToIdeal;24const padToIdeal = MachO.padToIdeal;
2425
25const page_size: u16 = 0x1000;
26
27base: *MachO,26base: *MachO,
28file: fs.File,27file: fs.File,
2928
...@@ -49,9 +48,6 @@ uuid_cmd_index: ?u16 = null,...@@ -49,9 +48,6 @@ uuid_cmd_index: ?u16 = null,
49/// Index into __TEXT,__text section.48/// Index into __TEXT,__text section.
50text_section_index: ?u16 = null,49text_section_index: ?u16 = null,
5150
52linkedit_off: u16 = page_size,
53linkedit_size: u16 = page_size,
54
55debug_info_section_index: ?u16 = null,51debug_info_section_index: ?u16 = null,
56debug_abbrev_section_index: ?u16 = null,52debug_abbrev_section_index: ?u16 = null,
57debug_str_section_index: ?u16 = null,53debug_str_section_index: ?u16 = null,
...@@ -76,7 +72,6 @@ dbg_info_decl_last: ?*TextBlock = null,...@@ -76,7 +72,6 @@ dbg_info_decl_last: ?*TextBlock = null,
76debug_string_table: std.ArrayListUnmanaged(u8) = .{},72debug_string_table: std.ArrayListUnmanaged(u8) = .{},
7773
78load_commands_dirty: bool = false,74load_commands_dirty: bool = false,
79strtab_dirty: bool = false,
80debug_string_table_dirty: bool = false,75debug_string_table_dirty: bool = false,
81debug_abbrev_section_dirty: bool = false,76debug_abbrev_section_dirty: bool = false,
82debug_aranges_section_dirty: bool = false,77debug_aranges_section_dirty: bool = false,
...@@ -87,8 +82,12 @@ const abbrev_compile_unit = 1;...@@ -87,8 +82,12 @@ const abbrev_compile_unit = 1;
87const abbrev_subprogram = 2;82const abbrev_subprogram = 2;
88const abbrev_subprogram_retvoid = 3;83const abbrev_subprogram_retvoid = 3;
89const abbrev_base_type = 4;84const abbrev_base_type = 4;
90const abbrev_pad1 = 5;85const abbrev_ptr_type = 5;
91const abbrev_parameter = 6;86const abbrev_struct_type = 6;
87const abbrev_anon_struct_type = 7;
88const abbrev_struct_member = 8;
89const abbrev_pad1 = 9;
90const abbrev_parameter = 10;
9291
93/// The reloc offset for the virtual address of a function in its Line Number Program.92/// The reloc offset for the virtual address of a function in its Line Number Program.
94/// Size is a virtual address integer.93/// Size is a virtual address integer.
...@@ -108,30 +107,21 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -108,30 +107,21 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
108 try self.load_commands.append(allocator, base_cmd);107 try self.load_commands.append(allocator, base_cmd);
109 self.load_commands_dirty = true;108 self.load_commands_dirty = true;
110 }109 }
110
111 if (self.symtab_cmd_index == null) {111 if (self.symtab_cmd_index == null) {
112 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);112 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
113 const base_cmd = self.base.load_commands.items[self.base.symtab_cmd_index.?].symtab;113 try self.load_commands.append(self.base.base.allocator, .{
114 const symtab_size = base_cmd.nsyms * @sizeOf(macho.nlist_64);
115 const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64));
116
117 log.debug("found symbol table free space 0x{x} to 0x{x}", .{ symtab_off, symtab_off + symtab_size });
118
119 const strtab_off = self.findFreeSpaceLinkedit(base_cmd.strsize, 1);
120
121 log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + base_cmd.strsize });
122
123 try self.load_commands.append(allocator, .{
124 .symtab = .{114 .symtab = .{
125 .cmdsize = @sizeOf(macho.symtab_command),115 .cmdsize = @sizeOf(macho.symtab_command),
126 .symoff = @intCast(u32, symtab_off),116 .symoff = 0,
127 .nsyms = base_cmd.nsyms,117 .nsyms = 0,
128 .stroff = @intCast(u32, strtab_off),118 .stroff = 0,
129 .strsize = base_cmd.strsize,119 .strsize = 0,
130 },120 },
131 });121 });
132 self.load_commands_dirty = true;122 self.load_commands_dirty = true;
133 self.strtab_dirty = true;
134 }123 }
124
135 if (self.pagezero_segment_cmd_index == null) {125 if (self.pagezero_segment_cmd_index == null) {
136 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);126 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
137 const base_cmd = self.base.load_commands.items[self.base.pagezero_segment_cmd_index.?].segment;127 const base_cmd = self.base.load_commands.items[self.base.pagezero_segment_cmd_index.?].segment;
...@@ -139,6 +129,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -139,6 +129,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
139 try self.load_commands.append(allocator, .{ .segment = cmd });129 try self.load_commands.append(allocator, .{ .segment = cmd });
140 self.load_commands_dirty = true;130 self.load_commands_dirty = true;
141 }131 }
132
142 if (self.text_segment_cmd_index == null) {133 if (self.text_segment_cmd_index == null) {
143 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);134 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
144 const base_cmd = self.base.load_commands.items[self.base.text_segment_cmd_index.?].segment;135 const base_cmd = self.base.load_commands.items[self.base.text_segment_cmd_index.?].segment;
...@@ -146,6 +137,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -146,6 +137,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
146 try self.load_commands.append(allocator, .{ .segment = cmd });137 try self.load_commands.append(allocator, .{ .segment = cmd });
147 self.load_commands_dirty = true;138 self.load_commands_dirty = true;
148 }139 }
140
149 if (self.data_const_segment_cmd_index == null) outer: {141 if (self.data_const_segment_cmd_index == null) outer: {
150 if (self.base.data_const_segment_cmd_index == null) break :outer; // __DATA_CONST is optional142 if (self.base.data_const_segment_cmd_index == null) break :outer; // __DATA_CONST is optional
151 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);143 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -154,6 +146,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -154,6 +146,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
154 try self.load_commands.append(allocator, .{ .segment = cmd });146 try self.load_commands.append(allocator, .{ .segment = cmd });
155 self.load_commands_dirty = true;147 self.load_commands_dirty = true;
156 }148 }
149
157 if (self.data_segment_cmd_index == null) outer: {150 if (self.data_segment_cmd_index == null) outer: {
158 if (self.base.data_segment_cmd_index == null) break :outer; // __DATA is optional151 if (self.base.data_segment_cmd_index == null) break :outer; // __DATA is optional
159 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);152 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -162,26 +155,29 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -162,26 +155,29 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
162 try self.load_commands.append(allocator, .{ .segment = cmd });155 try self.load_commands.append(allocator, .{ .segment = cmd });
163 self.load_commands_dirty = true;156 self.load_commands_dirty = true;
164 }157 }
158
165 if (self.linkedit_segment_cmd_index == null) {159 if (self.linkedit_segment_cmd_index == null) {
166 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);160 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
167 const base_cmd = self.base.load_commands.items[self.base.linkedit_segment_cmd_index.?].segment;161 const base_cmd = self.base.load_commands.items[self.base.linkedit_segment_cmd_index.?].segment;
168 var cmd = try self.copySegmentCommand(allocator, base_cmd);162 var cmd = try self.copySegmentCommand(allocator, base_cmd);
169 cmd.inner.vmsize = self.linkedit_size;163 // TODO this needs reworking
170 cmd.inner.fileoff = self.linkedit_off;164 cmd.inner.vmsize = self.base.page_size;
171 cmd.inner.filesize = self.linkedit_size;165 cmd.inner.fileoff = self.base.page_size;
166 cmd.inner.filesize = self.base.page_size;
172 try self.load_commands.append(allocator, .{ .segment = cmd });167 try self.load_commands.append(allocator, .{ .segment = cmd });
173 self.load_commands_dirty = true;168 self.load_commands_dirty = true;
174 }169 }
170
175 if (self.dwarf_segment_cmd_index == null) {171 if (self.dwarf_segment_cmd_index == null) {
176 self.dwarf_segment_cmd_index = @intCast(u16, self.load_commands.items.len);172 self.dwarf_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
177173
178 const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;174 const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
179 const ideal_size: u16 = 200 + 128 + 160 + 250;175 const ideal_size: u16 = 200 + 128 + 160 + 250;
180 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), page_size);176 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.base.page_size);
181 const off = linkedit.inner.fileoff + linkedit.inner.filesize;177 const fileoff = linkedit.inner.fileoff + linkedit.inner.filesize;
182 const vmaddr = linkedit.inner.vmaddr + linkedit.inner.vmsize;178 const vmaddr = linkedit.inner.vmaddr + linkedit.inner.vmsize;
183179
184 log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size });180 log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });
185181
186 try self.load_commands.append(allocator, .{182 try self.load_commands.append(allocator, .{
187 .segment = .{183 .segment = .{
...@@ -189,13 +185,14 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -189,13 +185,14 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
189 .segname = makeStaticString("__DWARF"),185 .segname = makeStaticString("__DWARF"),
190 .vmaddr = vmaddr,186 .vmaddr = vmaddr,
191 .vmsize = needed_size,187 .vmsize = needed_size,
192 .fileoff = off,188 .fileoff = fileoff,
193 .filesize = needed_size,189 .filesize = needed_size,
194 },190 },
195 },191 },
196 });192 });
197 self.load_commands_dirty = true;193 self.load_commands_dirty = true;
198 }194 }
195
199 if (self.debug_str_section_index == null) {196 if (self.debug_str_section_index == null) {
200 assert(self.debug_string_table.items.len == 0);197 assert(self.debug_string_table.items.len == 0);
201 self.debug_str_section_index = try self.allocateSection(198 self.debug_str_section_index = try self.allocateSection(
...@@ -205,18 +202,22 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -205,18 +202,22 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
205 );202 );
206 self.debug_string_table_dirty = true;203 self.debug_string_table_dirty = true;
207 }204 }
205
208 if (self.debug_info_section_index == null) {206 if (self.debug_info_section_index == null) {
209 self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0);207 self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0);
210 self.debug_info_header_dirty = true;208 self.debug_info_header_dirty = true;
211 }209 }
210
212 if (self.debug_abbrev_section_index == null) {211 if (self.debug_abbrev_section_index == null) {
213 self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0);212 self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0);
214 self.debug_abbrev_section_dirty = true;213 self.debug_abbrev_section_dirty = true;
215 }214 }
215
216 if (self.debug_aranges_section_index == null) {216 if (self.debug_aranges_section_index == null) {
217 self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4);217 self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4);
218 self.debug_aranges_section_dirty = true;218 self.debug_aranges_section_dirty = true;
219 }219 }
220
220 if (self.debug_line_section_index == null) {221 if (self.debug_line_section_index == null) {
221 self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0);222 self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0);
222 self.debug_line_header_dirty = true;223 self.debug_line_header_dirty = true;
...@@ -300,41 +301,91 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -300,41 +301,91 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
300 // we can simply append these bytes.301 // we can simply append these bytes.
301 const abbrev_buf = [_]u8{302 const abbrev_buf = [_]u8{
302 abbrev_compile_unit, DW.TAG.compile_unit, DW.CHILDREN.yes, // header303 abbrev_compile_unit, DW.TAG.compile_unit, DW.CHILDREN.yes, // header
303 DW.AT.stmt_list, DW.FORM.sec_offset, // offset304 DW.AT.stmt_list, DW.FORM.sec_offset, DW.AT.low_pc,
304 DW.AT.low_pc, DW.FORM.addr,305 DW.FORM.addr, DW.AT.high_pc, DW.FORM.addr,
305 DW.AT.high_pc, DW.FORM.addr,306 DW.AT.name, DW.FORM.strp, DW.AT.comp_dir,
306 DW.AT.name, DW.FORM.strp,307 DW.FORM.strp, DW.AT.producer, DW.FORM.strp,
307 DW.AT.comp_dir, DW.FORM.strp,308 DW.AT.language, DW.FORM.data2, 0,
308 DW.AT.producer, DW.FORM.strp,309 0, // table sentinel
309 DW.AT.language, DW.FORM.data2,310 abbrev_subprogram,
310 0, 0, // table sentinel311 DW.TAG.subprogram,
311 abbrev_subprogram, DW.TAG.subprogram, DW.CHILDREN.yes, // header312 DW.CHILDREN.yes, // header
312 DW.AT.low_pc, DW.FORM.addr, // start VM address313 DW.AT.low_pc,
313 DW.AT.high_pc, DW.FORM.data4,314 DW.FORM.addr,
314 DW.AT.type, DW.FORM.ref4,315 DW.AT.high_pc,
315 DW.AT.name, DW.FORM.string,316 DW.FORM.data4,
316 DW.AT.decl_line, DW.FORM.data4,317 DW.AT.type,
317 DW.AT.decl_file, DW.FORM.data1,318 DW.FORM.ref4,
319 DW.AT.name,
320 DW.FORM.string,
318 0, 0, // table sentinel321 0, 0, // table sentinel
319 abbrev_subprogram_retvoid,322 abbrev_subprogram_retvoid,
320 DW.TAG.subprogram, DW.CHILDREN.yes, // header323 DW.TAG.subprogram, DW.CHILDREN.yes, // header
321 DW.AT.low_pc, DW.FORM.addr,324 DW.AT.low_pc, DW.FORM.addr,
322 DW.AT.high_pc, DW.FORM.data4,325 DW.AT.high_pc, DW.FORM.data4,
323 DW.AT.name, DW.FORM.string,326 DW.AT.name, DW.FORM.string,
324 DW.AT.decl_line, DW.FORM.data4,327 0,
325 DW.AT.decl_file, DW.FORM.data1,328 0, // table sentinel
326 0, 0, // table sentinel329 abbrev_base_type,
327 abbrev_base_type, DW.TAG.base_type, DW.CHILDREN.no, // header330 DW.TAG.base_type,
328 DW.AT.encoding, DW.FORM.data1, DW.AT.byte_size,331 DW.CHILDREN.no, // header
329 DW.FORM.data1, DW.AT.name, DW.FORM.string,332 DW.AT.encoding,
330 0, 0, // table sentinel333 DW.FORM.data1,
331 abbrev_pad1, DW.TAG.unspecified_type, DW.CHILDREN.no, // header334 DW.AT.byte_size,
332 0, 0, // table sentinel335 DW.FORM.data1,
333 abbrev_parameter, DW.TAG.formal_parameter, DW.CHILDREN.no, // header336 DW.AT.name,
334 DW.AT.location, DW.FORM.exprloc, DW.AT.type,337 DW.FORM.string,
335 DW.FORM.ref4, DW.AT.name, DW.FORM.string,338 0,
336 0, 0, // table sentinel339 0, // table sentinel
337 0, 0, 0, // section sentinel340 abbrev_ptr_type,
341 DW.TAG.pointer_type,
342 DW.CHILDREN.no, // header
343 DW.AT.type,
344 DW.FORM.ref4,
345 0,
346 0, // table sentinel
347 abbrev_struct_type,
348 DW.TAG.structure_type,
349 DW.CHILDREN.yes, // header
350 DW.AT.byte_size,
351 DW.FORM.sdata,
352 DW.AT.name,
353 DW.FORM.string,
354 0,
355 0, // table sentinel
356 abbrev_anon_struct_type,
357 DW.TAG.structure_type,
358 DW.CHILDREN.yes, // header
359 DW.AT.byte_size,
360 DW.FORM.sdata,
361 0,
362 0, // table sentinel
363 abbrev_struct_member,
364 DW.TAG.member,
365 DW.CHILDREN.no, // header
366 DW.AT.name,
367 DW.FORM.string,
368 DW.AT.type,
369 DW.FORM.ref4,
370 DW.AT.data_member_location,
371 DW.FORM.sdata,
372 0,
373 0, // table sentinel
374 abbrev_pad1,
375 DW.TAG.unspecified_type,
376 DW.CHILDREN.no, // header
377 0,
378 0, // table sentinel
379 abbrev_parameter,
380 DW.TAG.formal_parameter, DW.CHILDREN.no, // header
381 DW.AT.location, DW.FORM.exprloc,
382 DW.AT.type, DW.FORM.ref4,
383 DW.AT.name, DW.FORM.string,
384 0,
385 0, // table sentinel
386 0,
387 0,
388 0, // section sentinel
338 };389 };
339390
340 const needed_size = abbrev_buf.len;391 const needed_size = abbrev_buf.len;
...@@ -583,13 +634,12 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -583,13 +634,12 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
583 }634 }
584 }635 }
585636
586 try self.writeStringTable();637 try self.writeLinkeditSegment();
587 self.updateDwarfSegment();638 self.updateDwarfSegment();
588 try self.writeLoadCommands(allocator);639 try self.writeLoadCommands(allocator);
589 try self.writeHeader();640 try self.writeHeader();
590641
591 assert(!self.load_commands_dirty);642 assert(!self.load_commands_dirty);
592 assert(!self.strtab_dirty);
593 assert(!self.debug_abbrev_section_dirty);643 assert(!self.debug_abbrev_section_dirty);
594 assert(!self.debug_aranges_section_dirty);644 assert(!self.debug_aranges_section_dirty);
595 assert(!self.debug_string_table_dirty);645 assert(!self.debug_string_table_dirty);
...@@ -663,7 +713,7 @@ fn updateDwarfSegment(self: *DebugSymbols) void {...@@ -663,7 +713,7 @@ fn updateDwarfSegment(self: *DebugSymbols) void {
663 if (file_size != dwarf_segment.inner.filesize) {713 if (file_size != dwarf_segment.inner.filesize) {
664 dwarf_segment.inner.filesize = file_size;714 dwarf_segment.inner.filesize = file_size;
665 if (dwarf_segment.inner.vmsize < dwarf_segment.inner.filesize) {715 if (dwarf_segment.inner.vmsize < dwarf_segment.inner.filesize) {
666 dwarf_segment.inner.vmsize = mem.alignForwardGeneric(u64, dwarf_segment.inner.filesize, page_size);716 dwarf_segment.inner.vmsize = mem.alignForwardGeneric(u64, dwarf_segment.inner.filesize, self.base.page_size);
667 }717 }
668 self.load_commands_dirty = true;718 self.load_commands_dirty = true;
669 }719 }
...@@ -719,23 +769,10 @@ fn writeHeader(self: *DebugSymbols) !void {...@@ -719,23 +769,10 @@ fn writeHeader(self: *DebugSymbols) !void {
719 try self.file.pwriteAll(mem.asBytes(&header), 0);769 try self.file.pwriteAll(mem.asBytes(&header), 0);
720}770}
721771
722fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 {
723 assert(start > 0);
724 var min_pos: u64 = std.math.maxInt(u64);
725
726 if (self.symtab_cmd_index) |idx| {
727 const symtab = self.load_commands.items[idx].symtab;
728 if (symtab.symoff >= start and symtab.symoff < min_pos) min_pos = symtab.symoff;
729 if (symtab.stroff >= start and symtab.stroff < min_pos) min_pos = symtab.stroff;
730 }
731
732 return min_pos - start;
733}
734
735fn allocatedSize(self: *DebugSymbols, start: u64) u64 {772fn allocatedSize(self: *DebugSymbols, start: u64) u64 {
736 const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;773 const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
737 assert(start >= seg.inner.fileoff);774 assert(start >= seg.inner.fileoff);
738 var min_pos: u64 = seg.inner.fileoff + seg.inner.filesize;775 var min_pos: u64 = std.math.maxInt(u64);
739 for (seg.sections.items) |section| {776 for (seg.sections.items) |section| {
740 if (section.offset <= start) continue;777 if (section.offset <= start) continue;
741 if (section.offset < min_pos) min_pos = section.offset;778 if (section.offset < min_pos) min_pos = section.offset;
...@@ -743,102 +780,72 @@ fn allocatedSize(self: *DebugSymbols, start: u64) u64 {...@@ -743,102 +780,72 @@ fn allocatedSize(self: *DebugSymbols, start: u64) u64 {
743 return min_pos - start;780 return min_pos - start;
744}781}
745782
746fn detectAllocCollisionLinkedit(self: *DebugSymbols, start: u64, size: u64) ?u64 {783fn writeLinkeditSegment(self: *DebugSymbols) !void {
747 const end = start + padToIdeal(size);784 const tracy = trace(@src());
785 defer tracy.end();
748786
749 if (self.symtab_cmd_index) |idx| outer: {787 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
750 if (self.load_commands.items.len == idx) break :outer;788 seg.inner.filesize = 0;
751 const symtab = self.load_commands.items[idx].symtab;
752 {
753 // Symbol table
754 const symsize = symtab.nsyms * @sizeOf(macho.nlist_64);
755 const increased_size = padToIdeal(symsize);
756 const test_end = symtab.symoff + increased_size;
757 if (end > symtab.symoff and start < test_end) {
758 return test_end;
759 }
760 }
761 {
762 // String table
763 const increased_size = padToIdeal(symtab.strsize);
764 const test_end = symtab.stroff + increased_size;
765 if (end > symtab.stroff and start < test_end) {
766 return test_end;
767 }
768 }
769 }
770789
771 return null;790 try self.writeSymbolTable();
791 try self.writeStringTable();
772}792}
773793
774fn findFreeSpaceLinkedit(self: *DebugSymbols, object_size: u64, min_alignment: u16) u64 {794fn writeSymbolTable(self: *DebugSymbols) !void {
775 var start: u64 = self.linkedit_off;795 const tracy = trace(@src());
776 while (self.detectAllocCollisionLinkedit(start, object_size)) |item_end| {796 defer tracy.end();
777 start = mem.alignForwardGeneric(u64, item_end, min_alignment);
778 }
779 return start;
780}
781797
782fn relocateSymbolTable(self: *DebugSymbols) !void {798 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
783 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;799 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
784 const nlocals = self.base.locals.items.len;800 symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
785 const nglobals = self.base.globals.items.len;
786 const nsyms = nlocals + nglobals;
787
788 if (symtab.nsyms < nsyms) {
789 const needed_size = nsyms * @sizeOf(macho.nlist_64);
790 if (needed_size > self.allocatedSizeLinkedit(symtab.symoff)) {
791 // Move the entire symbol table to a new location
792 const new_symoff = self.findFreeSpaceLinkedit(needed_size, @alignOf(macho.nlist_64));
793 const existing_size = symtab.nsyms * @sizeOf(macho.nlist_64);
794
795 assert(new_symoff + existing_size <= self.linkedit_off + self.linkedit_size); // TODO expand LINKEDIT segment.
796 log.debug("relocating symbol table from 0x{x}-0x{x} to 0x{x}-0x{x}", .{
797 symtab.symoff,
798 symtab.symoff + existing_size,
799 new_symoff,
800 new_symoff + existing_size,
801 });
802801
803 const amt = try self.file.copyRangeAll(symtab.symoff, self.file, new_symoff, existing_size);802 var locals = std.ArrayList(macho.nlist_64).init(self.base.base.allocator);
804 if (amt != existing_size) return error.InputOutput;803 defer locals.deinit();
805 symtab.symoff = @intCast(u32, new_symoff);804
806 }805 for (self.base.locals.items) |sym| {
807 symtab.nsyms = @intCast(u32, nsyms);806 if (sym.n_strx == 0) continue;
808 self.load_commands_dirty = true;807 if (self.base.symbol_resolver.get(sym.n_strx)) |_| continue;
808 try locals.append(sym);
809 }809 }
810}
811810
812pub fn writeLocalSymbol(self: *DebugSymbols, index: usize) !void {811 const nlocals = locals.items.len;
813 const tracy = trace(@src());812 const nexports = self.base.globals.items.len;
814 defer tracy.end();813
815 try self.relocateSymbolTable();814 const locals_off = symtab.symoff;
816 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;815 const locals_size = nlocals * @sizeOf(macho.nlist_64);
817 const off = symtab.symoff + @sizeOf(macho.nlist_64) * index;816 log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off });
818 log.debug("writing local symbol {} at 0x{x}", .{ index, off });817 try self.file.pwriteAll(mem.sliceAsBytes(locals.items), locals_off);
819 try self.file.pwriteAll(mem.asBytes(&self.base.locals.items[index]), off);818
819 const exports_off = locals_off + locals_size;
820 const exports_size = nexports * @sizeOf(macho.nlist_64);
821 log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off });
822 try self.file.pwriteAll(mem.sliceAsBytes(self.base.globals.items), exports_off);
823
824 symtab.nsyms = @intCast(u32, nlocals + nexports);
825 seg.inner.filesize += locals_size + exports_size;
826
827 self.load_commands_dirty = true;
820}828}
821829
822fn writeStringTable(self: *DebugSymbols) !void {830fn writeStringTable(self: *DebugSymbols) !void {
823 if (!self.strtab_dirty) return;
824
825 const tracy = trace(@src());831 const tracy = trace(@src());
826 defer tracy.end();832 defer tracy.end();
827833
834 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
828 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;835 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
829 const allocated_size = self.allocatedSizeLinkedit(symtab.stroff);836 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
830 const needed_size = mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64));837 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64)));
838 seg.inner.filesize += symtab.strsize;
831839
832 if (needed_size > allocated_size) {
833 symtab.strsize = 0;
834 symtab.stroff = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1));
835 }
836 symtab.strsize = @intCast(u32, needed_size);
837 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });840 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
838841
839 try self.file.pwriteAll(self.base.strtab.items, symtab.stroff);842 try self.file.pwriteAll(self.base.strtab.items, symtab.stroff);
843
844 if (symtab.strsize > self.base.strtab.items.len) {
845 // This is potentially the last section, so we need to pad it out.
846 try self.file.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
847 }
840 self.load_commands_dirty = true;848 self.load_commands_dirty = true;
841 self.strtab_dirty = false;
842}849}
843850
844pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const Module.Decl) !void {851pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const Module.Decl) !void {
...@@ -846,14 +853,21 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M...@@ -846,14 +853,21 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M
846 const tracy = trace(@src());853 const tracy = trace(@src());
847 defer tracy.end();854 defer tracy.end();
848855
856 log.debug("updateDeclLineNumber {s}{*}", .{ decl.name, decl });
857
849 const func = decl.val.castTag(.function).?.data;858 const func = decl.val.castTag(.function).?.data;
850 const line_off = @intCast(u28, decl.src_line + func.lbrace_line);859 log.debug(" (decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d})", .{
860 decl.src_line,
861 func.lbrace_line,
862 func.rbrace_line,
863 });
864 const line = @intCast(u28, decl.src_line + func.lbrace_line);
851865
852 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;866 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
853 const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?];867 const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?];
854 const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff();868 const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff();
855 var data: [4]u8 = undefined;869 var data: [4]u8 = undefined;
856 leb.writeUnsignedFixed(4, &data, line_off);870 leb.writeUnsignedFixed(4, &data, line);
857 try self.file.pwriteAll(&data, file_pos);871 try self.file.pwriteAll(&data, file_pos);
858}872}
859873
...@@ -886,7 +900,13 @@ pub fn initDeclDebugBuffers(...@@ -886,7 +900,13 @@ pub fn initDeclDebugBuffers(
886 try dbg_line_buffer.ensureTotalCapacity(26);900 try dbg_line_buffer.ensureTotalCapacity(26);
887901
888 const func = decl.val.castTag(.function).?.data;902 const func = decl.val.castTag(.function).?.data;
889 const line_off = @intCast(u28, decl.src_line + func.lbrace_line);903 log.debug("updateFunc {s}{*}", .{ decl.name, func.owner_decl });
904 log.debug(" (decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d})", .{
905 decl.src_line,
906 func.lbrace_line,
907 func.rbrace_line,
908 });
909 const line = @intCast(u28, decl.src_line + func.lbrace_line);
890910
891 dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{911 dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{
892 DW.LNS.extended_op,912 DW.LNS.extended_op,
...@@ -902,7 +922,7 @@ pub fn initDeclDebugBuffers(...@@ -902,7 +922,7 @@ pub fn initDeclDebugBuffers(
902 // to this function's begin curly.922 // to this function's begin curly.
903 assert(getRelocDbgLineOff() == dbg_line_buffer.items.len);923 assert(getRelocDbgLineOff() == dbg_line_buffer.items.len);
904 // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later.924 // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later.
905 leb.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off);925 leb.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line);
906926
907 dbg_line_buffer.appendAssumeCapacity(DW.LNS.set_file);927 dbg_line_buffer.appendAssumeCapacity(DW.LNS.set_file);
908 assert(getRelocDbgFileIndex() == dbg_line_buffer.items.len);928 assert(getRelocDbgFileIndex() == dbg_line_buffer.items.len);
...@@ -917,7 +937,7 @@ pub fn initDeclDebugBuffers(...@@ -917,7 +937,7 @@ pub fn initDeclDebugBuffers(
917937
918 // .debug_info subprogram938 // .debug_info subprogram
919 const decl_name_with_null = decl.name[0 .. mem.sliceTo(decl.name, 0).len + 1];939 const decl_name_with_null = decl.name[0 .. mem.sliceTo(decl.name, 0).len + 1];
920 try dbg_info_buffer.ensureUnusedCapacity(27 + decl_name_with_null.len);940 try dbg_info_buffer.ensureUnusedCapacity(25 + decl_name_with_null.len);
921941
922 const fn_ret_type = decl.ty.fnReturnType();942 const fn_ret_type = decl.ty.fnReturnType();
923 const fn_ret_has_bits = fn_ret_type.hasRuntimeBits();943 const fn_ret_has_bits = fn_ret_type.hasRuntimeBits();
...@@ -945,8 +965,6 @@ pub fn initDeclDebugBuffers(...@@ -945,8 +965,6 @@ pub fn initDeclDebugBuffers(
945 dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4965 dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4
946 }966 }
947 dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT.name, DW.FORM.string967 dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT.name, DW.FORM.string
948 mem.writeIntLittle(u32, dbg_info_buffer.addManyAsArrayAssumeCapacity(4), line_off + 1); // DW.AT.decl_line, DW.FORM.data4
949 dbg_info_buffer.appendAssumeCapacity(file_index); // DW.AT.decl_file, DW.FORM.data1
950 },968 },
951 else => {969 else => {
952 // TODO implement .debug_info for global variables970 // TODO implement .debug_info for global variables
...@@ -966,7 +984,6 @@ pub fn commitDeclDebugInfo(...@@ -966,7 +984,6 @@ pub fn commitDeclDebugInfo(
966 module: *Module,984 module: *Module,
967 decl: *Module.Decl,985 decl: *Module.Decl,
968 debug_buffers: *DeclDebugBuffers,986 debug_buffers: *DeclDebugBuffers,
969 target: std.Target,
970) !void {987) !void {
971 const tracy = trace(@src());988 const tracy = trace(@src());
972 defer tracy.end();989 defer tracy.end();
...@@ -1097,14 +1114,26 @@ pub fn commitDeclDebugInfo(...@@ -1097,14 +1114,26 @@ pub fn commitDeclDebugInfo(
1097 if (dbg_info_buffer.items.len == 0)1114 if (dbg_info_buffer.items.len == 0)
1098 return;1115 return;
10991116
1117 // We need this for the duration of this function only so that for composite
1118 // types such as []const u32, if the type *u32 is non-existent, we create
1119 // it synthetically and store the backing bytes in this arena. After we are
1120 // done with the relocations, we can safely deinit the entire memory slab.
1121 // TODO currently, we do not store the relocations for future use, however,
1122 // if that is the case, we should move memory management to a higher scope,
1123 // such as linker scope, or whatnot.
1124 var dbg_type_arena = std.heap.ArenaAllocator.init(allocator);
1125 defer dbg_type_arena.deinit();
1126
1100 {1127 {
1101 // Now we emit the .debug_info types of the Decl. These will count towards the size of1128 // Now we emit the .debug_info types of the Decl. These will count towards the size of
1102 // the buffer, so we have to do it before computing the offset, and we can't perform the actual1129 // the buffer, so we have to do it before computing the offset, and we can't perform the actual
1103 // relocations yet.1130 // relocations yet.
1104 var it = dbg_info_type_relocs.iterator();1131 var it: usize = 0;
1105 while (it.next()) |entry| {1132 while (it < dbg_info_type_relocs.count()) : (it += 1) {
1106 entry.value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);1133 const ty = dbg_info_type_relocs.keys()[it];
1107 try self.addDbgInfoType(entry.key_ptr.*, dbg_info_buffer, target);1134 const value_ptr = dbg_info_type_relocs.getPtr(ty).?;
1135 value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
1136 try self.addDbgInfoType(dbg_type_arena.allocator(), ty, dbg_info_buffer, dbg_info_type_relocs);
1108 }1137 }
1109 }1138 }
11101139
...@@ -1129,24 +1158,25 @@ pub fn commitDeclDebugInfo(...@@ -1129,24 +1158,25 @@ pub fn commitDeclDebugInfo(
1129/// Asserts the type has codegen bits.1158/// Asserts the type has codegen bits.
1130fn addDbgInfoType(1159fn addDbgInfoType(
1131 self: *DebugSymbols,1160 self: *DebugSymbols,
1161 arena: Allocator,
1132 ty: Type,1162 ty: Type,
1133 dbg_info_buffer: *std.ArrayList(u8),1163 dbg_info_buffer: *std.ArrayList(u8),
1134 target: std.Target,1164 dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
1135) !void {1165) !void {
1136 _ = self;1166 const target = self.base.base.options.target;
1167 var relocs = std.ArrayList(struct { ty: Type, reloc: u32 }).init(arena);
1168
1137 switch (ty.zigTypeTag()) {1169 switch (ty.zigTypeTag()) {
1138 .Void => unreachable,
1139 .NoReturn => unreachable,1170 .NoReturn => unreachable,
1171 .Void => {
1172 try dbg_info_buffer.append(abbrev_pad1);
1173 },
1140 .Bool => {1174 .Bool => {
1141 try dbg_info_buffer.appendSlice(&[_]u8{1175 try dbg_info_buffer.appendSlice(&[_]u8{
1142 abbrev_base_type,1176 abbrev_base_type,
1143 DW.ATE.boolean, // DW.AT.encoding , DW.FORM.data11177 DW.ATE.boolean, // DW.AT.encoding , DW.FORM.data1
1144 1, // DW.AT.byte_size, DW.FORM.data11178 1, // DW.AT.byte_size, DW.FORM.data1
1145 'b',1179 'b', 'o', 'o', 'l', 0, // DW.AT.name, DW.FORM.string
1146 'o',
1147 'o',
1148 'l',
1149 0, // DW.AT.name, DW.FORM.string
1150 });1180 });
1151 },1181 },
1152 .Int => {1182 .Int => {
...@@ -1163,11 +1193,120 @@ fn addDbgInfoType(...@@ -1163,11 +1193,120 @@ fn addDbgInfoType(
1163 // DW.AT.name, DW.FORM.string1193 // DW.AT.name, DW.FORM.string
1164 try dbg_info_buffer.writer().print("{}\x00", .{ty});1194 try dbg_info_buffer.writer().print("{}\x00", .{ty});
1165 },1195 },
1196 .Optional => {
1197 if (ty.isPtrLikeOptional()) {
1198 try dbg_info_buffer.ensureUnusedCapacity(12);
1199 dbg_info_buffer.appendAssumeCapacity(abbrev_base_type);
1200 // DW.AT.encoding, DW.FORM.data1
1201 dbg_info_buffer.appendAssumeCapacity(DW.ATE.address);
1202 // DW.AT.byte_size, DW.FORM.data1
1203 dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(target)));
1204 // DW.AT.name, DW.FORM.string
1205 try dbg_info_buffer.writer().print("{}\x00", .{ty});
1206 } else {
1207 log.debug("TODO implement .debug_info for type '{}'", .{ty});
1208 try dbg_info_buffer.append(abbrev_pad1);
1209 }
1210 },
1211 .Pointer => {
1212 if (ty.isSlice()) {
1213 // Slices are anonymous structs: struct { .ptr = *, .len = N }
1214 try dbg_info_buffer.ensureUnusedCapacity(23);
1215 // DW.AT.structure_type
1216 dbg_info_buffer.appendAssumeCapacity(abbrev_anon_struct_type);
1217 // DW.AT.byte_size, DW.FORM.sdata
1218 dbg_info_buffer.appendAssumeCapacity(16);
1219 // DW.AT.member
1220 dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
1221 // DW.AT.name, DW.FORM.string
1222 dbg_info_buffer.appendSliceAssumeCapacity("ptr");
1223 dbg_info_buffer.appendAssumeCapacity(0);
1224 // DW.AT.type, DW.FORM.ref4
1225 var index = dbg_info_buffer.items.len;
1226 try dbg_info_buffer.resize(index + 4);
1227 var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
1228 const ptr_ty = ty.slicePtrFieldType(buf);
1229 try relocs.append(.{ .ty = ptr_ty, .reloc = @intCast(u32, index) });
1230 // DW.AT.data_member_location, DW.FORM.sdata
1231 dbg_info_buffer.appendAssumeCapacity(0);
1232 // DW.AT.member
1233 dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
1234 // DW.AT.name, DW.FORM.string
1235 dbg_info_buffer.appendSliceAssumeCapacity("len");
1236 dbg_info_buffer.appendAssumeCapacity(0);
1237 // DW.AT.type, DW.FORM.ref4
1238 index = dbg_info_buffer.items.len;
1239 try dbg_info_buffer.resize(index + 4);
1240 try relocs.append(.{ .ty = Type.initTag(.usize), .reloc = @intCast(u32, index) });
1241 // DW.AT.data_member_location, DW.FORM.sdata
1242 dbg_info_buffer.appendAssumeCapacity(8);
1243 // DW.AT.structure_type delimit children
1244 dbg_info_buffer.appendAssumeCapacity(0);
1245 } else {
1246 try dbg_info_buffer.ensureUnusedCapacity(5);
1247 dbg_info_buffer.appendAssumeCapacity(abbrev_ptr_type);
1248 // DW.AT.type, DW.FORM.ref4
1249 const index = dbg_info_buffer.items.len;
1250 try dbg_info_buffer.resize(index + 4);
1251 try relocs.append(.{ .ty = ty.childType(), .reloc = @intCast(u32, index) });
1252 }
1253 },
1254 .Struct => blk: {
1255 // try dbg_info_buffer.ensureUnusedCapacity(23);
1256 // DW.AT.structure_type
1257 try dbg_info_buffer.append(abbrev_struct_type);
1258 // DW.AT.byte_size, DW.FORM.sdata
1259 const abi_size = ty.abiSize(target);
1260 try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
1261 // DW.AT.name, DW.FORM.string
1262 const struct_name = try ty.nameAlloc(arena);
1263 try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1);
1264 dbg_info_buffer.appendSliceAssumeCapacity(struct_name);
1265 dbg_info_buffer.appendAssumeCapacity(0);
1266
1267 const struct_obj = ty.castTag(.@"struct").?.data;
1268 if (struct_obj.layout == .Packed) {
1269 log.debug("TODO implement .debug_info for packed structs", .{});
1270 break :blk;
1271 }
1272
1273 const fields = ty.structFields();
1274 for (fields.keys()) |field_name, field_index| {
1275 const field = fields.get(field_name).?;
1276 // DW.AT.member
1277 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);
1278 dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
1279 // DW.AT.name, DW.FORM.string
1280 dbg_info_buffer.appendSliceAssumeCapacity(field_name);
1281 dbg_info_buffer.appendAssumeCapacity(0);
1282 // DW.AT.type, DW.FORM.ref4
1283 var index = dbg_info_buffer.items.len;
1284 try dbg_info_buffer.resize(index + 4);
1285 try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) });
1286 // DW.AT.data_member_location, DW.FORM.sdata
1287 const field_off = ty.structFieldOffset(field_index, target);
1288 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
1289 }
1290
1291 // DW.AT.structure_type delimit children
1292 try dbg_info_buffer.append(0);
1293 },
1166 else => {1294 else => {
1167 std.log.scoped(.compiler).err("TODO implement .debug_info for type '{}'", .{ty});1295 log.debug("TODO implement .debug_info for type '{}'", .{ty});
1168 try dbg_info_buffer.append(abbrev_pad1);1296 try dbg_info_buffer.append(abbrev_pad1);
1169 },1297 },
1170 }1298 }
1299
1300 for (relocs.items) |rel| {
1301 const gop = try dbg_info_type_relocs.getOrPut(self.base.base.allocator, rel.ty);
1302 if (!gop.found_existing) {
1303 gop.value_ptr.* = .{
1304 .off = undefined,
1305 .relocs = .{},
1306 };
1307 }
1308 try gop.value_ptr.relocs.append(self.base.base.allocator, rel.reloc);
1309 }
1171}1310}
11721311
1173fn updateDeclDebugInfoAllocation(1312fn updateDeclDebugInfoAllocation(