macho: parse archives

This commit is contained in:
Jakub Konka 2024-01-11 17:34:52 +01:00
parent d05e9c3792
commit c5e509595a
3 changed files with 59 additions and 15 deletions

View File

@ -845,11 +845,48 @@ fn parseFatLibrary(self: *MachO, path: []const u8) !fat.Arch {
}
fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Arch) ParseError!void {
_ = self;
_ = lib;
_ = must_link;
_ = fat_arch;
return error.Unhandled;
const tracy = trace(@src());
defer tracy.end();
const gpa = self.base.comp.gpa;
const file = try std.fs.cwd().openFile(lib.path, .{});
defer file.close();
const data = if (fat_arch) |arch| blk: {
try file.seekTo(arch.offset);
const data = try gpa.alloc(u8, arch.size);
const nread = try file.readAll(data);
if (nread != arch.size) return error.InputOutput;
break :blk data;
} else try file.readToEndAlloc(gpa, std.math.maxInt(u32));
var archive = Archive{ .path = try gpa.dupe(u8, lib.path), .data = data };
defer archive.deinit(gpa);
try archive.parse(self);
var has_parse_error = false;
for (archive.objects.items) |extracted| {
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
self.files.set(index, .{ .object = extracted });
const object = &self.files.items(.data)[index].object;
object.index = index;
object.alive = must_link or lib.needed; // TODO: or self.options.all_load;
object.hidden = lib.hidden;
object.parse(self) catch |err| switch (err) {
error.MalformedObject,
error.InvalidCpuArch,
error.InvalidTarget,
=> has_parse_error = true,
else => |e| return e,
};
try self.objects.append(gpa, index);
// Finally, we do a post-parse check for -ObjC to see if we need to force load this member
// anyhow.
// TODO: object.alive = object.alive or (self.options.force_load_objc and object.hasObjc());
}
if (has_parse_error) return error.MalformedArchive;
}
fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) ParseError!void {

View File

@ -73,14 +73,20 @@ pub fn isArchive(path: []const u8, fat_arch: ?fat.Arch) !bool {
}
pub fn deinit(self: *Archive, allocator: Allocator) void {
allocator.free(self.data);
allocator.free(self.path);
self.objects.deinit(allocator);
}
pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {
const gpa = macho_file.base.allocator;
pub fn parse(self: *Archive, macho_file: *MachO) !void {
const gpa = macho_file.base.comp.gpa;
var arena = std.heap.ArenaAllocator.init(gpa);
defer arena.deinit();
var stream = std.io.fixedBufferStream(self.data);
const reader = stream.reader();
_ = try reader.readBytesNoEof(SARMAG);
while (true) {
if (stream.pos >= self.data.len) break;
@ -89,18 +95,18 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {
const hdr = try reader.readStruct(ar_hdr);
if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {
macho_file.base.fatal("{s}: invalid header delimiter: expected '{s}', found '{s}'", .{
self.path, std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
try macho_file.reportParseError(self.path, "invalid header delimiter: expected '{s}', found '{s}'", .{
std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
});
return error.ParseFailed;
return error.MalformedArchive;
}
var size = try hdr.size();
const name = name: {
if (hdr.name()) |n| break :name try arena.dupe(u8, n);
if (hdr.name()) |n| break :name n;
if (try hdr.nameLength()) |len| {
size -= len;
const buf = try arena.alloc(u8, len);
const buf = try arena.allocator().alloc(u8, len);
try reader.readNoEof(buf);
const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len;
break :name buf[0..actual_len];
@ -114,9 +120,9 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {
if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue;
const object = Object{
.archive = self.path,
.path = name,
.data = self.data[stream.pos..][0..size],
.archive = try gpa.dupe(u8, self.path),
.path = try gpa.dupe(u8, name),
.data = try gpa.dupe(u8, self.data[stream.pos..][0..size]),
.index = undefined,
.alive = false,
.mtime = hdr.date() catch 0,

View File

@ -56,6 +56,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
sf.stabs.deinit(allocator);
}
self.stab_files.deinit(allocator);
allocator.free(self.data);
}
pub fn parse(self: *Object, macho_file: *MachO) !void {