aboutsummaryrefslogtreecommitdiff
path: root/src/link/MachO/Object.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/link/MachO/Object.zig')
-rw-r--r--src/link/MachO/Object.zig137
1 files changed, 70 insertions, 67 deletions
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index b53a31af56..49eb34c522 100644
--- a/src/link/MachO/Object.zig
+++ b/src/link/MachO/Object.zig
@@ -27,7 +27,6 @@ header: ?macho.mach_header_64 = null,
file: ?fs.File = null,
file_offset: ?u32 = null,
name: ?[]const u8 = null,
-mtime: ?u64 = null,
load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
@@ -51,9 +50,17 @@ symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
strtab: std.ArrayListUnmanaged(u8) = .{},
data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
+// Debug info
+debug_info: ?DebugInfo = null,
+tu_name: ?[]const u8 = null,
+tu_comp_dir: ?[]const u8 = null,
+mtime: ?u64 = null,
+
symbols: std.ArrayListUnmanaged(*Symbol) = .{},
sections_as_symbols: std.AutoHashMapUnmanaged(u8, *Symbol) = .{},
+text_blocks: std.ArrayListUnmanaged(*TextBlock) = .{},
+
const DebugInfo = struct {
inner: dwarf.DwarfInfo,
debug_info: []u8,
@@ -160,6 +167,19 @@ pub fn deinit(self: *Object) void {
self.strtab.deinit(self.allocator);
self.symbols.deinit(self.allocator);
self.sections_as_symbols.deinit(self.allocator);
+ self.text_blocks.deinit(self.allocator);
+
+ if (self.debug_info) |*db| {
+ db.deinit(self.allocator);
+ }
+
+ if (self.tu_name) |n| {
+ self.allocator.free(n);
+ }
+
+ if (self.tu_comp_dir) |n| {
+ self.allocator.free(n);
+ }
if (self.name) |n| {
self.allocator.free(n);
@@ -203,6 +223,7 @@ pub fn parse(self: *Object) !void {
try self.readLoadCommands(reader);
try self.parseSymtab();
try self.parseDataInCode();
+ try self.parseDebugInfo();
}
pub fn readLoadCommands(self: *Object, reader: anytype) !void {
@@ -431,11 +452,27 @@ const TextBlockParser = struct {
else
max_align;
+ const stab: ?TextBlock.Stab = if (self.object.debug_info) |di| blk: {
+ // TODO there has to be a better to handle this.
+ for (di.inner.func_list.items) |func| {
+ if (func.pc_range) |range| {
+ if (senior_nlist.nlist.n_value >= range.start and senior_nlist.nlist.n_value < range.end) {
+ break :blk TextBlock.Stab{
+ .function = range.end - range.start,
+ };
+ }
+ }
+ }
+ if (self.zld.globals.contains(senior_sym.name)) break :blk .global;
+ break :blk .static;
+ } else null;
+
const block = try self.allocator.create(TextBlock);
errdefer self.allocator.destroy(block);
block.* = TextBlock.init(self.allocator);
block.local_sym_index = senior_nlist.index;
+ block.stab = stab;
block.code = try self.allocator.dupe(u8, code);
block.size = size;
block.alignment = actual_align;
@@ -531,9 +568,11 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
// Is there any padding between symbols within the section?
const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
+ // TODO is it perhaps worth skip parsing subsections in Debug mode and not worry about
+ // duplicates at all? Need some benchmarks!
// const is_splittable = false;
- const has_dices: bool = blk: {
+ zld.has_dices = blk: {
if (self.text_section_index) |index| {
if (index != id) break :blk false;
if (self.data_in_code_entries.items.len == 0) break :blk false;
@@ -541,7 +580,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
}
break :blk false;
};
- zld.has_dices = has_dices;
+ zld.has_stabs = zld.has_stabs or self.debug_info != null;
next: {
if (is_splittable) blocks: {
@@ -625,6 +664,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
} else {
try zld.blocks.putNoClobber(zld.allocator, match, block);
}
+
+ try self.text_blocks.append(self.allocator, block);
}
var parser = TextBlockParser{
@@ -681,6 +722,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
} else {
try zld.blocks.putNoClobber(zld.allocator, match, block);
}
+
+ try self.text_blocks.append(self.allocator, block);
}
break :next;
@@ -758,9 +801,25 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
reg.segment_id = match.seg;
reg.section_id = match.sect;
+ const stab: ?TextBlock.Stab = if (self.debug_info) |di| blk: {
+ // TODO there has to be a better to handle this.
+ for (di.inner.func_list.items) |func| {
+ if (func.pc_range) |range| {
+ if (reg.address >= range.start and reg.address < range.end) {
+ break :blk TextBlock.Stab{
+ .function = range.end - range.start,
+ };
+ }
+ }
+ }
+ if (zld.globals.contains(sym.name)) break :blk .global;
+ break :blk .static;
+ } else null;
+
contained.appendAssumeCapacity(.{
.local_sym_index = reg.local_sym_index,
.offset = nlist_with_index.nlist.n_value - sect.addr,
+ .stab = stab,
});
}
@@ -785,6 +844,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
} else {
try zld.blocks.putNoClobber(zld.allocator, match, block);
}
+
+ try self.text_blocks.append(self.allocator, block);
}
}
}
@@ -861,13 +922,12 @@ fn parseSymtab(self: *Object) !void {
}
pub fn parseDebugInfo(self: *Object) !void {
+ log.debug("parsing debug info in '{s}'", .{self.name.?});
+
var debug_info = blk: {
var di = try DebugInfo.parseFromObject(self.allocator, self);
break :blk di orelse return;
};
- defer debug_info.deinit(self.allocator);
-
- log.debug("parsing debug info in '{s}'", .{self.name.?});
// We assume there is only one CU.
const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) {
@@ -881,6 +941,10 @@ pub fn parseDebugInfo(self: *Object) !void {
const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_name);
const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir);
+ self.debug_info = debug_info;
+ self.tu_name = try self.allocator.dupe(u8, name);
+ self.tu_comp_dir = try self.allocator.dupe(u8, comp_dir);
+
if (self.mtime == null) {
self.mtime = mtime: {
const file = self.file orelse break :mtime 0;
@@ -888,67 +952,6 @@ pub fn parseDebugInfo(self: *Object) !void {
break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));
};
}
-
- try self.stabs.ensureUnusedCapacity(self.allocator, self.symbols.items.len + 4);
-
- // Current dir
- self.stabs.appendAssumeCapacity(try Symbol.Stab.new(self.allocator, comp_dir, .{
- .kind = .so,
- .file = self,
- }));
-
- // Artifact name
- self.stabs.appendAssumeCapacity(try Symbol.Stab.new(self.allocator, name, .{
- .kind = .so,
- .file = self,
- }));
-
- // Path to object file with debug info
- self.stabs.appendAssumeCapacity(try Symbol.Stab.new(self.allocator, self.name.?, .{
- .kind = .oso,
- .file = self,
- }));
-
- for (self.symbols.items) |sym| {
- if (sym.cast(Symbol.Regular)) |reg| {
- const size: u64 = blk: for (debug_info.inner.func_list.items) |func| {
- if (func.pc_range) |range| {
- if (reg.address >= range.start and reg.address < range.end) {
- break :blk range.end - range.start;
- }
- }
- } else 0;
-
- const stab = try Symbol.Stab.new(self.allocator, sym.name, .{
- .kind = kind: {
- if (size > 0) break :kind .function;
- switch (reg.linkage) {
- .translation_unit => break :kind .static,
- else => break :kind .global,
- }
- },
- .size = size,
- .symbol = sym,
- .file = self,
- });
- self.stabs.appendAssumeCapacity(stab);
- } else if (sym.cast(Symbol.Tentative)) |_| {
- const stab = try Symbol.Stab.new(self.allocator, sym.name, .{
- .kind = .global,
- .size = 0,
- .symbol = sym,
- .file = self,
- });
- self.stabs.appendAssumeCapacity(stab);
- }
- }
-
- // Closing delimiter.
- const delim_stab = try Symbol.Stab.new(self.allocator, "", .{
- .kind = .so,
- .file = self,
- });
- self.stabs.appendAssumeCapacity(delim_stab);
}
pub fn parseDataInCode(self: *Object) !void {