Skip to content

Commit

Permalink
Merge pull request #72 from kubkon/unwind-fixes
Browse files Browse the repository at this point in the history
macho: unwind info fixes for objects without MH_SUBSECTIONS_VIA_SYMBOLS
  • Loading branch information
kubkon authored Aug 4, 2023
2 parents a3f55c2 + 2e9a9b9 commit 2804038
Show file tree
Hide file tree
Showing 9 changed files with 662 additions and 443 deletions.
36 changes: 36 additions & 0 deletions src/MachO.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2163,6 +2163,42 @@ fn calcSectionSizes(self: *MachO) !void {
try thunks.createThunks(self, @as(u8, @intCast(sect_id)));
}
}

// Update offsets of all symbols contained within each Atom.
// We need to do this since our unwind info synthesiser relies on
// traversing the symbols when synthesising unwind info and DWARF CFI records.
for (slice.items(.first_atom_index)) |first_atom_index| {
if (first_atom_index == 0) continue;
var atom_index = first_atom_index;

while (true) {
const atom = self.getAtom(atom_index);
const sym = self.getSymbol(atom.getSymbolWithLoc());

if (atom.getFile() != null) {
// Update each symbol contained within the atom
var it = Atom.getInnerSymbolsIterator(self, atom_index);
while (it.next()) |sym_loc| {
const inner_sym = self.getSymbolPtr(sym_loc);
inner_sym.n_value = sym.n_value + Atom.calcInnerSymbolOffset(
self,
atom_index,
sym_loc.sym_index,
);
}

// If there is a section alias, update it now too
if (Atom.getSectionAlias(self, atom_index)) |sym_loc| {
const alias = self.getSymbolPtr(sym_loc);
alias.n_value = sym.n_value;
}
}

if (atom.next_index) |next_index| {
atom_index = next_index;
} else break;
}
}
}

fn allocateSegments(self: *MachO) !void {
Expand Down
18 changes: 7 additions & 11 deletions src/MachO/Atom.zig
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ pub inline fn getSymbolWithLoc(self: Atom) SymbolWithLoc {

const InnerSymIterator = struct {
sym_index: u32,
count: u32,
nsyms: u32,
file: u32,
pos: u32 = 0,

pub fn next(it: *@This()) ?SymbolWithLoc {
if (it.count == 0) return null;
const res = SymbolWithLoc{ .sym_index = it.sym_index, .file = it.file };
it.sym_index += 1;
it.count -= 1;
if (it.pos == it.nsyms) return null;
const res = SymbolWithLoc{ .sym_index = it.sym_index + it.pos, .file = it.file };
it.pos += 1;
return res;
}
};
Expand All @@ -96,7 +96,7 @@ pub fn getInnerSymbolsIterator(macho_file: *MachO, atom_index: AtomIndex) InnerS
assert(atom.getFile() != null);
return .{
.sym_index = atom.inner_sym_index,
.count = atom.inner_nsyms_trailing,
.nsyms = atom.inner_nsyms_trailing,
.file = atom.file,
};
}
Expand Down Expand Up @@ -222,11 +222,7 @@ pub fn parseRelocTarget(macho_file: *MachO, ctx: struct {

// Find containing atom
log.debug(" | locating symbol by address @{x} in section {d}", .{ address_in_section, sect_id });
const candidate = object.getSymbolByAddress(address_in_section, sect_id);
// Make sure we are not dealing with a local alias.
const atom_index = object.getAtomIndexForSymbol(candidate) orelse break :sym_index candidate;
const atom = macho_file.getAtom(atom_index);
break :sym_index atom.sym_index;
break :sym_index object.getSymbolByAddress(address_in_section, sect_id);
} else object.reverse_symtab_lookup[ctx.rel.r_symbolnum];

const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = ctx.object_id + 1 };
Expand Down
42 changes: 23 additions & 19 deletions src/MachO/Object.zig
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ exec_atoms: std.ArrayListUnmanaged(AtomIndex) = .{},

eh_frame_sect_id: ?u8 = null,
eh_frame_relocs_lookup: std.AutoArrayHashMapUnmanaged(u32, Record) = .{},
eh_frame_records_lookup: std.AutoArrayHashMapUnmanaged(AtomIndex, u32) = .{},
eh_frame_records_lookup: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{},

unwind_info_sect_id: ?u8 = null,
unwind_relocs_lookup: []Record = undefined,
unwind_records_lookup: std.AutoHashMapUnmanaged(AtomIndex, u32) = .{},
unwind_records_lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},

