macho: parse an input object file!

This commit is contained in:
Jakub Konka 2024-01-10 19:39:40 +01:00
parent 7588eeccea
commit 0c171afab0
8 changed files with 799 additions and 433 deletions

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,7 @@ unwind_records: Loc = .{},
flags: Flags = .{},
pub fn getName(self: Atom, macho_file: *MachO) [:0]const u8 {
return macho_file.string_intern.getAssumeExists(self.name);
return macho_file.strings.getAssumeExists(self.name);
}
pub fn getFile(self: Atom, macho_file: *MachO) File {

View File

@ -431,7 +431,7 @@ pub fn initSymbols(self: *Dylib, macho_file: *MachO) !void {
for (self.exports.items(.name)) |noff| {
const name = self.getString(noff);
const off = try macho_file.string_intern.insert(gpa, name);
const off = try macho_file.strings.insert(gpa, name);
const gop = try macho_file.getOrCreateGlobal(off);
self.symbols.addOneAssumeCapacity().* = gop.index;
}

View File

@ -31,6 +31,14 @@ num_weak_bind_relocs: u32 = 0,
output_symtab_ctx: MachO.SymtabCtx = .{},
pub fn isObject(path: []const u8) !bool {
const file = try std.fs.cwd().openFile(path, .{});
defer file.close();
const reader = file.reader();
const header = reader.readStruct(macho.mach_header_64) catch return false;
return header.filetype == macho.MH_OBJECT;
}
pub fn deinit(self: *Object, allocator: Allocator) void {
for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| {
relocs.deinit(allocator);
@ -55,12 +63,25 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
var stream = std.io.fixedBufferStream(self.data);
const reader = stream.reader();
self.header = try reader.readStruct(macho.mach_header_64);
const this_cpu_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
macho.CPU_TYPE_ARM64 => .aarch64,
macho.CPU_TYPE_X86_64 => .x86_64,
else => |x| {
try macho_file.reportParseError2(self.index, "unknown cpu architecture: {d}", .{x});
return error.InvalidCpuArch;
},
};
if (macho_file.getTarget().cpu.arch != this_cpu_arch) {
try macho_file.reportParseError2(self.index, "invalid cpu architecture: {s}", .{@tagName(this_cpu_arch)});
return error.InvalidCpuArch;
}
if (self.getLoadCommand(.SEGMENT_64)) |lc| {
const sections = lc.getSections();
try self.sections.ensureUnusedCapacity(gpa, sections.len);
@ -146,6 +167,20 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
}
self.initPlatform();
if (self.platform) |platform| {
if (!macho_file.platform.eqlTarget(platform)) {
try macho_file.reportParseError2(self.index, "invalid platform: {}", .{
platform.fmtTarget(macho_file.getTarget().cpu.arch),
});
return error.InvalidTarget;
}
if (macho_file.platform.version.order(platform.version) != .lt) {
try macho_file.reportParseError2(self.index, "object file built for newer platform: {}", .{platform});
return error.InvalidTarget;
}
}
try self.initDwarfInfo(macho_file);
for (self.atoms.items) |atom_index| {
@ -175,7 +210,7 @@ inline fn isLiteral(sect: macho.section_64) bool {
fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const slice = self.sections.slice();
for (slice.items(.header), slice.items(.subsections), 0..) |sect, *subsections, n_sect| {
if (isLiteral(sect)) continue;
@ -243,7 +278,7 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {
fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const slice = self.sections.slice();
try self.atoms.ensureUnusedCapacity(gpa, self.sections.items(.header).len);
@ -299,12 +334,12 @@ const AddAtomArgs = struct {
};
fn addAtom(self: *Object, args: AddAtomArgs, macho_file: *MachO) !Atom.Index {
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const atom_index = try macho_file.addAtom();
const atom = macho_file.getAtom(atom_index).?;
atom.file = self.index;
atom.atom_index = atom_index;
atom.name = try macho_file.string_intern.insert(gpa, args.name);
atom.name = try macho_file.strings.insert(gpa, args.name);
atom.n_sect = args.n_sect;
atom.size = args.size;
atom.alignment = args.alignment;
@ -319,7 +354,7 @@ fn initLiteralSections(self: *Object, macho_file: *MachO) !void {
// TODO here we should split into equal-sized records, hash the contents, and then
// deduplicate - ICF.
// For now, we simply cover each literal section with one large atom.
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const slice = self.sections.slice();
try self.atoms.ensureUnusedCapacity(gpa, self.sections.items(.header).len);
@ -401,10 +436,10 @@ fn linkNlistToAtom(self: *Object, macho_file: *MachO) !void {
if (self.findAtomInSection(nlist.n_value, nlist.n_sect - 1)) |atom_index| {
atom.* = atom_index;
} else {
macho_file.base.fatal("{}: symbol {s} not attached to any (sub)section", .{
self.fmtPath(), self.getString(nlist.n_strx),
try macho_file.reportParseError2(self.index, "symbol {s} not attached to any (sub)section", .{
self.getString(nlist.n_strx),
});
return error.ParseFailed;
return error.MalformedObject;
}
}
}
@ -413,7 +448,7 @@ fn linkNlistToAtom(self: *Object, macho_file: *MachO) !void {
fn initSymbols(self: *Object, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const slice = self.symtab.slice();
try self.symbols.ensureUnusedCapacity(gpa, slice.items(.nlist).len);
@ -421,7 +456,7 @@ fn initSymbols(self: *Object, macho_file: *MachO) !void {
for (slice.items(.nlist), slice.items(.atom), 0..) |nlist, atom_index, i| {
if (nlist.ext()) {
const name = self.getString(nlist.n_strx);
const off = try macho_file.string_intern.insert(gpa, name);
const off = try macho_file.strings.insert(gpa, name);
const gop = try macho_file.getOrCreateGlobal(off);
self.symbols.addOneAssumeCapacity().* = gop.index;
continue;
@ -433,7 +468,7 @@ fn initSymbols(self: *Object, macho_file: *MachO) !void {
const name = self.getString(nlist.n_strx);
symbol.* = .{
.value = nlist.n_value,
.name = try macho_file.string_intern.insert(gpa, name),
.name = try macho_file.strings.insert(gpa, name),
.nlist_idx = @intCast(i),
.atom = 0,
.file = self.index,
@ -482,7 +517,7 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {
if (start == end) return;
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const syms = self.symtab.items(.nlist);
const sym_lookup = SymbolLookup{ .ctx = self, .entries = nlists };
@ -490,11 +525,10 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {
while (i < end) : (i += 1) {
const open = syms[i];
if (open.n_type != macho.N_SO) {
macho_file.base.fatal("{}: unexpected symbol stab type 0x{x} as the first entry", .{
self.fmtPath(),
try macho_file.reportParseError2(self.index, "unexpected symbol stab type 0x{x} as the first entry", .{
open.n_type,
});
return error.ParseFailed;
return error.MalformedObject;
}
while (i < end and syms[i].n_type == macho.N_SO and syms[i].n_sect != 0) : (i += 1) {}
@ -522,11 +556,10 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {
stab.symbol = sym_lookup.find(nlist.n_value);
},
else => {
macho_file.base.fatal("{}: unhandled symbol stab type 0x{x}", .{
self.fmtPath(),
try macho_file.reportParseError2(self.index, "unhandled symbol stab type 0x{x}", .{
nlist.n_type,
});
return error.ParseFailed;
return error.MalformedObject;
},
}
try sf.stabs.append(gpa, stab);
@ -548,7 +581,7 @@ fn sortAtoms(self: *Object, macho_file: *MachO) !void {
fn initRelocs(self: *Object, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
const cpu_arch = macho_file.options.cpu_arch.?;
const cpu_arch = macho_file.getTarget().cpu.arch;
const slice = self.sections.slice();
for (slice.items(.header), slice.items(.relocs), 0..) |sect, *out, n_sect| {
@ -589,7 +622,7 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void {
fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const nlists = self.symtab.items(.nlist);
const slice = self.sections.slice();
const sect = slice.items(.header)[sect_id];
@ -667,10 +700,10 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
const cie = for (self.cies.items) |*cie| {
if (cie.offset <= rel.offset and rel.offset < cie.offset + cie.getSize()) break cie;
} else {
macho_file.base.fatal("{}: {s},{s}: 0x{x}: bad relocation", .{
self.fmtPath(), sect.segName(), sect.sectName(), rel.offset,
try macho_file.reportParseError2(self.index, "{s},{s}: 0x{x}: bad relocation", .{
sect.segName(), sect.sectName(), rel.offset,
});
return error.ParseFailed;
return error.MalformedObject;
};
cie.personality = .{ .index = @intCast(rel.target), .offset = rel.offset - cie.offset };
},
@ -695,7 +728,7 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
}
};
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const data = self.getSectionData(sect_id);
const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry));
const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs];
@ -722,10 +755,10 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
for (relocs[reloc_start..reloc_idx]) |rel| {
if (rel.type != .unsigned or rel.meta.length != 3) {
macho_file.base.fatal("{}: {s},{s}: 0x{x}: bad relocation", .{
self.fmtPath(), header.segName(), header.sectName(), rel.offset,
try macho_file.reportParseError2(self.index, "{s},{s}: 0x{x}: bad relocation", .{
header.segName(), header.sectName(), rel.offset,
});
return error.ParseFailed;
return error.MalformedObject;
}
assert(rel.type == .unsigned and rel.meta.length == 3); // TODO error
const offset = rel.offset - rec_start;
@ -740,10 +773,10 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
const atom = out.getAtom(macho_file);
out.atom_offset = @intCast(rec.rangeStart - atom.getInputAddress(macho_file));
} else {
macho_file.base.fatal("{}: {s},{s}: 0x{x}: bad relocation", .{
self.fmtPath(), header.segName(), header.sectName(), rel.offset,
try macho_file.reportParseError2(self.index, "{s},{s}: 0x{x}: bad relocation", .{
header.segName(), header.sectName(), rel.offset,
});
return error.ParseFailed;
return error.MalformedObject;
},
},
16 => switch (rel.tag) { // personality function
@ -753,10 +786,10 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
.local => if (sym_lookup.find(rec.personalityFunction)) |sym_index| {
out.personality = sym_index;
} else {
macho_file.base.fatal("{}: {s},{s}: 0x{x}: bad relocation", .{
self.fmtPath(), header.segName(), header.sectName(), rel.offset,
try macho_file.reportParseError2(self.index, "{s},{s}: 0x{x}: bad relocation", .{
header.segName(), header.sectName(), rel.offset,
});
return error.ParseFailed;
return error.MalformedObject;
},
},
24 => switch (rel.tag) { // lsda
@ -769,10 +802,10 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
const atom = out.getLsdaAtom(macho_file).?;
out.lsda_offset = @intCast(rec.lsda - atom.getInputAddress(macho_file));
} else {
macho_file.base.fatal("{}: {s},{s}: 0x{x}: bad relocation", .{
self.fmtPath(), header.segName(), header.sectName(), rel.offset,
try macho_file.reportParseError2(self.index, "{s},{s}: 0x{x}: bad relocation", .{
header.segName(), header.sectName(), rel.offset,
});
return error.ParseFailed;
return error.MalformedObject;
},
},
else => {},
@ -780,7 +813,7 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
}
}
if (!macho_file.options.relocatable) try self.synthesiseNullUnwindRecords(macho_file);
if (!macho_file.base.isObject()) try self.synthesiseNullUnwindRecords(macho_file);
const sortFn = struct {
fn sortFn(ctx: *MachO, lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool {
@ -818,7 +851,7 @@ fn synthesiseNullUnwindRecords(self: *Object, macho_file: *MachO) !void {
const Superposition = struct { atom: Atom.Index, size: u64, cu: ?UnwindInfo.Record.Index = null, fde: ?Fde.Index = null };
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
var superposition = std.AutoArrayHashMap(u64, Superposition).init(gpa);
defer superposition.deinit();
@ -875,7 +908,7 @@ fn synthesiseNullUnwindRecords(self: *Object, macho_file: *MachO) !void {
rec.atom_offset = fde.atom_offset;
rec.fde = fde_index;
rec.file = fde.file;
switch (macho_file.options.cpu_arch.?) {
switch (macho_file.getTarget().cpu.arch) {
.x86_64 => rec.enc.setMode(macho.UNWIND_X86_64_MODE.DWARF),
.aarch64 => rec.enc.setMode(macho.UNWIND_ARM64_MODE.DWARF),
else => unreachable,
@ -907,7 +940,7 @@ fn initPlatform(self: *Object) void {
.VERSION_MIN_IPHONEOS,
.VERSION_MIN_TVOS,
.VERSION_MIN_WATCHOS,
=> break MachO.Options.Platform.fromLoadCommand(cmd),
=> break MachO.Platform.fromLoadCommand(cmd),
else => {},
}
} else null;
@ -921,7 +954,7 @@ fn initDwarfInfo(self: *Object, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
var debug_info_index: ?usize = null;
var debug_abbrev_index: ?usize = null;
@ -942,8 +975,8 @@ fn initDwarfInfo(self: *Object, macho_file: *MachO) !void {
.debug_str = if (debug_str_index) |index| self.getSectionData(@intCast(index)) else "",
};
dwarf_info.init(gpa) catch {
macho_file.base.fatal("{}: invalid __DWARF info found", .{self.fmtPath()});
return error.ParseFailed;
try macho_file.reportParseError2(self.index, "invalid __DWARF info found", .{});
return error.MalformedObject;
};
self.dwarf_info = dwarf_info;
}
@ -1060,7 +1093,7 @@ pub fn scanRelocs(self: Object, macho_file: *MachO) !void {
pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
for (self.symbols.items, 0..) |index, i| {
const sym = macho_file.getSymbol(index);
@ -1079,7 +1112,7 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void {
defer gpa.free(name);
const atom = macho_file.getAtom(atom_index).?;
atom.atom_index = atom_index;
atom.name = try macho_file.string_intern.insert(gpa, name);
atom.name = try macho_file.strings.insert(gpa, name);
atom.file = self.index;
atom.size = nlist.n_value;
atom.alignment = (nlist.n_desc >> 8) & 0x0f;
@ -1130,7 +1163,7 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) !void {
const name = sym.getName(macho_file);
// TODO in -r mode, we actually want to merge symbol names and emit only one
// work it out when emitting relocs
if (name.len > 0 and (name[0] == 'L' or name[0] == 'l') and !macho_file.options.relocatable) continue;
if (name.len > 0 and (name[0] == 'L' or name[0] == 'l') and !macho_file.base.isObject()) continue;
sym.flags.output_symtab = true;
if (sym.isLocal()) {
try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file);
@ -1171,7 +1204,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) void {
const file = sym.getFile(macho_file) orelse continue;
if (file.getIndex() != self.index) continue;
if (!sym.flags.output_symtab) continue;
if (macho_file.options.relocatable) {
if (macho_file.base.isObject()) {
const name = sym.getName(macho_file);
if (name.len > 0 and (name[0] == 'L' or name[0] == 'l')) continue;
}
@ -1329,7 +1362,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) void {
const file = sym.getFile(macho_file) orelse continue;
if (file.getIndex() != self.index) continue;
if (!sym.flags.output_symtab) continue;
if (macho_file.options.relocatable) {
if (macho_file.base.isObject()) {
const name = sym.getName(macho_file);
if (name.len > 0 and (name[0] == 'L' or name[0] == 'l')) continue;
}
@ -1747,7 +1780,7 @@ const x86_64 = struct {
out: *std.ArrayListUnmanaged(Relocation),
macho_file: *MachO,
) !void {
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const relocs = @as(
[*]align(1) const macho.relocation_info,
@ -1783,10 +1816,10 @@ const x86_64 = struct {
else
addend;
const target = self.findAtomInSection(@intCast(taddr), @intCast(nsect)) orelse {
macho_file.base.fatal("{}: {s},{s}: 0x{x}: bad relocation", .{
self.fmtPath(), sect.segName(), sect.sectName(), rel.r_address,
try macho_file.reportParseError2(self.index, "{s},{s}: 0x{x}: bad relocation", .{
sect.segName(), sect.sectName(), rel.r_address,
});
return error.ParseFailed;
return error.MalformedObject;
};
addend = taddr - @as(i64, @intCast(macho_file.getAtom(target).?.getInputAddress(macho_file)));
break :blk target;
@ -1796,34 +1829,38 @@ const x86_64 = struct {
@as(macho.reloc_type_x86_64, @enumFromInt(relocs[i - 1].r_type)) == .X86_64_RELOC_SUBTRACTOR)
blk: {
if (rel_type != .X86_64_RELOC_UNSIGNED) {
macho_file.base.fatal("{}: {s},{s}: 0x{x}: X86_64_RELOC_SUBTRACTOR followed by {s}", .{
self.fmtPath(), sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type),
try macho_file.reportParseError2(self.index, "{s},{s}: 0x{x}: X86_64_RELOC_SUBTRACTOR followed by {s}", .{
sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type),
});
return error.ParseFailed;
return error.MalformedObject;
}
break :blk true;
} else false;
const @"type": Relocation.Type = validateRelocType(rel, rel_type) catch |err| {
switch (err) {
error.Pcrel => macho_file.base.fatal(
"{}: {s},{s}: 0x{x}: PC-relative {s} relocation",
.{ self.fmtPath(), sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type) },
error.Pcrel => try macho_file.reportParseError2(
self.index,
"{s},{s}: 0x{x}: PC-relative {s} relocation",
.{ sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type) },
),
error.NonPcrel => macho_file.base.fatal(
"{}: {s},{s}: 0x{x}: non-PC-relative {s} relocation",
.{ self.fmtPath(), sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type) },
error.NonPcrel => try macho_file.reportParseError2(
self.index,
"{s},{s}: 0x{x}: non-PC-relative {s} relocation",
.{ sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type) },
),
error.InvalidLength => macho_file.base.fatal(
"{}: {s},{s}: 0x{x}: invalid length of {d} in {s} relocation",
.{ self.fmtPath(), sect.segName(), sect.sectName(), rel_offset, @as(u8, 1) << rel.r_length, @tagName(rel_type) },
error.InvalidLength => try macho_file.reportParseError2(
self.index,
"{s},{s}: 0x{x}: invalid length of {d} in {s} relocation",
.{ sect.segName(), sect.sectName(), rel_offset, @as(u8, 1) << rel.r_length, @tagName(rel_type) },
),
error.NonExtern => macho_file.base.fatal(
"{}: {s},{s}: 0x{x}: non-extern target in {s} relocation",
.{ self.fmtPath(), sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type) },
error.NonExtern => try macho_file.reportParseError2(
self.index,
"{s},{s}: 0x{x}: non-extern target in {s} relocation",
.{ sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type) },
),
}
return error.ParseFailed;
return error.MalformedObject;
};
out.appendAssumeCapacity(.{
@ -1899,7 +1936,7 @@ const aarch64 = struct {
out: *std.ArrayListUnmanaged(Relocation),
macho_file: *MachO,
) !void {
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const relocs = @as(
[*]align(1) const macho.relocation_info,
@ -1921,20 +1958,21 @@ const aarch64 = struct {
addend = rel.r_symbolnum;
i += 1;
if (i >= relocs.len) {
macho_file.base.fatal("{}: {s},{s}: 0x{x}: unterminated ARM64_RELOC_ADDEND", .{
self.fmtPath(), sect.segName(), sect.sectName(), rel_offset,
try macho_file.reportParseError2(self.index, "{s},{s}: 0x{x}: unterminated ARM64_RELOC_ADDEND", .{
sect.segName(), sect.sectName(), rel_offset,
});
return error.ParseFailed;
return error.MalformedObject;
}
rel = relocs[i];
switch (@as(macho.reloc_type_arm64, @enumFromInt(rel.r_type))) {
.ARM64_RELOC_PAGE21, .ARM64_RELOC_PAGEOFF12 => {},
else => |x| {
macho_file.base.fatal(
"{}: {s},{s}: 0x{x}: ARM64_RELOC_ADDEND followed by {s}",
.{ self.fmtPath(), sect.segName(), sect.sectName(), rel_offset, @tagName(x) },
try macho_file.reportParseError2(
self.index,
"{s},{s}: 0x{x}: ARM64_RELOC_ADDEND followed by {s}",
.{ sect.segName(), sect.sectName(), rel_offset, @tagName(x) },
);
return error.ParseFailed;
return error.MalformedObject;
},
}
},
@ -1958,10 +1996,10 @@ const aarch64 = struct {
else
addend;
const target = self.findAtomInSection(@intCast(taddr), @intCast(nsect)) orelse {
macho_file.base.fatal("{}: {s},{s}: 0x{x}: bad relocation", .{
self.fmtPath(), sect.segName(), sect.sectName(), rel.r_address,
try macho_file.reportParseError2(self.index, "{s},{s}: 0x{x}: bad relocation", .{
sect.segName(), sect.sectName(), rel.r_address,
});
return error.ParseFailed;
return error.MalformedObject;
};
addend = taddr - @as(i64, @intCast(macho_file.getAtom(target).?.getInputAddress(macho_file)));
break :blk target;
@ -1971,34 +2009,38 @@ const aarch64 = struct {
@as(macho.reloc_type_arm64, @enumFromInt(relocs[i - 1].r_type)) == .ARM64_RELOC_SUBTRACTOR)
blk: {
if (rel_type != .ARM64_RELOC_UNSIGNED) {
macho_file.base.fatal("{}: {s},{s}: 0x{x}: ARM64_RELOC_SUBTRACTOR followed by {s}", .{
self.fmtPath(), sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type),
try macho_file.reportParseError2(self.index, "{s},{s}: 0x{x}: ARM64_RELOC_SUBTRACTOR followed by {s}", .{
sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type),
});
return error.ParseFailed;
return error.MalformedObject;
}
break :blk true;
} else false;
const @"type": Relocation.Type = validateRelocType(rel, rel_type) catch |err| {
switch (err) {
error.Pcrel => macho_file.base.fatal(
"{}: {s},{s}: 0x{x}: PC-relative {s} relocation",
.{ self.fmtPath(), sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type) },
error.Pcrel => try macho_file.reportParseError2(
self.index,
"{s},{s}: 0x{x}: PC-relative {s} relocation",
.{ sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type) },
),
error.NonPcrel => macho_file.base.fatal(
"{}: {s},{s}: 0x{x}: non-PC-relative {s} relocation",
.{ self.fmtPath(), sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type) },
error.NonPcrel => try macho_file.reportParseError2(
self.index,
"{s},{s}: 0x{x}: non-PC-relative {s} relocation",
.{ sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type) },
),
error.InvalidLength => macho_file.base.fatal(
"{}: {s},{s}: 0x{x}: invalid length of {d} in {s} relocation",
.{ self.fmtPath(), sect.segName(), sect.sectName(), rel_offset, @as(u8, 1) << rel.r_length, @tagName(rel_type) },
error.InvalidLength => try macho_file.reportParseError2(
self.index,
"{s},{s}: 0x{x}: invalid length of {d} in {s} relocation",
.{ sect.segName(), sect.sectName(), rel_offset, @as(u8, 1) << rel.r_length, @tagName(rel_type) },
),
error.NonExtern => macho_file.base.fatal(
"{}: {s},{s}: 0x{x}: non-extern target in {s} relocation",
.{ self.fmtPath(), sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type) },
error.NonExtern => try macho_file.reportParseError2(
self.index,
"{s},{s}: 0x{x}: non-extern target in {s} relocation",
.{ sect.segName(), sect.sectName(), rel_offset, @tagName(rel_type) },
),
}
return error.ParseFailed;
return error.MalformedObject;
};
out.appendAssumeCapacity(.{

View File

@ -55,7 +55,7 @@ pub fn weakRef(symbol: Symbol, macho_file: *MachO) bool {
}
pub fn getName(symbol: Symbol, macho_file: *MachO) [:0]const u8 {
return macho_file.string_intern.getAssumeExists(symbol.name);
return macho_file.strings.getAssumeExists(symbol.name);
}
pub fn getAtom(symbol: Symbol, macho_file: *MachO) ?*Atom {

View File

@ -372,7 +372,7 @@ pub const Encoding = extern struct {
pub fn isDwarf(enc: Encoding, macho_file: *MachO) bool {
const mode = enc.getMode();
return switch (macho_file.options.cpu_arch.?) {
return switch (macho_file.getTarget().cpu.arch) {
.aarch64 => @as(macho.UNWIND_ARM64_MODE, @enumFromInt(mode)) == .DWARF,
.x86_64 => @as(macho.UNWIND_X86_64_MODE, @enumFromInt(mode)) == .DWARF,
else => unreachable,

View File

@ -155,10 +155,10 @@ pub const Fde = struct {
const pc_begin = std.mem.readInt(i64, data[8..][0..8], .little);
const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);
fde.atom = object.findAtom(taddr) orelse {
macho_file.base.fatal("{}: {s},{s}: 0x{x}: invalid function reference in FDE", .{
object.fmtPath(), sect.segName(), sect.sectName(), fde.offset + 8,
try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{
sect.segName(), sect.sectName(), fde.offset + 8,
});
return error.ParseFailed;
return error.MalformedObject;
};
const atom = fde.getAtom(macho_file);
fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));
@ -172,11 +172,10 @@ pub const Fde = struct {
if (cie_index) |cie| {
fde.cie = cie;
} else {
macho_file.base.fatal("{}: no matching CIE found for FDE at offset {x}", .{
object.fmtPath(),
try macho_file.reportParseError2(object.index, "no matching CIE found for FDE at offset {x}", .{
fde.offset,
});
return error.ParseFailed;
return error.MalformedObject;
}
const cie = fde.getCie(macho_file);
@ -194,10 +193,10 @@ pub const Fde = struct {
};
const lsda_addr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + fde.lsda_ptr_offset)) + lsda_ptr);
fde.lsda = object.findAtom(lsda_addr) orelse {
macho_file.base.fatal("{}: {s},{s}: 0x{x}: invalid LSDA reference in FDE", .{
object.fmtPath(), sect.segName(), sect.sectName(), fde.offset + fde.lsda_ptr_offset,
try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid LSDA reference in FDE", .{
sect.segName(), sect.sectName(), fde.offset + fde.lsda_ptr_offset,
});
return error.ParseFailed;
return error.MalformedObject;
};
const lsda_atom = fde.getLsdaAtom(macho_file).?;
fde.lsda_offset = @intCast(lsda_addr - lsda_atom.getInputAddress(macho_file));

View File

@ -8,7 +8,7 @@ pub const GotSection = struct {
}
pub fn addSymbol(got: *GotSection, sym_index: Symbol.Index, macho_file: *MachO) !void {
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const index = @as(Index, @intCast(got.symbols.items.len));
const entry = try got.symbols.addOne(gpa);
entry.* = sym_index;
@ -29,7 +29,7 @@ pub const GotSection = struct {
pub fn addDyldRelocs(got: GotSection, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const seg_id = macho_file.sections.items(.segment_id)[macho_file.got_sect_index.?];
const seg = macho_file.segments.items[seg_id];
@ -111,7 +111,7 @@ pub const StubsSection = struct {
}
pub fn addSymbol(stubs: *StubsSection, sym_index: Symbol.Index, macho_file: *MachO) !void {
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const index = @as(Index, @intCast(stubs.symbols.items.len));
const entry = try stubs.symbols.addOne(gpa);
entry.* = sym_index;
@ -133,7 +133,7 @@ pub const StubsSection = struct {
pub fn write(stubs: StubsSection, macho_file: *MachO, writer: anytype) !void {
const tracy = trace(@src());
defer tracy.end();
const cpu_arch = macho_file.options.cpu_arch.?;
const cpu_arch = macho_file.getTarget().cpu.arch;
const laptr_sect = macho_file.sections.items(.header)[macho_file.la_symbol_ptr_sect_index.?];
for (stubs.symbols.items, 0..) |sym_index, idx| {
@ -213,7 +213,7 @@ pub const StubsHelperSection = struct {
const tracy = trace(@src());
defer tracy.end();
_ = stubs_helper;
const cpu_arch = macho_file.options.cpu_arch.?;
const cpu_arch = macho_file.getTarget().cpu.arch;
var s: usize = preambleSize(cpu_arch);
for (macho_file.stubs.symbols.items) |sym_index| {
const sym = macho_file.getSymbol(sym_index);
@ -230,7 +230,7 @@ pub const StubsHelperSection = struct {
try stubs_helper.writePreamble(macho_file, writer);
const cpu_arch = macho_file.options.cpu_arch.?;
const cpu_arch = macho_file.getTarget().cpu.arch;
const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
const preamble_size = preambleSize(cpu_arch);
const entry_size = entrySize(cpu_arch);
@ -272,7 +272,7 @@ pub const StubsHelperSection = struct {
fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {
_ = stubs_helper;
const cpu_arch = macho_file.options.cpu_arch.?;
const cpu_arch = macho_file.getTarget().cpu.arch;
const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
const dyld_private_addr = target: {
const sym = macho_file.getSymbol(macho_file.dyld_private_index.?);
@ -331,7 +331,7 @@ pub const LaSymbolPtrSection = struct {
const tracy = trace(@src());
defer tracy.end();
_ = laptr;
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const sect = macho_file.sections.items(.header)[macho_file.la_symbol_ptr_sect_index.?];
const seg_id = macho_file.sections.items(.segment_id)[macho_file.la_symbol_ptr_sect_index.?];
@ -371,7 +371,7 @@ pub const LaSymbolPtrSection = struct {
const tracy = trace(@src());
defer tracy.end();
_ = laptr;
const cpu_arch = macho_file.options.cpu_arch.?;
const cpu_arch = macho_file.getTarget().cpu.arch;
const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
for (macho_file.stubs.symbols.items, 0..) |sym_index, idx| {
const sym = macho_file.getSymbol(sym_index);
@ -397,7 +397,7 @@ pub const TlvPtrSection = struct {
}
pub fn addSymbol(tlv: *TlvPtrSection, sym_index: Symbol.Index, macho_file: *MachO) !void {
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const index = @as(Index, @intCast(tlv.symbols.items.len));
const entry = try tlv.symbols.addOne(gpa);
entry.* = sym_index;
@ -418,7 +418,7 @@ pub const TlvPtrSection = struct {
pub fn addDyldRelocs(tlv: TlvPtrSection, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const seg_id = macho_file.sections.items(.segment_id)[macho_file.tlv_ptr_sect_index.?];
const seg = macho_file.segments.items[seg_id];
@ -510,7 +510,7 @@ pub const ObjcStubsSection = struct {
}
pub fn addSymbol(objc: *ObjcStubsSection, sym_index: Symbol.Index, macho_file: *MachO) !void {
const gpa = macho_file.base.allocator;
const gpa = macho_file.base.comp.gpa;
const index = @as(Index, @intCast(objc.symbols.items.len));
const entry = try objc.symbols.addOne(gpa);
entry.* = sym_index;
@ -521,11 +521,11 @@ pub const ObjcStubsSection = struct {
pub fn getAddress(objc: ObjcStubsSection, index: Index, macho_file: *MachO) u64 {
assert(index < objc.symbols.items.len);
const header = macho_file.sections.items(.header)[macho_file.objc_stubs_sect_index.?];
return header.addr + index * entrySize(macho_file.options.cpu_arch.?);
return header.addr + index * entrySize(macho_file.getTarget().cpu.arch);
}
pub fn size(objc: ObjcStubsSection, macho_file: *MachO) usize {
return objc.symbols.items.len * entrySize(macho_file.options.cpu_arch.?);
return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);
}
pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: anytype) !void {
@ -535,7 +535,7 @@ pub const ObjcStubsSection = struct {
for (objc.symbols.items, 0..) |sym_index, idx| {
const sym = macho_file.getSymbol(sym_index);
const addr = objc.getAddress(@intCast(idx), macho_file);
switch (macho_file.options.cpu_arch.?) {
switch (macho_file.getTarget().cpu.arch) {
.x86_64 => {
try writer.writeAll(&.{ 0x48, 0x8b, 0x35 });
{
@ -654,12 +654,12 @@ pub const WeakBindSection = bind.WeakBind;
pub const LazyBindSection = bind.LazyBind;
pub const ExportTrieSection = Trie;
const aarch64 = @import("../aarch64.zig");
const aarch64 = @import("../../arch/aarch64/bits.zig");
const assert = std.debug.assert;
const bind = @import("dyld_info/bind.zig");
const math = std.math;
const std = @import("std");
const trace = @import("../tracy.zig").trace;
const trace = @import("../../tracy.zig").trace;
const Allocator = std.mem.Allocator;
const MachO = @import("../MachO.zig");