Commit 37033a96ac
Changed files (4)
src
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;
- }
-
- 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.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);
+
+ 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;
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);
}
}
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,
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});
-
- 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},
- );
+ if (zo.dwarf != null and !self.base.isRelocatable()) {
+ // Create dSYM bundle.
+ log.debug("creating {s}.dSYM bundle", .{emit.sub_path});
- var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{});
- defer d_sym_bundle.close();
+ 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 d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{
- .truncate = false,
- .read = true,
- });
+ var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{});
+ defer d_sym_bundle.close();
- 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,
+ const d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{
+ .truncate = false,
+ .read = true,
+ });
+
+ 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(