const Entry = struct {
start: u32 = 0,
Expand Down Expand Up @@ -272,11 +272,11 @@ const SymbolAtIndex = struct {
const sym = self.getSymbol(ctx);
if (!sym.ext()) {
const sym_name = self.getSymbolName(ctx);
if (mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L")) return 0;
return 1;
if (mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L")) return 3;
return 2;
}
if (sym.weakDef() or sym.pext()) return 2;
return 3;
if (sym.weakDef() or sym.pext()) return 1;
return 0;
}

/// Performs lexicographic-like check.
Expand Down Expand Up @@ -421,8 +421,8 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
macho_file,
object_id,
sym_index,
0,
0,
sym_index,
1,
sect.size,
sect.@"align",
out_sect_id,
Expand Down Expand Up @@ -500,8 +500,8 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
macho_file,
object_id,
sym_index,
0,
0,
sym_index,
1,
atom_size,
sect.@"align",
out_sect_id,
Expand All @@ -519,7 +519,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
const atom_loc = filterSymbolsByAddress(symtab[next_sym_index..], addr, addr + 1);
assert(atom_loc.len > 0);
const atom_sym_index = atom_loc.index + next_sym_index;
const nsyms_trailing = atom_loc.len - 1;
const nsyms_trailing = atom_loc.len;
next_sym_index += atom_loc.len;

const atom_size = if (next_sym_index < sect_start_index + sect_loc.len)
Expand All @@ -536,7 +536,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
macho_file,
object_id,
atom_sym_index,
atom_sym_index + 1,
atom_sym_index,
nsyms_trailing,
atom_size,
atom_align,
Expand Down Expand Up @@ -770,8 +770,7 @@ fn parseEhFrameSection(self: *Object, macho_file: *MachO, object_id: u32) !void
if (target.getFile() != object_id) {
self.eh_frame_relocs_lookup.getPtr(offset).?.dead = true;
} else {
const atom_index = self.getAtomIndexForSymbol(target.sym_index).?;
self.eh_frame_records_lookup.putAssumeCapacityNoClobber(atom_index, offset);
self.eh_frame_records_lookup.putAssumeCapacityNoClobber(target, offset);
}
}
}
Expand Down Expand Up @@ -800,10 +799,10 @@ fn parseUnwindInfo(self: *Object, macho_file: *MachO, object_id: u32) !void {
_ = try macho_file.initSection("__TEXT", "__unwind_info", .{});
}

try self.unwind_records_lookup.ensureTotalCapacity(gpa, @as(u32, @intCast(self.exec_atoms.items.len)));

const unwind_records = self.getUnwindRecords();

try self.unwind_records_lookup.ensureTotalCapacity(gpa, @as(u32, @intCast(unwind_records.len)));

const needs_eh_frame = for (unwind_records) |record| {
if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) break true;
} else false;
Expand Down Expand Up @@ -842,8 +841,7 @@ fn parseUnwindInfo(self: *Object, macho_file: *MachO, object_id: u32) !void {
if (target.getFile() != object_id) {
self.unwind_relocs_lookup[record_id].dead = true;
} else {
const atom_index = self.getAtomIndexForSymbol(target.sym_index).?;
self.unwind_records_lookup.putAssumeCapacityNoClobber(atom_index, @as(u32, @intCast(record_id)));
self.unwind_records_lookup.putAssumeCapacityNoClobber(target, @as(u32, @intCast(record_id)));
}
}
}
Expand Down Expand Up @@ -1010,7 +1008,13 @@ pub fn getSymbolByAddress(self: Object, addr: u64, sect_hint: ?u8) u32 {
Predicate{ .addr = @as(i64, @intCast(addr)) },
);
if (target_sym_index > 0) {
return @as(u32, @intCast(lookup.start + target_sym_index - 1));
// Hone in on the most senior alias of the target symbol.
// See SymbolAtIndex.lessThan for more context.
var start = target_sym_index - 1;
while (start > 0 and
self.source_address_lookup[lookup.start..][start - 1] == addr) : (start -= 1)
{}
return @as(u32, @intCast(lookup.start + start));
}
}
return self.getSectionAliasSymbolIndex(sect_id);
Expand Down
Loading

0 comments on commit 2804038

Please sign in to comment.