authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-11 17:34:52+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-24 12:34:38+01:00
logc5e509595a267ddec7d49a9d89ab2bc4f86a9d35
treee0af57085dd439d7642a9b6920e9dd32187c2517
parentd05e9c379267e9a68522eca3fe8800803c6a5c70

macho: parse archives


3 files changed, 59 insertions(+), 15 deletions(-)

src/link/MachO.zig+42-5
......@@ -845,11 +845,48 @@ fn parseFatLibrary(self: *MachO, path: []const u8) !fat.Arch {
845845}
846846
847847fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Arch) ParseError!void {
848 _ = self;
849 _ = lib;
850 _ = must_link;
851 _ = fat_arch;
852 return error.Unhandled;
848 const tracy = trace(@src());
849 defer tracy.end();
850
851 const gpa = self.base.comp.gpa;
852
853 const file = try std.fs.cwd().openFile(lib.path, .{});
854 defer file.close();
855
856 const data = if (fat_arch) |arch| blk: {
857 try file.seekTo(arch.offset);
858 const data = try gpa.alloc(u8, arch.size);
859 const nread = try file.readAll(data);
860 if (nread != arch.size) return error.InputOutput;
861 break :blk data;
862 } else try file.readToEndAlloc(gpa, std.math.maxInt(u32));
863
864 var archive = Archive{ .path = try gpa.dupe(u8, lib.path), .data = data };
865 defer archive.deinit(gpa);
866 try archive.parse(self);
867
868 var has_parse_error = false;
869 for (archive.objects.items) |extracted| {
870 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
871 self.files.set(index, .{ .object = extracted });
872 const object = &self.files.items(.data)[index].object;
873 object.index = index;
874 object.alive = must_link or lib.needed; // TODO: or self.options.all_load;
875 object.hidden = lib.hidden;
876 object.parse(self) catch |err| switch (err) {
877 error.MalformedObject,
878 error.InvalidCpuArch,
879 error.InvalidTarget,
880 => has_parse_error = true,
881 else => |e| return e,
882 };
883 try self.objects.append(gpa, index);
884
885 // Finally, we do a post-parse check for -ObjC to see if we need to force load this member
886 // anyhow.
887 // TODO: object.alive = object.alive or (self.options.force_load_objc and object.hasObjc());
888 }
889 if (has_parse_error) return error.MalformedArchive;
853890}
854891
855892fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) ParseError!void {
src/link/MachO/Archive.zig+16-10
......@@ -73,14 +73,20 @@ pub fn isArchive(path: []const u8, fat_arch: ?fat.Arch) !bool {
7373}
7474
7575pub fn deinit(self: *Archive, allocator: Allocator) void {
76 allocator.free(self.data);
77 allocator.free(self.path);
7678 self.objects.deinit(allocator);
7779}
7880
79pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {
80 const gpa = macho_file.base.allocator;
81pub fn parse(self: *Archive, macho_file: *MachO) !void {
82 const gpa = macho_file.base.comp.gpa;
83
84 var arena = std.heap.ArenaAllocator.init(gpa);
85 defer arena.deinit();
8186
8287 var stream = std.io.fixedBufferStream(self.data);
8388 const reader = stream.reader();
89 _ = try reader.readBytesNoEof(SARMAG);
8490
8591 while (true) {
8692 if (stream.pos >= self.data.len) break;
......@@ -89,18 +95,18 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {
8995 const hdr = try reader.readStruct(ar_hdr);
9096
9197 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {
92 macho_file.base.fatal("{s}: invalid header delimiter: expected '{s}', found '{s}'", .{
93 self.path, std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
98 try macho_file.reportParseError(self.path, "invalid header delimiter: expected '{s}', found '{s}'", .{
99 std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
94100 });
95 return error.ParseFailed;
101 return error.MalformedArchive;
96102 }
97103
98104 var size = try hdr.size();
99105 const name = name: {
100 if (hdr.name()) |n| break :name try arena.dupe(u8, n);
106 if (hdr.name()) |n| break :name n;
101107 if (try hdr.nameLength()) |len| {
102108 size -= len;
103 const buf = try arena.alloc(u8, len);
109 const buf = try arena.allocator().alloc(u8, len);
104110 try reader.readNoEof(buf);
105111 const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len;
106112 break :name buf[0..actual_len];
......@@ -114,9 +120,9 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {
114120 if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue;
115121
116122 const object = Object{
117 .archive = self.path,
118 .path = name,
119 .data = self.data[stream.pos..][0..size],
123 .archive = try gpa.dupe(u8, self.path),
124 .path = try gpa.dupe(u8, name),
125 .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]),
120126 .index = undefined,
121127 .alive = false,
122128 .mtime = hdr.date() catch 0,
src/link/MachO/Object.zig+1
......@@ -56,6 +56,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
5656 sf.stabs.deinit(allocator);
5757 }
5858 self.stab_files.deinit(allocator);
59 allocator.free(self.data);
5960}
6061
6162pub fn parse(self: *Object, macho_file: *MachO) !void {