| ... | ... | @@ -401,35 +401,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 401 | 401 | parent: u16, |
| 402 | 402 | }, .Dynamic).init(arena); |
| 403 | 403 | |
| 404 | | var parse_error_ctx: struct { |
| 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 | | } |
| 404 | var parse_ctx = ParseErrorCtx.init(arena); |
| 417 | 405 | |
| 418 | 406 | for (libs.keys(), libs.values()) |path, lib| { |
| 419 | 407 | const in_file = try std.fs.cwd().openFile(path, .{}); |
| 420 | 408 | defer in_file.close(); |
| 421 | | |
| 409 | defer parse_ctx.detected_targets.clearRetainingCapacity(); |
| 422 | 410 | self.parseLibrary( |
| 423 | 411 | in_file, |
| 424 | 412 | path, |
| 425 | 413 | lib, |
| 426 | 414 | false, |
| 427 | 415 | &dependent_libs, |
| 428 | | &parse_error_ctx, |
| 429 | | ) catch |err| try self.handleAndReportParseError(path, err, parse_error_ctx); |
| 416 | &parse_ctx, |
| 417 | ) catch |err| try self.handleAndReportParseError(path, err, &parse_ctx); |
| 430 | 418 | } |
| 431 | 419 | |
| 432 | | self.parseDependentLibs(&dependent_libs, &parse_error_ctx) catch |err| { |
| 420 | self.parseDependentLibs(&dependent_libs, &parse_ctx) catch |err| { |
| 433 | 421 | // TODO convert to error |
| 434 | 422 | log.err("parsing dependent libraries failed with err {s}", .{@errorName(err)}); |
| 435 | 423 | }; |
| ... | ... | @@ -727,9 +715,7 @@ fn resolveLib( |
| 727 | 715 | |
| 728 | 716 | const ParseError = error{ |
| 729 | 717 | UnknownFileType, |
| 730 | | MissingArchFatLib, |
| 731 | 718 | InvalidTarget, |
| 732 | | InvalidLibStubTargets, |
| 733 | 719 | DylibAlreadyExists, |
| 734 | 720 | IncompatibleDylibVersion, |
| 735 | 721 | OutOfMemory, |
| ... | ... | @@ -748,19 +734,19 @@ pub fn parsePositional( |
| 748 | 734 | path: []const u8, |
| 749 | 735 | must_link: bool, |
| 750 | 736 | dependent_libs: anytype, |
| 751 | | error_ctx: anytype, |
| 737 | ctx: *ParseErrorCtx, |
| 752 | 738 | ) ParseError!void { |
| 753 | 739 | const tracy = trace(@src()); |
| 754 | 740 | defer tracy.end(); |
| 755 | 741 | |
| 756 | 742 | if (Object.isObject(file)) { |
| 757 | | try self.parseObject(file, path, error_ctx); |
| 743 | try self.parseObject(file, path, ctx); |
| 758 | 744 | } else { |
| 759 | 745 | try self.parseLibrary(file, path, .{ |
| 760 | 746 | .path = null, |
| 761 | 747 | .needed = false, |
| 762 | 748 | .weak = false, |
| 763 | | }, must_link, dependent_libs, error_ctx); |
| 749 | }, must_link, dependent_libs, ctx); |
| 764 | 750 | } |
| 765 | 751 | } |
| 766 | 752 | |
| ... | ... | @@ -768,7 +754,7 @@ fn parseObject( |
| 768 | 754 | self: *MachO, |
| 769 | 755 | file: std.fs.File, |
| 770 | 756 | path: []const u8, |
| 771 | | error_ctx: anytype, |
| 757 | ctx: *ParseErrorCtx, |
| 772 | 758 | ) ParseError!void { |
| 773 | 759 | const tracy = trace(@src()); |
| 774 | 760 | defer tracy.end(); |
| ... | ... | @@ -790,20 +776,21 @@ fn parseObject( |
| 790 | 776 | errdefer object.deinit(gpa); |
| 791 | 777 | try object.parse(gpa); |
| 792 | 778 | |
| 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 | 780 | macho.CPU_TYPE_ARM64 => .aarch64, |
| 795 | 781 | macho.CPU_TYPE_X86_64 => .x86_64, |
| 796 | 782 | else => unreachable, |
| 797 | 783 | }; |
| 798 | | error_ctx.detected_arch = cpu_arch; |
| 799 | | |
| 800 | | if (object.getPlatform()) |platform| { |
| 801 | | error_ctx.detected_platform = platform; |
| 802 | | } |
| 784 | const detected_platform = object.getPlatform(); |
| 785 | const this_cpu_arch = self.base.options.target.cpu.arch; |
| 786 | const this_platform = Platform.fromTarget(self.base.options.target); |
| 803 | 787 | |
| 804 | | if (self.base.options.target.cpu.arch != cpu_arch) return error.InvalidTarget; |
| 805 | | if (error_ctx.detected_platform) |platform| { |
| 806 | | if (!Platform.fromTarget(self.base.options.target).eqlTarget(platform)) return error.InvalidTarget; |
| 788 | if (this_cpu_arch != detected_cpu_arch or |
| 789 | (detected_platform != null and !detected_platform.?.eqlTarget(this_platform))) |
| 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 | } |
| 808 | 795 | |
| 809 | 796 | try self.objects.append(gpa, object); |
| ... | ... | @@ -816,48 +803,61 @@ pub fn parseLibrary( |
| 816 | 803 | lib: link.SystemLib, |
| 817 | 804 | must_link: bool, |
| 818 | 805 | dependent_libs: anytype, |
| 819 | | error_ctx: anytype, |
| 806 | ctx: *ParseErrorCtx, |
| 820 | 807 | ) ParseError!void { |
| 821 | 808 | const tracy = trace(@src()); |
| 822 | 809 | defer tracy.end(); |
| 823 | 810 | |
| 824 | 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 | 813 | try file.seekTo(offset); |
| 827 | 814 | |
| 828 | 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 | 817 | } else if (Dylib.isDylib(file, offset)) { |
| 831 | 818 | try self.parseDylib(file, path, offset, dependent_libs, .{ |
| 832 | 819 | .needed = lib.needed, |
| 833 | 820 | .weak = lib.weak, |
| 834 | | }, error_ctx); |
| 821 | }, ctx); |
| 835 | 822 | } else return error.UnknownFileType; |
| 836 | 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 | 825 | } else if (Dylib.isDylib(file, 0)) { |
| 839 | 826 | try self.parseDylib(file, path, 0, dependent_libs, .{ |
| 840 | 827 | .needed = lib.needed, |
| 841 | 828 | .weak = lib.weak, |
| 842 | | }, error_ctx); |
| 829 | }, ctx); |
| 843 | 830 | } else { |
| 844 | 831 | self.parseLibStub(file, path, dependent_libs, .{ |
| 845 | 832 | .needed = lib.needed, |
| 846 | 833 | .weak = lib.weak, |
| 847 | | }, error_ctx) catch |err| switch (err) { |
| 834 | }, ctx) catch |err| switch (err) { |
| 848 | 835 | error.NotLibStub, error.UnexpectedToken => return error.UnknownFileType, |
| 849 | 836 | else => |e| return e, |
| 850 | 837 | }; |
| 851 | 838 | } |
| 852 | 839 | } |
| 853 | 840 | |
| 854 | | pub fn parseFatLibrary(self: *MachO, file: std.fs.File, cpu_arch: std.Target.Cpu.Arch) ParseError!u64 { |
| 855 | | _ = self; |
| 856 | | var buffer: [2]fat.Arch = undefined; |
| 857 | | const fat_archs = try fat.parseArchs(file, &buffer); |
| 841 | pub fn parseFatLibrary( |
| 842 | self: *MachO, |
| 843 | file: std.fs.File, |
| 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 | 852 | const offset = for (fat_archs) |arch| { |
| 859 | 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 | 861 | return offset; |
| 862 | 862 | } |
| 863 | 863 | |
| ... | ... | @@ -866,7 +866,7 @@ fn parseArchive( |
| 866 | 866 | path: []const u8, |
| 867 | 867 | fat_offset: u64, |
| 868 | 868 | must_link: bool, |
| 869 | | error_ctx: anytype, |
| 869 | ctx: *ParseErrorCtx, |
| 870 | 870 | ) ParseError!void { |
| 871 | 871 | const gpa = self.base.allocator; |
| 872 | 872 | |
| ... | ... | @@ -892,20 +892,21 @@ fn parseArchive( |
| 892 | 892 | var object = try archive.parseObject(gpa, off); // TODO we are doing all this work to pull the header only! |
| 893 | 893 | defer object.deinit(gpa); |
| 894 | 894 | |
| 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 | 896 | macho.CPU_TYPE_ARM64 => .aarch64, |
| 897 | 897 | macho.CPU_TYPE_X86_64 => .x86_64, |
| 898 | 898 | else => unreachable, |
| 899 | 899 | }; |
| 900 | | error_ctx.detected_arch = cpu_arch; |
| 901 | | |
| 902 | | if (object.getPlatform()) |platform| { |
| 903 | | error_ctx.detected_platform = platform; |
| 904 | | } |
| 900 | const detected_platform = object.getPlatform(); |
| 901 | const this_cpu_arch = self.base.options.target.cpu.arch; |
| 902 | const this_platform = Platform.fromTarget(self.base.options.target); |
| 905 | 903 | |
| 906 | | if (self.base.options.target.cpu.arch != cpu_arch) return error.InvalidTarget; |
| 907 | | if (error_ctx.detected_platform) |platform| { |
| 908 | | if (!Platform.fromTarget(self.base.options.target).eqlTarget(platform)) return error.InvalidTarget; |
| 904 | if (this_cpu_arch != detected_cpu_arch or |
| 905 | (detected_platform != null and !detected_platform.?.eqlTarget(this_platform))) |
| 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 | } |
| 911 | 912 | |
| ... | ... | @@ -941,7 +942,7 @@ fn parseDylib( |
| 941 | 942 | offset: u64, |
| 942 | 943 | dependent_libs: anytype, |
| 943 | 944 | dylib_options: DylibOpts, |
| 944 | | error_ctx: anytype, |
| 945 | ctx: *ParseErrorCtx, |
| 945 | 946 | ) ParseError!void { |
| 946 | 947 | const gpa = self.base.allocator; |
| 947 | 948 | const file_stat = try file.stat(); |
| ... | ... | @@ -961,20 +962,21 @@ fn parseDylib( |
| 961 | 962 | contents, |
| 962 | 963 | ); |
| 963 | 964 | |
| 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 | 966 | macho.CPU_TYPE_ARM64 => .aarch64, |
| 966 | 967 | macho.CPU_TYPE_X86_64 => .x86_64, |
| 967 | 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); |
| 970 | 973 | |
| 971 | | if (dylib.getPlatform(contents)) |platform| { |
| 972 | | error_ctx.detected_platform = platform; |
| 973 | | } |
| 974 | | |
| 975 | | if (self.base.options.target.cpu.arch != cpu_arch) return error.InvalidTarget; |
| 976 | | if (error_ctx.detected_platform) |platform| { |
| 977 | | if (!Platform.fromTarget(self.base.options.target).eqlTarget(platform)) return error.InvalidTarget; |
| 974 | if (this_cpu_arch != detected_cpu_arch or |
| 975 | (detected_platform != null and !detected_platform.?.eqlTarget(this_platform))) |
| 976 | { |
| 977 | const platform = detected_platform orelse this_platform; |
| 978 | try ctx.detected_targets.append(try platform.allocPrintTarget(ctx.arena, detected_cpu_arch)); |
| 979 | return error.InvalidTarget; |
| 978 | 980 | } |
| 979 | 981 | |
| 980 | 982 | try self.addDylib(dylib, .{ |
| ... | ... | @@ -989,7 +991,7 @@ fn parseLibStub( |
| 989 | 991 | path: []const u8, |
| 990 | 992 | dependent_libs: anytype, |
| 991 | 993 | dylib_options: DylibOpts, |
| 992 | | error_ctx: anytype, |
| 994 | ctx: *ParseErrorCtx, |
| 993 | 995 | ) ParseError!void { |
| 994 | 996 | const gpa = self.base.allocator; |
| 995 | 997 | var lib_stub = try LibStub.loadFromFile(gpa, file); |
| ... | ... | @@ -1004,12 +1006,17 @@ fn parseLibStub( |
| 1004 | 1006 | |
| 1005 | 1007 | const first_tbd = lib_stub.inner[0]; |
| 1006 | 1008 | const targets = try first_tbd.targets(gpa); |
| 1009 | defer { |
| 1010 | for (targets) |t| gpa.free(t); |
| 1011 | gpa.free(targets); |
| 1012 | } |
| 1007 | 1013 | if (!matcher.matchesTarget(targets)) { |
| 1008 | | error_ctx.detected_stub_targets = targets; |
| 1009 | | return error.InvalidLibStubTargets; |
| 1014 | try ctx.detected_targets.ensureUnusedCapacity(targets.len); |
| 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 | } |
| 1014 | 1021 | |
| 1015 | 1022 | var dylib = Dylib{ .weak = dylib_options.weak }; |
| ... | ... | @@ -1059,7 +1066,7 @@ fn addDylib(self: *MachO, dylib: Dylib, dylib_options: DylibOpts) ParseError!voi |
| 1059 | 1066 | } |
| 1060 | 1067 | } |
| 1061 | 1068 | |
| 1062 | | pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, error_ctx: anytype) ParseError!void { |
| 1069 | pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, ctx: *ParseErrorCtx) ParseError!void { |
| 1063 | 1070 | const tracy = trace(@src()); |
| 1064 | 1071 | defer tracy.end(); |
| 1065 | 1072 | |
| ... | ... | @@ -1105,7 +1112,7 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, error_ctx: anyt |
| 1105 | 1112 | log.debug("trying dependency at fully resolved path {s}", .{full_path}); |
| 1106 | 1113 | |
| 1107 | 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 | 1116 | try file.seekTo(offset); |
| 1110 | 1117 | break :blk offset; |
| 1111 | 1118 | } else 0; |
| ... | ... | @@ -1114,12 +1121,12 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, error_ctx: anyt |
| 1114 | 1121 | try self.parseDylib(file, full_path, offset, dependent_libs, .{ |
| 1115 | 1122 | .dependent = true, |
| 1116 | 1123 | .weak = weak, |
| 1117 | | }, error_ctx); |
| 1124 | }, ctx); |
| 1118 | 1125 | } else { |
| 1119 | 1126 | self.parseLibStub(file, full_path, dependent_libs, .{ |
| 1120 | 1127 | .dependent = true, |
| 1121 | 1128 | .weak = weak, |
| 1122 | | }, error_ctx) catch |err| switch (err) { |
| 1129 | }, ctx) catch |err| switch (err) { |
| 1123 | 1130 | error.NotLibStub, error.UnexpectedToken => continue, |
| 1124 | 1131 | else => |e| return e, |
| 1125 | 1132 | }; |
| ... | ... | @@ -4845,50 +4852,40 @@ pub fn getSectionPrecedence(header: macho.section_64) u8 { |
| 4845 | 4852 | return (@as(u8, @intCast(segment_precedence)) << 4) + section_precedence; |
| 4846 | 4853 | } |
| 4847 | 4854 | |
| 4848 | | pub fn handleAndReportParseError(self: *MachO, path: []const u8, err: ParseError, parse_error_ctx: anytype) !void { |
| 4855 | pub 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 | |
| 4864 | pub fn handleAndReportParseError( |
| 4865 | self: *MachO, |
| 4866 | path: []const u8, |
| 4867 | err: ParseError, |
| 4868 | ctx: *const ParseErrorCtx, |
| 4869 | ) !void { |
| 4849 | 4870 | const cpu_arch = self.base.options.target.cpu.arch; |
| 4850 | 4871 | switch (err) { |
| 4851 | 4872 | error.DylibAlreadyExists => {}, |
| 4852 | 4873 | error.UnknownFileType => try self.reportParseError(path, "unknown file type", .{}), |
| 4853 | | error.MissingArchFatLib => try self.reportParseError( |
| 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 => { |
| 4874 | error.InvalidTarget => { |
| 4873 | 4875 | var targets_string = std.ArrayList(u8).init(self.base.allocator); |
| 4874 | 4876 | defer targets_string.deinit(); |
| 4875 | 4877 | try targets_string.writer().writeAll("("); |
| 4876 | | for (parse_error_ctx.detected_stub_targets) |t| { |
| 4878 | for (ctx.detected_targets.items) |t| { |
| 4877 | 4879 | try targets_string.writer().print("{s}, ", .{t}); |
| 4878 | 4880 | } |
| 4879 | 4881 | try targets_string.resize(targets_string.items.len - 2); |
| 4880 | 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 | 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 | | path, |
| 4889 | | "parsing positional argument failed with error '{s}'", |
| 4890 | | .{@errorName(e)}, |
| 4891 | | ), |
| 4888 | else => |e| try self.reportParseError(path, "{s}: parsing object failed", .{@errorName(e)}), |
| 4892 | 4889 | } |
| 4893 | 4890 | } |
| 4894 | 4891 | |