From 37033a96ac2e33a56eb2e153462d1a730b426029 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 8 Feb 2024 11:13:52 +0100 Subject: [PATCH] macho: move Dwarf handle to ZigObject from DebugSymbols --- src/link/Dwarf.zig | 30 ++++--- src/link/MachO.zig | 50 +++++------ src/link/MachO/DebugSymbols.zig | 145 ++++++++------------------------ src/link/MachO/ZigObject.zig | 95 ++++++++++++++++++--- 4 files changed, 155 insertions(+), 165 deletions(-) diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 6607cdb119..a38853b7a1 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1351,9 +1351,10 @@ pub fn commitDeclState( }, .macho => { - const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; + const macho_file = self.bin_file.cast(File.MachO).?; + const d_sym = macho_file.getDebugSymbols().?; const sect_index = d_sym.debug_line_section_index.?; - try d_sym.growSection(sect_index, needed_size, true); + try d_sym.growSection(sect_index, needed_size, true, macho_file); const sect = d_sym.getSection(sect_index); const file_pos = sect.offset + src_fn.off; try pwriteDbgLineNops( @@ -1597,9 +1598,10 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons }, .macho => { - const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; + const macho_file = self.bin_file.cast(File.MachO).?; + const d_sym = macho_file.getDebugSymbols().?; const sect_index = d_sym.debug_info_section_index.?; - try d_sym.growSection(sect_index, needed_size, true); + try d_sym.growSection(sect_index, needed_size, true, macho_file); const sect = d_sym.getSection(sect_index); const file_pos = sect.offset + atom.off; try pwriteDbgInfoNops( @@ -1877,9 +1879,10 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void { try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos); }, .macho => { - const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; + const macho_file = self.bin_file.cast(File.MachO).?; + const d_sym = macho_file.getDebugSymbols().?; const sect_index = d_sym.debug_abbrev_section_index.?; - try d_sym.growSection(sect_index, needed_size, false); + try d_sym.growSection(sect_index, needed_size, false, macho_file); const sect = d_sym.getSection(sect_index); const file_pos = sect.offset + abbrev_offset; try d_sym.file.pwriteAll(&abbrev_buf, file_pos); @@ -2292,9 +2295,10 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos); }, .macho => { - const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; + const macho_file = self.bin_file.cast(File.MachO).?; + const d_sym = macho_file.getDebugSymbols().?; const sect_index = d_sym.debug_aranges_section_index.?; - try d_sym.growSection(sect_index, needed_size, false); + try d_sym.growSection(sect_index, needed_size, false, macho_file); const sect = d_sym.getSection(sect_index); const file_pos = sect.offset; try d_sym.file.pwriteAll(di_buf.items, file_pos); @@ -2432,10 +2436,11 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { try elf_file.base.file.?.pwriteAll(buffer, file_pos + delta); }, .macho => { - const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; + const macho_file = self.bin_file.cast(File.MachO).?; + const d_sym = macho_file.getDebugSymbols().?; const sect_index = d_sym.debug_line_section_index.?; const needed_size: u32 = @intCast(d_sym.getSection(sect_index).size + delta); - try d_sym.growSection(sect_index, needed_size, true); + try d_sym.growSection(sect_index, needed_size, true, macho_file); const file_pos = d_sym.getSection(sect_index).offset + first_fn.off; const amt = try d_sym.file.preadAll(buffer, file_pos); @@ -2653,8 +2658,9 @@ fn addDIFile(self: *Dwarf, mod: *Module, decl_index: InternPool.DeclIndex) !u28 elf_file.markDirty(elf_file.debug_line_section_index.?); }, .macho => { - const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; - d_sym.markDirty(d_sym.debug_line_section_index.?); + const macho_file = self.bin_file.cast(File.MachO).?; + const d_sym = macho_file.getDebugSymbols().?; + d_sym.markDirty(d_sym.debug_line_section_index.?, macho_file); }, .wasm => {}, else => unreachable, diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 84de97f4e9..00b456eb12 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -255,43 +255,35 @@ pub fn createEmpty( )}), } }); self.zig_object = index; - try self.getZigObject().?.init(self); + const zo = self.getZigObject().?; + try zo.init(self); + try self.initMetadata(.{ .symbol_count_hint = options.symbol_count_hint, .program_code_size_hint = options.program_code_size_hint, }); - switch (comp.config.debug_format) { - .strip => {}, - .dwarf => if (!self.base.isRelocatable()) { - // Create dSYM bundle. - log.debug("creating {s}.dSYM bundle", .{emit.sub_path}); + if (zo.dwarf != null and !self.base.isRelocatable()) { + // Create dSYM bundle. + log.debug("creating {s}.dSYM bundle", .{emit.sub_path}); - const sep = fs.path.sep_str; - const d_sym_path = try std.fmt.allocPrint( - arena, - "{s}.dSYM" ++ sep ++ "Contents" ++ sep ++ "Resources" ++ sep ++ "DWARF", - .{emit.sub_path}, - ); + const sep = fs.path.sep_str; + const d_sym_path = try std.fmt.allocPrint( + arena, + "{s}.dSYM" ++ sep ++ "Contents" ++ sep ++ "Resources" ++ sep ++ "DWARF", + .{emit.sub_path}, + ); - var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{}); - defer d_sym_bundle.close(); + var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{}); + defer d_sym_bundle.close(); - const d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{ - .truncate = false, - .read = true, - }); + const d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{ + .truncate = false, + .read = true, + }); - self.d_sym = .{ - .allocator = gpa, - .dwarf = link.File.Dwarf.init(&self.base, .dwarf32), - .file = d_sym_file, - }; - try self.d_sym.?.initMetadata(self); - } else { - @panic("TODO: implement generating and emitting __DWARF in .o file"); - }, - .code_view => unreachable, + self.d_sym = .{ .allocator = gpa, .file = d_sym_file }; + try self.d_sym.?.initMetadata(self); } } } @@ -3152,7 +3144,7 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex) pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: InternPool.DeclIndex) !void { if (self.llvm_object) |_| return; - return self.getZigObject().?.updateDeclLineNumber(self, module, decl_index); + return self.getZigObject().?.updateDeclLineNumber(module, decl_index); } pub fn updateExports( diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 10f6717118..959a88b4da 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -1,5 +1,4 @@ allocator: Allocator, -dwarf: Dwarf, file: fs.File, symtab_cmd: macho.symtab_command = .{}, @@ -17,12 +16,6 @@ debug_str_section_index: ?u8 = null, debug_aranges_section_index: ?u8 = null, debug_line_section_index: ?u8 = null, -debug_string_table_dirty: bool = false, -debug_abbrev_section_dirty: bool = false, -debug_aranges_section_dirty: bool = false, -debug_info_header_dirty: bool = false, -debug_line_header_dirty: bool = false, - relocs: std.ArrayListUnmanaged(Reloc) = .{}, /// Output synthetic sections @@ -44,7 +37,7 @@ pub const Reloc = struct { pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void { try self.strtab.append(self.allocator, 0); - if (self.dwarf_segment_cmd_index == null) { + { self.dwarf_segment_cmd_index = @as(u8, @intCast(self.segments.items.len)); const page_size = macho_file.getPageSize(); @@ -63,46 +56,19 @@ pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void { }); } - if (self.debug_str_section_index == null) { - assert(self.dwarf.strtab.buffer.items.len == 0); - try self.dwarf.strtab.buffer.append(self.allocator, 0); - self.debug_str_section_index = try self.allocateSection( - "__debug_str", - @as(u32, @intCast(self.dwarf.strtab.buffer.items.len)), - 0, - ); - self.debug_string_table_dirty = true; - } + self.debug_str_section_index = try self.allocateSection("__debug_str", 200, 0); + self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0); + self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0); + self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4); + self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0); - if (self.debug_info_section_index == null) { - self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0); - self.debug_info_header_dirty = true; - } - - if (self.debug_abbrev_section_index == null) { - self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0); - self.debug_abbrev_section_dirty = true; - } - - if (self.debug_aranges_section_index == null) { - self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4); - self.debug_aranges_section_dirty = true; - } - - if (self.debug_line_section_index == null) { - self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0); - self.debug_line_header_dirty = true; - } - - if (self.linkedit_segment_cmd_index == null) { - self.linkedit_segment_cmd_index = @as(u8, @intCast(self.segments.items.len)); - try self.segments.append(self.allocator, .{ - .segname = makeStaticString("__LINKEDIT"), - .maxprot = macho.PROT.READ, - .initprot = macho.PROT.READ, - .cmdsize = @sizeOf(macho.segment_command_64), - }); - } + self.linkedit_segment_cmd_index = @as(u8, @intCast(self.segments.items.len)); + try self.segments.append(self.allocator, .{ + .segname = makeStaticString("__LINKEDIT"), + .maxprot = macho.PROT.READ, + .initprot = macho.PROT.READ, + .cmdsize = @sizeOf(macho.segment_command_64), + }); } fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u8 { @@ -133,7 +99,13 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme return index; } -pub fn growSection(self: *DebugSymbols, sect_index: u8, needed_size: u32, requires_file_copy: bool) !void { +pub fn growSection( + self: *DebugSymbols, + sect_index: u8, + needed_size: u32, + requires_file_copy: bool, + macho_file: *MachO, +) !void { const sect = self.getSectionPtr(sect_index); if (needed_size > self.allocatedSize(sect.offset)) { @@ -162,20 +134,22 @@ pub fn growSection(self: *DebugSymbols, sect_index: u8, needed_size: u32, requir } sect.size = needed_size; - self.markDirty(sect_index); + self.markDirty(sect_index, macho_file); } -pub fn markDirty(self: *DebugSymbols, sect_index: u8) void { - if (self.debug_info_section_index.? == sect_index) { - self.debug_info_header_dirty = true; - } else if (self.debug_line_section_index.? == sect_index) { - self.debug_line_header_dirty = true; - } else if (self.debug_abbrev_section_index.? == sect_index) { - self.debug_abbrev_section_dirty = true; - } else if (self.debug_str_section_index.? == sect_index) { - self.debug_string_table_dirty = true; - } else if (self.debug_aranges_section_index.? == sect_index) { - self.debug_aranges_section_dirty = true; +pub fn markDirty(self: *DebugSymbols, sect_index: u8, macho_file: *MachO) void { + if (macho_file.getZigObject()) |zo| { + if (self.debug_info_section_index.? == sect_index) { + zo.debug_info_header_dirty = true; + } else if (self.debug_line_section_index.? == sect_index) { + zo.debug_line_header_dirty = true; + } else if (self.debug_abbrev_section_index.? == sect_index) { + zo.debug_abbrev_dirty = true; + } else if (self.debug_str_section_index.? == sect_index) { + zo.debug_strtab_dirty = true; + } else if (self.debug_aranges_section_index.? == sect_index) { + zo.debug_aranges_dirty = true; + } } } @@ -201,13 +175,6 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 } pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { - const comp = macho_file.base.comp; - // TODO This linker code currently assumes there is only 1 compilation unit - // and it corresponds to the Zig source code. - const zcu = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented; - - try self.dwarf.flushModule(zcu); - for (self.relocs.items) |*reloc| { const sym = macho_file.getSymbol(reloc.target); const sym_name = sym.getName(macho_file); @@ -226,54 +193,12 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { try self.file.pwriteAll(mem.asBytes(&addr), file_offset); } - if (self.debug_abbrev_section_dirty) { - try self.dwarf.writeDbgAbbrev(); - self.debug_abbrev_section_dirty = false; - } - - if (self.debug_info_header_dirty) { - // Currently only one compilation unit is supported, so the address range is simply - // identical to the main program header virtual address and memory size. - const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?]; - const low_pc = text_section.addr; - const high_pc = text_section.addr + text_section.size; - try self.dwarf.writeDbgInfoHeader(zcu, low_pc, high_pc); - self.debug_info_header_dirty = false; - } - - if (self.debug_aranges_section_dirty) { - // Currently only one compilation unit is supported, so the address range is simply - // identical to the main program header virtual address and memory size. - const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?]; - try self.dwarf.writeDbgAranges(text_section.addr, text_section.size); - self.debug_aranges_section_dirty = false; - } - - if (self.debug_line_header_dirty) { - try self.dwarf.writeDbgLineHeader(); - self.debug_line_header_dirty = false; - } - - { - const sect_index = self.debug_str_section_index.?; - if (self.debug_string_table_dirty or self.dwarf.strtab.buffer.items.len != self.getSection(sect_index).size) { - const needed_size = @as(u32, @intCast(self.dwarf.strtab.buffer.items.len)); - try self.growSection(sect_index, needed_size, false); - try self.file.pwriteAll(self.dwarf.strtab.buffer.items, self.getSection(sect_index).offset); - self.debug_string_table_dirty = false; - } - } - self.finalizeDwarfSegment(macho_file); try self.writeLinkeditSegmentData(macho_file); // Write load commands const ncmds, const sizeofcmds = try self.writeLoadCommands(macho_file); try self.writeHeader(macho_file, ncmds, sizeofcmds); - - assert(!self.debug_abbrev_section_dirty); - assert(!self.debug_aranges_section_dirty); - assert(!self.debug_string_table_dirty); } pub fn deinit(self: *DebugSymbols) void { @@ -281,7 +206,6 @@ pub fn deinit(self: *DebugSymbols) void { self.file.close(); self.segments.deinit(gpa); self.sections.deinit(gpa); - self.dwarf.deinit(); self.relocs.deinit(gpa); self.symtab.deinit(gpa); self.strtab.deinit(gpa); @@ -534,7 +458,6 @@ const padToIdeal = MachO.padToIdeal; const trace = @import("../../tracy.zig").trace; const Allocator = mem.Allocator; -const Dwarf = @import("../Dwarf.zig"); const MachO = @import("../MachO.zig"); const StringTable = @import("../StringTable.zig"); const Type = @import("../../type.zig").Type; diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index ecd2470733..abaa4fe6f7 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -46,16 +46,33 @@ tlv_initializers: TlvInitializerTable = .{}, /// A table of relocations. relocs: RelocationTable = .{}, +dwarf: ?Dwarf = null, + dynamic_relocs: MachO.DynamicRelocs = .{}, output_symtab_ctx: MachO.SymtabCtx = .{}, output_ar_state: Archive.ArState = .{}, +debug_strtab_dirty: bool = true, +debug_abbrev_dirty: bool = true, +debug_aranges_dirty: bool = true, +debug_info_header_dirty: bool = true, +debug_line_header_dirty: bool = true, + pub fn init(self: *ZigObject, macho_file: *MachO) !void { const comp = macho_file.base.comp; const gpa = comp.gpa; try self.atoms.append(gpa, 0); // null input section try self.strtab.buffer.append(gpa, 0); + + switch (comp.config.debug_format) { + .strip => {}, + .dwarf => |v| { + assert(v == .@"32"); + self.dwarf = Dwarf.init(&macho_file.base, .dwarf32); + }, + .code_view => unreachable, + } } pub fn deinit(self: *ZigObject, allocator: Allocator) void { @@ -101,6 +118,10 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { tlv_init.deinit(allocator); } self.tlv_initializers.deinit(allocator); + + if (self.dwarf) |*dw| { + dw.deinit(); + } } fn addNlist(self: *ZigObject, allocator: Allocator) !Symbol.Index { @@ -407,6 +428,60 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO) !void { if (metadata.text_state != .unused) metadata.text_state = .flushed; if (metadata.const_state != .unused) metadata.const_state = .flushed; } + + if (self.dwarf) |*dw| { + const zcu = macho_file.base.comp.module.?; + try dw.flushModule(zcu); + + if (self.debug_abbrev_dirty) { + try dw.writeDbgAbbrev(); + self.debug_abbrev_dirty = false; + } + + if (self.debug_info_header_dirty) { + // Currently only one compilation unit is supported, so the address range is simply + // identical to the main program header virtual address and memory size. + const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?]; + const low_pc = text_section.addr; + const high_pc = text_section.addr + text_section.size; + try dw.writeDbgInfoHeader(zcu, low_pc, high_pc); + self.debug_info_header_dirty = false; + } + + if (self.debug_aranges_dirty) { + // Currently only one compilation unit is supported, so the address range is simply + // identical to the main program header virtual address and memory size. + const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?]; + try dw.writeDbgAranges(text_section.addr, text_section.size); + self.debug_aranges_dirty = false; + } + + if (self.debug_line_header_dirty) { + try dw.writeDbgLineHeader(); + self.debug_line_header_dirty = false; + } + + if (!macho_file.base.isRelocatable()) { + const d_sym = macho_file.getDebugSymbols().?; + const sect_index = d_sym.debug_str_section_index.?; + if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != d_sym.getSection(sect_index).size) { + const needed_size = @as(u32, @intCast(dw.strtab.buffer.items.len)); + try d_sym.growSection(sect_index, needed_size, false, macho_file); + try d_sym.file.pwriteAll(dw.strtab.buffer.items, d_sym.getSection(sect_index).offset); + self.debug_strtab_dirty = false; + } + } else { + // TODO: relocatable + } + } + + // The point of flushModule() is to commit changes, so in theory, nothing should + // be dirty after this. However, it is possible for some things to remain + // dirty because they fail to be written in the event of compile errors, + // such as debug_line_header_dirty and debug_info_header_dirty. + assert(!self.debug_abbrev_dirty); + assert(!self.debug_aranges_dirty); + assert(!self.debug_strtab_dirty); } pub fn getDeclVAddr( @@ -572,7 +647,7 @@ pub fn updateFunc( var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); - var decl_state: ?Dwarf.DeclState = if (macho_file.getDebugSymbols()) |d_sym| try d_sym.dwarf.initDeclState(mod, decl_index) else null; + var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null; defer if (decl_state) |*ds| ds.deinit(); const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none; @@ -600,7 +675,7 @@ pub fn updateFunc( if (decl_state) |*ds| { const sym = macho_file.getSymbol(sym_index); - try macho_file.getDebugSymbols().?.dwarf.commitDeclState( + try self.dwarf.?.commitDeclState( mod, decl_index, sym.getAddress(.{}, macho_file), @@ -647,7 +722,7 @@ pub fn updateDecl( var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); - var decl_state: ?Dwarf.DeclState = if (macho_file.getDebugSymbols()) |d_sym| try d_sym.dwarf.initDeclState(mod, decl_index) else null; + var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null; defer if (decl_state) |*ds| ds.deinit(); const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; @@ -681,7 +756,7 @@ pub fn updateDecl( if (decl_state) |*ds| { const sym = macho_file.getSymbol(sym_index); - try macho_file.getDebugSymbols().?.dwarf.commitDeclState( + try self.dwarf.?.commitDeclState( mod, decl_index, sym.getAddress(.{}, macho_file), @@ -1257,15 +1332,9 @@ fn updateLazySymbol( } /// Must be called only after a successful call to `updateDecl`. -pub fn updateDeclLineNumber( - self: *ZigObject, - macho_file: *MachO, - mod: *Module, - decl_index: InternPool.DeclIndex, -) !void { - _ = self; - if (macho_file.getDebugSymbols()) |d_sym| { - try d_sym.dwarf.updateDeclLineNumber(mod, decl_index); +pub fn updateDeclLineNumber(self: *ZigObject, mod: *Module, decl_index: InternPool.DeclIndex) !void { + if (self.dwarf) |*dw| { + try dw.updateDeclLineNumber(mod, decl_index); } }