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 {...@@ -845,11 +845,48 @@ fn parseFatLibrary(self: *MachO, path: []const u8) !fat.Arch {
845}845}
846846
847fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Arch) ParseError!void {847fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Arch) ParseError!void {
848 _ = self;848 const tracy = trace(@src());
849 _ = lib;849 defer tracy.end();
850 _ = must_link;850
851 _ = fat_arch;851 const gpa = self.base.comp.gpa;
852 return error.Unhandled;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;
853}890}
854891
855fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) ParseError!void {892fn 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 {...@@ -73,14 +73,20 @@ pub fn isArchive(path: []const u8, fat_arch: ?fat.Arch) !bool {
73}73}
7474
75pub fn deinit(self: *Archive, allocator: Allocator) void {75pub fn deinit(self: *Archive, allocator: Allocator) void {
76 allocator.free(self.data);
77 allocator.free(self.path);
76 self.objects.deinit(allocator);78 self.objects.deinit(allocator);
77}79}
7880
79pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {81pub fn parse(self: *Archive, macho_file: *MachO) !void {
80 const gpa = macho_file.base.allocator;82 const gpa = macho_file.base.comp.gpa;
83
84 var arena = std.heap.ArenaAllocator.init(gpa);
85 defer arena.deinit();
8186
82 var stream = std.io.fixedBufferStream(self.data);87 var stream = std.io.fixedBufferStream(self.data);
83 const reader = stream.reader();88 const reader = stream.reader();
89 _ = try reader.readBytesNoEof(SARMAG);
8490
85 while (true) {91 while (true) {
86 if (stream.pos >= self.data.len) break;92 if (stream.pos >= self.data.len) break;
...@@ -89,18 +95,18 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {...@@ -89,18 +95,18 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {
89 const hdr = try reader.readStruct(ar_hdr);95 const hdr = try reader.readStruct(ar_hdr);
9096
91 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {97 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {
92 macho_file.base.fatal("{s}: invalid header delimiter: expected '{s}', found '{s}'", .{98 try macho_file.reportParseError(self.path, "invalid header delimiter: expected '{s}', found '{s}'", .{
93 self.path, std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),99 std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
94 });100 });
95 return error.ParseFailed;101 return error.MalformedArchive;
96 }102 }
97103
98 var size = try hdr.size();104 var size = try hdr.size();
99 const name = name: {105 const name = name: {
100 if (hdr.name()) |n| break :name try arena.dupe(u8, n);106 if (hdr.name()) |n| break :name n;
101 if (try hdr.nameLength()) |len| {107 if (try hdr.nameLength()) |len| {
102 size -= len;108 size -= len;
103 const buf = try arena.alloc(u8, len);109 const buf = try arena.allocator().alloc(u8, len);
104 try reader.readNoEof(buf);110 try reader.readNoEof(buf);
105 const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len;111 const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len;
106 break :name buf[0..actual_len];112 break :name buf[0..actual_len];
...@@ -114,9 +120,9 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {...@@ -114,9 +120,9 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {
114 if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue;120 if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue;
115121
116 const object = Object{122 const object = Object{
117 .archive = self.path,123 .archive = try gpa.dupe(u8, self.path),
118 .path = name,124 .path = try gpa.dupe(u8, name),
119 .data = self.data[stream.pos..][0..size],125 .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]),
120 .index = undefined,126 .index = undefined,
121 .alive = false,127 .alive = false,
122 .mtime = hdr.date() catch 0,128 .mtime = hdr.date() catch 0,
src/link/MachO/Object.zig+1
...@@ -56,6 +56,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -56,6 +56,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
56 sf.stabs.deinit(allocator);56 sf.stabs.deinit(allocator);
57 }57 }
58 self.stab_files.deinit(allocator);58 self.stab_files.deinit(allocator);
59 allocator.free(self.data);
59}60}
6061
61pub fn parse(self: *Object, macho_file: *MachO) !void {62pub fn parse(self: *Object, macho_file: *MachO) !void {