authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-29 22:16:48+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-29 22:16:48+02:00
log7e167537c032133b416f36425e29c028c10a9462
treea637fca84c61c1a100d235f88d19ca7577545610
parent79b3285aa216350e0c2ff18436a169af69e4570f

macho: simplify handling and reporting parsing errors


4 files changed, 136 insertions(+), 134 deletions(-)

src/link/MachO.zig+100-103
...@@ -401,35 +401,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -401,35 +401,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
401 parent: u16,401 parent: u16,
402 }, .Dynamic).init(arena);402 }, .Dynamic).init(arena);
403403
404 var parse_error_ctx: struct {404 var parse_ctx = ParseErrorCtx.init(arena);
405 detected_arch: std.Target.Cpu.Arch,
406 detected_platform: ?Platform,
407 detected_stub_targets: []const []const u8,
408 } = .{
409 .detected_arch = undefined,
410 .detected_platform = null,
411 .detected_stub_targets = &[0][]const u8{},
412 };
413 defer {
414 for (parse_error_ctx.detected_stub_targets) |target| self.base.allocator.free(target);
415 self.base.allocator.free(parse_error_ctx.detected_stub_targets);
416 }
417405
418 for (libs.keys(), libs.values()) |path, lib| {406 for (libs.keys(), libs.values()) |path, lib| {
419 const in_file = try std.fs.cwd().openFile(path, .{});407 const in_file = try std.fs.cwd().openFile(path, .{});
420 defer in_file.close();408 defer in_file.close();
421409 defer parse_ctx.detected_targets.clearRetainingCapacity();
422 self.parseLibrary(410 self.parseLibrary(
423 in_file,411 in_file,
424 path,412 path,
425 lib,413 lib,
426 false,414 false,
427 &dependent_libs,415 &dependent_libs,
428 &parse_error_ctx,416 &parse_ctx,
429 ) catch |err| try self.handleAndReportParseError(path, err, parse_error_ctx);417 ) catch |err| try self.handleAndReportParseError(path, err, &parse_ctx);
430 }418 }
431419
432 self.parseDependentLibs(&dependent_libs, &parse_error_ctx) catch |err| {420 self.parseDependentLibs(&dependent_libs, &parse_ctx) catch |err| {
433 // TODO convert to error421 // TODO convert to error
434 log.err("parsing dependent libraries failed with err {s}", .{@errorName(err)});422 log.err("parsing dependent libraries failed with err {s}", .{@errorName(err)});
435 };423 };
...@@ -727,9 +715,7 @@ fn resolveLib(...@@ -727,9 +715,7 @@ fn resolveLib(
727715
728const ParseError = error{716const ParseError = error{
729 UnknownFileType,717 UnknownFileType,
730 MissingArchFatLib,
731 InvalidTarget,718 InvalidTarget,
732 InvalidLibStubTargets,
733 DylibAlreadyExists,719 DylibAlreadyExists,
734 IncompatibleDylibVersion,720 IncompatibleDylibVersion,
735 OutOfMemory,721 OutOfMemory,
...@@ -748,19 +734,19 @@ pub fn parsePositional(...@@ -748,19 +734,19 @@ pub fn parsePositional(
748 path: []const u8,734 path: []const u8,
749 must_link: bool,735 must_link: bool,
750 dependent_libs: anytype,736 dependent_libs: anytype,
751 error_ctx: anytype,737 ctx: *ParseErrorCtx,
752) ParseError!void {738) ParseError!void {
753 const tracy = trace(@src());739 const tracy = trace(@src());
754 defer tracy.end();740 defer tracy.end();
755741
756 if (Object.isObject(file)) {742 if (Object.isObject(file)) {
757 try self.parseObject(file, path, error_ctx);743 try self.parseObject(file, path, ctx);
758 } else {744 } else {
759 try self.parseLibrary(file, path, .{745 try self.parseLibrary(file, path, .{
760 .path = null,746 .path = null,
761 .needed = false,747 .needed = false,
762 .weak = false,748 .weak = false,
763 }, must_link, dependent_libs, error_ctx);749 }, must_link, dependent_libs, ctx);
764 }750 }
765}751}
766752
...@@ -768,7 +754,7 @@ fn parseObject(...@@ -768,7 +754,7 @@ fn parseObject(
768 self: *MachO,754 self: *MachO,
769 file: std.fs.File,755 file: std.fs.File,
770 path: []const u8,756 path: []const u8,
771 error_ctx: anytype,757 ctx: *ParseErrorCtx,
772) ParseError!void {758) ParseError!void {
773 const tracy = trace(@src());759 const tracy = trace(@src());
774 defer tracy.end();760 defer tracy.end();
...@@ -790,20 +776,21 @@ fn parseObject(...@@ -790,20 +776,21 @@ fn parseObject(
790 errdefer object.deinit(gpa);776 errdefer object.deinit(gpa);
791 try object.parse(gpa);777 try object.parse(gpa);
792778
793 const cpu_arch: std.Target.Cpu.Arch = switch (object.header.cputype) {779 const detected_cpu_arch: std.Target.Cpu.Arch = switch (object.header.cputype) {
794 macho.CPU_TYPE_ARM64 => .aarch64,780 macho.CPU_TYPE_ARM64 => .aarch64,
795 macho.CPU_TYPE_X86_64 => .x86_64,781 macho.CPU_TYPE_X86_64 => .x86_64,
796 else => unreachable,782 else => unreachable,
797 };783 };
798 error_ctx.detected_arch = cpu_arch;784 const detected_platform = object.getPlatform();
799785 const this_cpu_arch = self.base.options.target.cpu.arch;
800 if (object.getPlatform()) |platform| {786 const this_platform = Platform.fromTarget(self.base.options.target);
801 error_ctx.detected_platform = platform;
802 }
803787
804 if (self.base.options.target.cpu.arch != cpu_arch) return error.InvalidTarget;788 if (this_cpu_arch != detected_cpu_arch or
805 if (error_ctx.detected_platform) |platform| {789 (detected_platform != null and !detected_platform.?.eqlTarget(this_platform)))
806 if (!Platform.fromTarget(self.base.options.target).eqlTarget(platform)) return error.InvalidTarget;790 {
791 const platform = detected_platform orelse this_platform;
792 try ctx.detected_targets.append(try platform.allocPrintTarget(ctx.arena, detected_cpu_arch));
793 return error.InvalidTarget;
807 }794 }
808795
809 try self.objects.append(gpa, object);796 try self.objects.append(gpa, object);
...@@ -816,48 +803,61 @@ pub fn parseLibrary(...@@ -816,48 +803,61 @@ pub fn parseLibrary(
816 lib: link.SystemLib,803 lib: link.SystemLib,
817 must_link: bool,804 must_link: bool,
818 dependent_libs: anytype,805 dependent_libs: anytype,
819 error_ctx: anytype,806 ctx: *ParseErrorCtx,
820) ParseError!void {807) ParseError!void {
821 const tracy = trace(@src());808 const tracy = trace(@src());
822 defer tracy.end();809 defer tracy.end();
823810
824 if (fat.isFatLibrary(file)) {811 if (fat.isFatLibrary(file)) {
825 const offset = try self.parseFatLibrary(file, self.base.options.target.cpu.arch);812 const offset = try self.parseFatLibrary(file, self.base.options.target.cpu.arch, ctx);
826 try file.seekTo(offset);813 try file.seekTo(offset);
827814
828 if (Archive.isArchive(file, offset)) {815 if (Archive.isArchive(file, offset)) {
829 try self.parseArchive(path, offset, must_link, error_ctx);816 try self.parseArchive(path, offset, must_link, ctx);
830 } else if (Dylib.isDylib(file, offset)) {817 } else if (Dylib.isDylib(file, offset)) {
831 try self.parseDylib(file, path, offset, dependent_libs, .{818 try self.parseDylib(file, path, offset, dependent_libs, .{
832 .needed = lib.needed,819 .needed = lib.needed,
833 .weak = lib.weak,820 .weak = lib.weak,
834 }, error_ctx);821 }, ctx);
835 } else return error.UnknownFileType;822 } else return error.UnknownFileType;
836 } else if (Archive.isArchive(file, 0)) {823 } else if (Archive.isArchive(file, 0)) {
837 try self.parseArchive(path, 0, must_link, error_ctx);824 try self.parseArchive(path, 0, must_link, ctx);
838 } else if (Dylib.isDylib(file, 0)) {825 } else if (Dylib.isDylib(file, 0)) {
839 try self.parseDylib(file, path, 0, dependent_libs, .{826 try self.parseDylib(file, path, 0, dependent_libs, .{
840 .needed = lib.needed,827 .needed = lib.needed,
841 .weak = lib.weak,828 .weak = lib.weak,
842 }, error_ctx);829 }, ctx);
843 } else {830 } else {
844 self.parseLibStub(file, path, dependent_libs, .{831 self.parseLibStub(file, path, dependent_libs, .{
845 .needed = lib.needed,832 .needed = lib.needed,
846 .weak = lib.weak,833 .weak = lib.weak,
847 }, error_ctx) catch |err| switch (err) {834 }, ctx) catch |err| switch (err) {
848 error.NotLibStub, error.UnexpectedToken => return error.UnknownFileType,835 error.NotLibStub, error.UnexpectedToken => return error.UnknownFileType,
849 else => |e| return e,836 else => |e| return e,
850 };837 };
851 }838 }
852}839}
853840
854pub fn parseFatLibrary(self: *MachO, file: std.fs.File, cpu_arch: std.Target.Cpu.Arch) ParseError!u64 {841pub fn parseFatLibrary(
855 _ = self;842 self: *MachO,
856 var buffer: [2]fat.Arch = undefined;843 file: std.fs.File,
857 const fat_archs = try fat.parseArchs(file, &buffer);844 cpu_arch: std.Target.Cpu.Arch,
845 ctx: *ParseErrorCtx,
846) ParseError!u64 {
847 const gpa = self.base.allocator;
848
849 const fat_archs = try fat.parseArchs(gpa, file);
850 defer gpa.free(fat_archs);
851
858 const offset = for (fat_archs) |arch| {852 const offset = for (fat_archs) |arch| {
859 if (arch.tag == cpu_arch) break arch.offset;853 if (arch.tag == cpu_arch) break arch.offset;
860 } else return error.MissingArchFatLib;854 } else {
855 try ctx.detected_targets.ensureTotalCapacityPrecise(fat_archs.len);
856 for (fat_archs) |arch| {
857 ctx.detected_targets.appendAssumeCapacity(try ctx.arena.dupe(u8, @tagName(arch.tag)));
858 }
859 return error.InvalidTarget;
860 };
861 return offset;861 return offset;
862}862}
863863
...@@ -866,7 +866,7 @@ fn parseArchive(...@@ -866,7 +866,7 @@ fn parseArchive(
866 path: []const u8,866 path: []const u8,
867 fat_offset: u64,867 fat_offset: u64,
868 must_link: bool,868 must_link: bool,
869 error_ctx: anytype,869 ctx: *ParseErrorCtx,
870) ParseError!void {870) ParseError!void {
871 const gpa = self.base.allocator;871 const gpa = self.base.allocator;
872872
...@@ -892,20 +892,21 @@ fn parseArchive(...@@ -892,20 +892,21 @@ fn parseArchive(
892 var object = try archive.parseObject(gpa, off); // TODO we are doing all this work to pull the header only!892 var object = try archive.parseObject(gpa, off); // TODO we are doing all this work to pull the header only!
893 defer object.deinit(gpa);893 defer object.deinit(gpa);
894894
895 const cpu_arch: std.Target.Cpu.Arch = switch (object.header.cputype) {895 const detected_cpu_arch: std.Target.Cpu.Arch = switch (object.header.cputype) {
896 macho.CPU_TYPE_ARM64 => .aarch64,896 macho.CPU_TYPE_ARM64 => .aarch64,
897 macho.CPU_TYPE_X86_64 => .x86_64,897 macho.CPU_TYPE_X86_64 => .x86_64,
898 else => unreachable,898 else => unreachable,
899 };899 };
900 error_ctx.detected_arch = cpu_arch;900 const detected_platform = object.getPlatform();
901901 const this_cpu_arch = self.base.options.target.cpu.arch;
902 if (object.getPlatform()) |platform| {902 const this_platform = Platform.fromTarget(self.base.options.target);
903 error_ctx.detected_platform = platform;
904 }
905903
906 if (self.base.options.target.cpu.arch != cpu_arch) return error.InvalidTarget;904 if (this_cpu_arch != detected_cpu_arch or
907 if (error_ctx.detected_platform) |platform| {905 (detected_platform != null and !detected_platform.?.eqlTarget(this_platform)))
908 if (!Platform.fromTarget(self.base.options.target).eqlTarget(platform)) return error.InvalidTarget;906 {
907 const platform = detected_platform orelse this_platform;
908 try ctx.detected_targets.append(try platform.allocPrintTarget(gpa, detected_cpu_arch));
909 return error.InvalidTarget;
909 }910 }
910 }911 }
911912
...@@ -941,7 +942,7 @@ fn parseDylib(...@@ -941,7 +942,7 @@ fn parseDylib(
941 offset: u64,942 offset: u64,
942 dependent_libs: anytype,943 dependent_libs: anytype,
943 dylib_options: DylibOpts,944 dylib_options: DylibOpts,
944 error_ctx: anytype,945 ctx: *ParseErrorCtx,
945) ParseError!void {946) ParseError!void {
946 const gpa = self.base.allocator;947 const gpa = self.base.allocator;
947 const file_stat = try file.stat();948 const file_stat = try file.stat();
...@@ -961,20 +962,21 @@ fn parseDylib(...@@ -961,20 +962,21 @@ fn parseDylib(
961 contents,962 contents,
962 );963 );
963964
964 const cpu_arch: std.Target.Cpu.Arch = switch (dylib.header.?.cputype) {965 const detected_cpu_arch: std.Target.Cpu.Arch = switch (dylib.header.?.cputype) {
965 macho.CPU_TYPE_ARM64 => .aarch64,966 macho.CPU_TYPE_ARM64 => .aarch64,
966 macho.CPU_TYPE_X86_64 => .x86_64,967 macho.CPU_TYPE_X86_64 => .x86_64,
967 else => unreachable,968 else => unreachable,
968 };969 };
969 error_ctx.detected_arch = cpu_arch;970 const detected_platform = dylib.getPlatform(contents);
971 const this_cpu_arch = self.base.options.target.cpu.arch;
972 const this_platform = Platform.fromTarget(self.base.options.target);
970973
971 if (dylib.getPlatform(contents)) |platform| {974 if (this_cpu_arch != detected_cpu_arch or
972 error_ctx.detected_platform = platform;975 (detected_platform != null and !detected_platform.?.eqlTarget(this_platform)))
973 }976 {
974977 const platform = detected_platform orelse this_platform;
975 if (self.base.options.target.cpu.arch != cpu_arch) return error.InvalidTarget;978 try ctx.detected_targets.append(try platform.allocPrintTarget(ctx.arena, detected_cpu_arch));
976 if (error_ctx.detected_platform) |platform| {979 return error.InvalidTarget;
977 if (!Platform.fromTarget(self.base.options.target).eqlTarget(platform)) return error.InvalidTarget;
978 }980 }
979981
980 try self.addDylib(dylib, .{982 try self.addDylib(dylib, .{
...@@ -989,7 +991,7 @@ fn parseLibStub(...@@ -989,7 +991,7 @@ fn parseLibStub(
989 path: []const u8,991 path: []const u8,
990 dependent_libs: anytype,992 dependent_libs: anytype,
991 dylib_options: DylibOpts,993 dylib_options: DylibOpts,
992 error_ctx: anytype,994 ctx: *ParseErrorCtx,
993) ParseError!void {995) ParseError!void {
994 const gpa = self.base.allocator;996 const gpa = self.base.allocator;
995 var lib_stub = try LibStub.loadFromFile(gpa, file);997 var lib_stub = try LibStub.loadFromFile(gpa, file);
...@@ -1004,12 +1006,17 @@ fn parseLibStub(...@@ -1004,12 +1006,17 @@ fn parseLibStub(
10041006
1005 const first_tbd = lib_stub.inner[0];1007 const first_tbd = lib_stub.inner[0];
1006 const targets = try first_tbd.targets(gpa);1008 const targets = try first_tbd.targets(gpa);
1009 defer {
1010 for (targets) |t| gpa.free(t);
1011 gpa.free(targets);
1012 }
1007 if (!matcher.matchesTarget(targets)) {1013 if (!matcher.matchesTarget(targets)) {
1008 error_ctx.detected_stub_targets = targets;1014 try ctx.detected_targets.ensureUnusedCapacity(targets.len);
1009 return error.InvalidLibStubTargets;1015 for (targets) |t| {
1016 ctx.detected_targets.appendAssumeCapacity(try ctx.arena.dupe(u8, t));
1017 }
1018 return error.InvalidTarget;
1010 }1019 }
1011 for (targets) |t| gpa.free(t);
1012 gpa.free(targets);
1013 }1020 }
10141021
1015 var dylib = Dylib{ .weak = dylib_options.weak };1022 var dylib = Dylib{ .weak = dylib_options.weak };
...@@ -1059,7 +1066,7 @@ fn addDylib(self: *MachO, dylib: Dylib, dylib_options: DylibOpts) ParseError!voi...@@ -1059,7 +1066,7 @@ fn addDylib(self: *MachO, dylib: Dylib, dylib_options: DylibOpts) ParseError!voi
1059 }1066 }
1060}1067}
10611068
1062pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, error_ctx: anytype) ParseError!void {1069pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, ctx: *ParseErrorCtx) ParseError!void {
1063 const tracy = trace(@src());1070 const tracy = trace(@src());
1064 defer tracy.end();1071 defer tracy.end();
10651072
...@@ -1105,7 +1112,7 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, error_ctx: anyt...@@ -1105,7 +1112,7 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, error_ctx: anyt
1105 log.debug("trying dependency at fully resolved path {s}", .{full_path});1112 log.debug("trying dependency at fully resolved path {s}", .{full_path});
11061113
1107 const offset: u64 = if (fat.isFatLibrary(file)) blk: {1114 const offset: u64 = if (fat.isFatLibrary(file)) blk: {
1108 const offset = try self.parseFatLibrary(file, self.base.options.target.cpu.arch);1115 const offset = try self.parseFatLibrary(file, self.base.options.target.cpu.arch, ctx);
1109 try file.seekTo(offset);1116 try file.seekTo(offset);
1110 break :blk offset;1117 break :blk offset;
1111 } else 0;1118 } else 0;
...@@ -1114,12 +1121,12 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, error_ctx: anyt...@@ -1114,12 +1121,12 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, error_ctx: anyt
1114 try self.parseDylib(file, full_path, offset, dependent_libs, .{1121 try self.parseDylib(file, full_path, offset, dependent_libs, .{
1115 .dependent = true,1122 .dependent = true,
1116 .weak = weak,1123 .weak = weak,
1117 }, error_ctx);1124 }, ctx);
1118 } else {1125 } else {
1119 self.parseLibStub(file, full_path, dependent_libs, .{1126 self.parseLibStub(file, full_path, dependent_libs, .{
1120 .dependent = true,1127 .dependent = true,
1121 .weak = weak,1128 .weak = weak,
1122 }, error_ctx) catch |err| switch (err) {1129 }, ctx) catch |err| switch (err) {
1123 error.NotLibStub, error.UnexpectedToken => continue,1130 error.NotLibStub, error.UnexpectedToken => continue,
1124 else => |e| return e,1131 else => |e| return e,
1125 };1132 };
...@@ -4845,50 +4852,40 @@ pub fn getSectionPrecedence(header: macho.section_64) u8 {...@@ -4845,50 +4852,40 @@ pub fn getSectionPrecedence(header: macho.section_64) u8 {
4845 return (@as(u8, @intCast(segment_precedence)) << 4) + section_precedence;4852 return (@as(u8, @intCast(segment_precedence)) << 4) + section_precedence;
4846}4853}
48474854
4848pub fn handleAndReportParseError(self: *MachO, path: []const u8, err: ParseError, parse_error_ctx: anytype) !void {4855pub const ParseErrorCtx = struct {
4856 arena: Allocator,
4857 detected_targets: std.ArrayList([]const u8),
4858
4859 pub fn init(arena: Allocator) ParseErrorCtx {
4860 return .{ .arena = arena, .detected_targets = std.ArrayList([]const u8).init(arena) };
4861 }
4862};
4863
4864pub fn handleAndReportParseError(
4865 self: *MachO,
4866 path: []const u8,
4867 err: ParseError,
4868 ctx: *const ParseErrorCtx,
4869) !void {
4849 const cpu_arch = self.base.options.target.cpu.arch;4870 const cpu_arch = self.base.options.target.cpu.arch;
4850 switch (err) {4871 switch (err) {
4851 error.DylibAlreadyExists => {},4872 error.DylibAlreadyExists => {},
4852 error.UnknownFileType => try self.reportParseError(path, "unknown file type", .{}),4873 error.UnknownFileType => try self.reportParseError(path, "unknown file type", .{}),
4853 error.MissingArchFatLib => try self.reportParseError(4874 error.InvalidTarget => {
4854 path,
4855 "missing architecture in universal file, expected '{s}'",
4856 .{@tagName(cpu_arch)},
4857 ),
4858 error.InvalidTarget => if (parse_error_ctx.detected_platform) |platform| {
4859 try self.reportParseError(path, "invalid target '{s}-{}', expected '{s}-{}'", .{
4860 @tagName(parse_error_ctx.detected_arch),
4861 platform.fmtTarget(),
4862 @tagName(cpu_arch),
4863 Platform.fromTarget(self.base.options.target).fmtTarget(),
4864 });
4865 } else {
4866 try self.reportParseError(
4867 path,
4868 "invalid architecture '{s}', expected '{s}'",
4869 .{ @tagName(parse_error_ctx.detected_arch), @tagName(cpu_arch) },
4870 );
4871 },
4872 error.InvalidLibStubTargets => {
4873 var targets_string = std.ArrayList(u8).init(self.base.allocator);4875 var targets_string = std.ArrayList(u8).init(self.base.allocator);
4874 defer targets_string.deinit();4876 defer targets_string.deinit();
4875 try targets_string.writer().writeAll("(");4877 try targets_string.writer().writeAll("(");
4876 for (parse_error_ctx.detected_stub_targets) |t| {4878 for (ctx.detected_targets.items) |t| {
4877 try targets_string.writer().print("{s}, ", .{t});4879 try targets_string.writer().print("{s}, ", .{t});
4878 }4880 }
4879 try targets_string.resize(targets_string.items.len - 2);4881 try targets_string.resize(targets_string.items.len - 2);
4880 try targets_string.writer().writeAll(")");4882 try targets_string.writer().writeAll(")");
4881 try self.reportParseError(path, "invalid targets '{s}', expected '{s}-{}'", .{4883 try self.reportParseError(path, "invalid target: expected '{}', but found '{s}'", .{
4884 Platform.fromTarget(self.base.options.target).fmtTarget(cpu_arch),
4882 targets_string.items,4885 targets_string.items,
4883 @tagName(cpu_arch),
4884 Platform.fromTarget(self.base.options.target).fmtTarget(),
4885 });4886 });
4886 },4887 },
4887 else => |e| try self.reportParseError(4888 else => |e| try self.reportParseError(path, "{s}: parsing object failed", .{@errorName(e)}),
4888 path,
4889 "parsing positional argument failed with error '{s}'",
4890 .{@errorName(e)},
4891 ),
4892 }4889 }
4893}4890}
48944891
src/link/MachO/fat.zig+9-5
...@@ -10,12 +10,15 @@ pub const Arch = struct {...@@ -10,12 +10,15 @@ pub const Arch = struct {
10 offset: u64,10 offset: u64,
11};11};
1212
13pub fn parseArchs(file: std.fs.File, buffer: *[2]Arch) ![]const Arch {13/// Caller owns the memory.
14pub fn parseArchs(gpa: Allocator, file: std.fs.File) ![]const Arch {
14 const reader = file.reader();15 const reader = file.reader();
15 const fat_header = try reader.readStructBig(macho.fat_header);16 const fat_header = try reader.readStructBig(macho.fat_header);
16 assert(fat_header.magic == macho.FAT_MAGIC);17 assert(fat_header.magic == macho.FAT_MAGIC);
1718
18 var count: usize = 0;19 var archs = try std.ArrayList(Arch).initCapacity(gpa, fat_header.nfat_arch);
20 defer archs.deinit();
21
19 var fat_arch_index: u32 = 0;22 var fat_arch_index: u32 = 0;
20 while (fat_arch_index < fat_header.nfat_arch) : (fat_arch_index += 1) {23 while (fat_arch_index < fat_header.nfat_arch) : (fat_arch_index += 1) {
21 const fat_arch = try reader.readStructBig(macho.fat_arch);24 const fat_arch = try reader.readStructBig(macho.fat_arch);
...@@ -26,11 +29,11 @@ pub fn parseArchs(file: std.fs.File, buffer: *[2]Arch) ![]const Arch {...@@ -26,11 +29,11 @@ pub fn parseArchs(file: std.fs.File, buffer: *[2]Arch) ![]const Arch {
26 macho.CPU_TYPE_X86_64 => if (fat_arch.cpusubtype == macho.CPU_SUBTYPE_X86_64_ALL) .x86_64 else continue,29 macho.CPU_TYPE_X86_64 => if (fat_arch.cpusubtype == macho.CPU_SUBTYPE_X86_64_ALL) .x86_64 else continue,
27 else => continue,30 else => continue,
28 };31 };
29 buffer[count] = .{ .tag = arch, .offset = fat_arch.offset };32
30 count += 1;33 archs.appendAssumeCapacity(.{ .tag = arch, .offset = fat_arch.offset });
31 }34 }
3235
33 return buffer[0..count];36 return archs.toOwnedSlice();
34}37}
3538
36const std = @import("std");39const std = @import("std");
...@@ -38,3 +41,4 @@ const assert = std.debug.assert;...@@ -38,3 +41,4 @@ const assert = std.debug.assert;
38const log = std.log.scoped(.archive);41const log = std.log.scoped(.archive);
39const macho = std.macho;42const macho = std.macho;
40const mem = std.mem;43const mem = std.mem;
44const Allocator = mem.Allocator;
src/link/MachO/load_commands.zig+19-6
...@@ -384,24 +384,37 @@ pub const Platform = struct {...@@ -384,24 +384,37 @@ pub const Platform = struct {
384 return false;384 return false;
385 }385 }
386386
387 pub fn fmtTarget(plat: Platform) std.fmt.Formatter(formatTarget) {387 pub fn fmtTarget(plat: Platform, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(formatTarget) {
388 return .{ .data = plat };388 return .{ .data = .{ .platform = plat, .cpu_arch = cpu_arch } };
389 }389 }
390390
391 const FmtCtx = struct {
392 platform: Platform,
393 cpu_arch: std.Target.Cpu.Arch,
394 };
395
391 pub fn formatTarget(396 pub fn formatTarget(
392 plat: Platform,397 ctx: FmtCtx,
393 comptime unused_fmt_string: []const u8,398 comptime unused_fmt_string: []const u8,
394 options: std.fmt.FormatOptions,399 options: std.fmt.FormatOptions,
395 writer: anytype,400 writer: anytype,
396 ) !void {401 ) !void {
397 _ = unused_fmt_string;402 _ = unused_fmt_string;
398 _ = options;403 _ = options;
399 try writer.print("{s}", .{@tagName(plat.os_tag)});404 try writer.print("{s}-{s}", .{ @tagName(ctx.cpu_arch), @tagName(ctx.platform.os_tag) });
400 if (plat.abi != .none) {405 if (ctx.platform.abi != .none) {
401 try writer.print("-{s}", .{@tagName(plat.abi)});406 try writer.print("-{s}", .{@tagName(ctx.platform.abi)});
402 }407 }
403 }408 }
404409
410 /// Caller owns the memory.
411 pub fn allocPrintTarget(plat: Platform, gpa: Allocator, cpu_arch: std.Target.Cpu.Arch) error{OutOfMemory}![]u8 {
412 var buffer = std.ArrayList(u8).init(gpa);
413 defer buffer.deinit();
414 try buffer.writer().print("{}", .{plat.fmtTarget(cpu_arch)});
415 return buffer.toOwnedSlice();
416 }
417
405 pub fn eqlTarget(plat: Platform, other: Platform) bool {418 pub fn eqlTarget(plat: Platform, other: Platform) bool {
406 return plat.os_tag == other.os_tag and plat.abi == other.abi;419 return plat.os_tag == other.os_tag and plat.abi == other.abi;
407 }420 }
src/link/MachO/zld.zig+8-20
...@@ -345,48 +345,36 @@ pub fn linkWithZld(...@@ -345,48 +345,36 @@ pub fn linkWithZld(
345 parent: u16,345 parent: u16,
346 }, .Dynamic).init(arena);346 }, .Dynamic).init(arena);
347347
348 var parse_error_ctx: struct {348 var parse_ctx = MachO.ParseErrorCtx.init(arena);
349 detected_arch: std.Target.Cpu.Arch,
350 detected_platform: ?Platform,
351 detected_stub_targets: []const []const u8,
352 } = .{
353 .detected_arch = undefined,
354 .detected_platform = null,
355 .detected_stub_targets = &[0][]const u8{},
356 };
357 defer {
358 for (parse_error_ctx.detected_stub_targets) |t| gpa.free(t);
359 gpa.free(parse_error_ctx.detected_stub_targets);
360 }
361349
362 for (positionals.items) |obj| {350 for (positionals.items) |obj| {
363 const in_file = try std.fs.cwd().openFile(obj.path, .{});351 const in_file = try std.fs.cwd().openFile(obj.path, .{});
364 defer in_file.close();352 defer in_file.close();
365353 defer parse_ctx.detected_targets.clearRetainingCapacity();
366 macho_file.parsePositional(354 macho_file.parsePositional(
367 in_file,355 in_file,
368 obj.path,356 obj.path,
369 obj.must_link,357 obj.must_link,
370 &dependent_libs,358 &dependent_libs,
371 &parse_error_ctx,359 &parse_ctx,
372 ) catch |err| try macho_file.handleAndReportParseError(obj.path, err, parse_error_ctx);360 ) catch |err| try macho_file.handleAndReportParseError(obj.path, err, &parse_ctx);
373 }361 }
374362
375 for (libs.keys(), libs.values()) |path, lib| {363 for (libs.keys(), libs.values()) |path, lib| {
376 const in_file = try std.fs.cwd().openFile(path, .{});364 const in_file = try std.fs.cwd().openFile(path, .{});
377 defer in_file.close();365 defer in_file.close();
378366 defer parse_ctx.detected_targets.clearRetainingCapacity();
379 macho_file.parseLibrary(367 macho_file.parseLibrary(
380 in_file,368 in_file,
381 path,369 path,
382 lib,370 lib,
383 false,371 false,
384 &dependent_libs,372 &dependent_libs,
385 &parse_error_ctx,373 &parse_ctx,
386 ) catch |err| try macho_file.handleAndReportParseError(path, err, parse_error_ctx);374 ) catch |err| try macho_file.handleAndReportParseError(path, err, &parse_ctx);
387 }375 }
388376
389 macho_file.parseDependentLibs(&dependent_libs, &parse_error_ctx) catch |err| {377 macho_file.parseDependentLibs(&dependent_libs, &parse_ctx) catch |err| {
390 // TODO convert to error378 // TODO convert to error
391 log.err("parsing dependent libraries failed with err {s}", .{@errorName(err)});379 log.err("parsing dependent libraries failed with err {s}", .{@errorName(err)});
392 };380 };