authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-28 16:19:42+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-29 11:40:20+02:00
log1820aed786a2bb61a6526873e7a8ddf47d45e9fd
tree3abf13999c01f19669632c0eef3a83ff595d5e8c
parent68dc1a3e3fc8ab739cb34ed536c71a02727b3825

macho: convert log.err when CPU arch is mismatched into actual errors


2 files changed, 118 insertions(+), 99 deletions(-)

src/link/MachO.zig+76-88
......@@ -396,11 +396,17 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
396396 self.dylibs_map.clearRetainingCapacity();
397397 self.referenced_dylibs.clearRetainingCapacity();
398398
399 const cpu_arch = self.base.options.target.cpu.arch;
399400 var dependent_libs = std.fifo.LinearFifo(struct {
400401 id: Dylib.Id,
401402 parent: u16,
402403 }, .Dynamic).init(arena);
403404
405 var parse_error_ctx: union {
406 none: void,
407 detected_arch: std.Target.Cpu.Arch,
408 } = .{ .none = {} };
409
404410 for (libs.keys(), libs.values()) |path, lib| {
405411 const in_file = try std.fs.cwd().openFile(path, .{});
406412 defer in_file.close();
......@@ -411,15 +417,28 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
411417 lib,
412418 false,
413419 &dependent_libs,
414 &self.base.options,
415 ) catch |err| {
416 // TODO convert to error
417 log.err("{s}: parsing library failed with err {s}", .{ path, @errorName(err) });
418 continue;
420 &parse_error_ctx,
421 ) catch |err| switch (err) {
422 error.UnknownFileType => try self.reportParseError(path, "unknown file type", .{}),
423 error.MissingArchFatLib => try self.reportParseError(
424 path,
425 "missing architecture in universal file, expected '{s}'",
426 .{@tagName(cpu_arch)},
427 ),
428 error.InvalidArch => try self.reportParseError(
429 path,
430 "invalid architecture '{s}', expected '{s}'",
431 .{ @tagName(parse_error_ctx.detected_arch), @tagName(cpu_arch) },
432 ),
433 else => |e| try self.reportParseError(
434 path,
435 "parsing library failed with error '{s}'",
436 .{@errorName(e)},
437 ),
419438 };
420439 }
421440
422 self.parseDependentLibs(&dependent_libs, &self.base.options) catch |err| {
441 self.parseDependentLibs(&dependent_libs, &parse_error_ctx) catch |err| {
423442 // TODO convert to error
424443 log.err("parsing dependent libraries failed with err {s}", .{@errorName(err)});
425444 };
......@@ -710,19 +729,19 @@ pub fn parsePositional(
710729 path: []const u8,
711730 must_link: bool,
712731 dependent_libs: anytype,
713 link_options: *const link.Options,
732 error_ctx: anytype,
714733) !void {
715734 const tracy = trace(@src());
716735 defer tracy.end();
717736
718737 if (Object.isObject(file)) {
719 try self.parseObject(file, path, link_options);
738 try self.parseObject(file, path, error_ctx);
720739 } else {
721740 try self.parseLibrary(file, path, .{
722741 .path = null,
723742 .needed = false,
724743 .weak = false,
725 }, must_link, dependent_libs, link_options);
744 }, must_link, dependent_libs, error_ctx);
726745 }
727746}
728747
......@@ -730,7 +749,7 @@ fn parseObject(
730749 self: *MachO,
731750 file: std.fs.File,
732751 path: []const u8,
733 link_options: *const link.Options,
752 error_ctx: anytype,
734753) !void {
735754 const tracy = trace(@src());
736755 defer tracy.end();
......@@ -758,15 +777,11 @@ fn parseObject(
758777 macho.CPU_TYPE_X86_64 => .x86_64,
759778 else => unreachable,
760779 };
761 const self_cpu_arch = link_options.target.cpu.arch;
780 const self_cpu_arch = self.base.options.target.cpu.arch;
762781
763782 if (self_cpu_arch != cpu_arch) {
764 // TODO convert into an error
765 log.err("{s}: invalid architecture '{s}', expected '{s}'", .{
766 path,
767 @tagName(cpu_arch),
768 @tagName(self_cpu_arch),
769 });
783 error_ctx.* = .{ .detected_arch = cpu_arch };
784 return error.InvalidArch;
770785 }
771786}
772787
......@@ -777,70 +792,50 @@ pub fn parseLibrary(
777792 lib: link.SystemLib,
778793 must_link: bool,
779794 dependent_libs: anytype,
780 link_options: *const link.Options,
795 error_ctx: anytype,
781796) !void {
782797 const tracy = trace(@src());
783798 defer tracy.end();
784799
785 const cpu_arch = link_options.target.cpu.arch;
800 const cpu_arch = self.base.options.target.cpu.arch;
786801
787802 if (fat.isFatLibrary(file)) {
788 const offset = self.parseFatLibrary(file, path, cpu_arch) catch |err| switch (err) {
789 error.MissingArch => return,
790 else => |e| return e,
791 };
803 const offset = try self.parseFatLibrary(file, cpu_arch);
792804 try file.seekTo(offset);
793805
794806 if (Archive.isArchive(file, offset)) {
795 try self.parseArchive(path, offset, must_link, cpu_arch);
807 try self.parseArchive(path, offset, must_link, cpu_arch, error_ctx);
796808 } else if (Dylib.isDylib(file, offset)) {
797 try self.parseDylib(file, path, offset, dependent_libs, link_options, .{
809 try self.parseDylib(file, path, offset, dependent_libs, .{
798810 .needed = lib.needed,
799811 .weak = lib.weak,
800 });
801 } else {
802 // TODO convert into an error
803 log.err("{s}: unknown file type", .{path});
804 return;
805 }
812 }, error_ctx);
813 } else return error.UnknownFileType;
806814 } else if (Archive.isArchive(file, 0)) {
807 try self.parseArchive(path, 0, must_link, cpu_arch);
815 try self.parseArchive(path, 0, must_link, cpu_arch, error_ctx);
808816 } else if (Dylib.isDylib(file, 0)) {
809 try self.parseDylib(file, path, 0, dependent_libs, link_options, .{
817 try self.parseDylib(file, path, 0, dependent_libs, .{
810818 .needed = lib.needed,
811819 .weak = lib.weak,
812 });
820 }, error_ctx);
813821 } else {
814 self.parseLibStub(file, path, dependent_libs, link_options, .{
822 self.parseLibStub(file, path, dependent_libs, .{
815823 .needed = lib.needed,
816824 .weak = lib.weak,
817825 }) catch |err| switch (err) {
818 error.NotLibStub, error.UnexpectedToken => {
819 // TODO convert into an error
820 log.err("{s}: unknown file type", .{path});
821 return;
822 },
826 error.NotLibStub, error.UnexpectedToken => return error.UnknownFileType,
823827 else => |e| return e,
824828 };
825829 }
826830}
827831
828pub fn parseFatLibrary(
829 self: *MachO,
830 file: std.fs.File,
831 path: []const u8,
832 cpu_arch: std.Target.Cpu.Arch,
833) !u64 {
832pub fn parseFatLibrary(self: *MachO, file: std.fs.File, cpu_arch: std.Target.Cpu.Arch) !u64 {
834833 _ = self;
835834 var buffer: [2]fat.Arch = undefined;
836835 const fat_archs = try fat.parseArchs(file, &buffer);
837836 const offset = for (fat_archs) |arch| {
838837 if (arch.tag == cpu_arch) break arch.offset;
839 } else {
840 // TODO convert into an error
841 log.err("{s}: missing arch in universal file: expected {s}", .{ path, @tagName(cpu_arch) });
842 return error.MissingArch;
843 };
838 } else return error.MissingArchFatLib;
844839 return offset;
845840}
846841
......@@ -850,13 +845,13 @@ fn parseArchive(
850845 fat_offset: u64,
851846 must_link: bool,
852847 cpu_arch: std.Target.Cpu.Arch,
848 error_ctx: anytype,
853849) !void {
854850 const gpa = self.base.allocator;
855851
856852 // We take ownership of the file so that we can store it for the duration of symbol resolution.
857853 // TODO we shouldn't need to do that and could pre-parse the archive like we do for zld/ELF?
858854 const file = try std.fs.cwd().openFile(path, .{});
859 errdefer file.close();
860855 try file.seekTo(fat_offset);
861856
862857 var archive = Archive{
......@@ -882,13 +877,8 @@ fn parseArchive(
882877 else => unreachable,
883878 };
884879 if (cpu_arch != parsed_cpu_arch) {
885 // TODO convert into an error
886 log.err("{s}: invalid architecture in archive '{s}', expected '{s}'", .{
887 path,
888 @tagName(parsed_cpu_arch),
889 @tagName(cpu_arch),
890 });
891 return error.MissingArch;
880 error_ctx.* = .{ .detected_arch = parsed_cpu_arch };
881 return error.InvalidArch;
892882 }
893883 }
894884
......@@ -923,11 +913,11 @@ fn parseDylib(
923913 path: []const u8,
924914 offset: u64,
925915 dependent_libs: anytype,
926 link_options: *const link.Options,
927916 dylib_options: DylibOpts,
917 error_ctx: anytype,
928918) !void {
929919 const gpa = self.base.allocator;
930 const self_cpu_arch = link_options.target.cpu.arch;
920 const self_cpu_arch = self.base.options.target.cpu.arch;
931921
932922 const file_stat = try file.stat();
933923 const file_size = math.cast(usize, file_stat.size - offset) orelse return error.Overflow;
......@@ -952,18 +942,13 @@ fn parseDylib(
952942 else => unreachable,
953943 };
954944 if (self_cpu_arch != cpu_arch) {
955 // TODO convert into an error
956 log.err("{s}: invalid architecture '{s}', expected '{s}'", .{
957 path,
958 @tagName(cpu_arch),
959 @tagName(self_cpu_arch),
960 });
961 return error.MissingArch;
945 error_ctx.* = .{ .detected_arch = cpu_arch };
946 return error.InvalidArch;
962947 }
963948
964949 // TODO verify platform
965950
966 self.addDylib(dylib, link_options, .{
951 self.addDylib(dylib, .{
967952 .needed = dylib_options.needed,
968953 .weak = dylib_options.weak,
969954 }) catch |err| switch (err) {
......@@ -977,7 +962,6 @@ fn parseLibStub(
977962 file: std.fs.File,
978963 path: []const u8,
979964 dependent_libs: anytype,
980 link_options: *const link.Options,
981965 dylib_options: DylibOpts,
982966) !void {
983967 const gpa = self.base.allocator;
......@@ -993,14 +977,14 @@ fn parseLibStub(
993977
994978 try dylib.parseFromStub(
995979 gpa,
996 link_options.target,
980 self.base.options.target,
997981 lib_stub,
998982 @intCast(self.dylibs.items.len), // TODO defer it till later
999983 dependent_libs,
1000984 path,
1001985 );
1002986
1003 self.addDylib(dylib, link_options, .{
987 self.addDylib(dylib, .{
1004988 .needed = dylib_options.needed,
1005989 .weak = dylib_options.weak,
1006990 }) catch |err| switch (err) {
......@@ -1009,12 +993,7 @@ fn parseLibStub(
1009993 };
1010994}
1011995
1012fn addDylib(
1013 self: *MachO,
1014 dylib: Dylib,
1015 link_options: *const link.Options,
1016 dylib_options: DylibOpts,
1017) !void {
996fn addDylib(self: *MachO, dylib: Dylib, dylib_options: DylibOpts) !void {
1018997 if (dylib_options.id) |id| {
1019998 if (dylib.id.?.current_version < id.compatibility_version) {
1020999 // TODO convert into an error
......@@ -1034,7 +1013,7 @@ fn addDylib(
10341013 try self.dylibs.append(gpa, dylib);
10351014
10361015 const should_link_dylib_even_if_unreachable = blk: {
1037 if (link_options.dead_strip_dylibs and !dylib_options.needed) break :blk false;
1016 if (self.base.options.dead_strip_dylibs and !dylib_options.needed) break :blk false;
10381017 break :blk !(dylib_options.dependent or self.referenced_dylibs.contains(gop.value_ptr.*));
10391018 };
10401019
......@@ -1043,7 +1022,7 @@ fn addDylib(
10431022 }
10441023}
10451024
1046pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, link_options: *const link.Options) !void {
1025pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, error_ctx: anytype) !void {
10471026 const tracy = trace(@src());
10481027 defer tracy.end();
10491028
......@@ -1075,7 +1054,7 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, link_options: *
10751054
10761055 for (&[_][]const u8{ extension, ".tbd" }) |ext| {
10771056 const with_ext = try std.fmt.allocPrint(arena, "{s}{s}", .{ without_ext, ext });
1078 const full_path = if (link_options.sysroot) |root|
1057 const full_path = if (self.base.options.sysroot) |root|
10791058 try fs.path.join(arena, &.{ root, with_ext })
10801059 else
10811060 with_ext;
......@@ -1089,21 +1068,18 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, link_options: *
10891068 log.debug("trying dependency at fully resolved path {s}", .{full_path});
10901069
10911070 const offset: u64 = if (fat.isFatLibrary(file)) blk: {
1092 const offset = self.parseFatLibrary(file, full_path, link_options.target.cpu.arch) catch |err| switch (err) {
1093 error.MissingArch => break,
1094 else => |e| return e,
1095 };
1071 const offset = try self.parseFatLibrary(file, self.base.options.target.cpu.arch);
10961072 try file.seekTo(offset);
10971073 break :blk offset;
10981074 } else 0;
10991075
11001076 if (Dylib.isDylib(file, offset)) {
1101 try self.parseDylib(file, full_path, offset, dependent_libs, link_options, .{
1077 try self.parseDylib(file, full_path, offset, dependent_libs, .{
11021078 .dependent = true,
11031079 .weak = weak,
1104 });
1080 }, error_ctx);
11051081 } else {
1106 self.parseLibStub(file, full_path, dependent_libs, link_options, .{
1082 self.parseLibStub(file, full_path, dependent_libs, .{
11071083 .dependent = true,
11081084 .weak = weak,
11091085 }) catch |err| switch (err) {
......@@ -4836,6 +4812,18 @@ pub fn getSectionPrecedence(header: macho.section_64) u8 {
48364812 return (@as(u8, @intCast(segment_precedence)) << 4) + section_precedence;
48374813}
48384814
4815pub fn reportParseError(self: *MachO, path: []const u8, comptime format: []const u8, args: anytype) !void {
4816 const gpa = self.base.allocator;
4817 try self.misc_errors.ensureUnusedCapacity(gpa, 1);
4818 var notes = try gpa.alloc(File.ErrorMsg, 1);
4819 errdefer gpa.free(notes);
4820 notes[0] = .{ .msg = try std.fmt.allocPrint(gpa, "while parsing {s}", .{path}) };
4821 self.misc_errors.appendAssumeCapacity(.{
4822 .msg = try std.fmt.allocPrint(gpa, format, args),
4823 .notes = notes,
4824 });
4825}
4826
48394827pub fn reportUndefined(self: *MachO) error{OutOfMemory}!void {
48404828 const gpa = self.base.allocator;
48414829 const count = self.unresolved.count();
src/link/MachO/zld.zig+42-11
......@@ -345,6 +345,11 @@ pub fn linkWithZld(
345345 parent: u16,
346346 }, .Dynamic).init(arena);
347347
348 var parse_error_ctx: union {
349 none: void,
350 detected_arch: std.Target.Cpu.Arch,
351 } = .{ .none = {} };
352
348353 for (positionals.items) |obj| {
349354 const in_file = try std.fs.cwd().openFile(obj.path, .{});
350355 defer in_file.close();
......@@ -354,11 +359,24 @@ pub fn linkWithZld(
354359 obj.path,
355360 obj.must_link,
356361 &dependent_libs,
357 options,
358 ) catch |err| {
359 // TODO convert to error
360 log.err("{s}: parsing positional failed with err {s}", .{ obj.path, @errorName(err) });
361 continue;
362 &parse_error_ctx,
363 ) catch |err| switch (err) {
364 error.UnknownFileType => try macho_file.reportParseError(obj.path, "unknown file type", .{}),
365 error.MissingArchFatLib => try macho_file.reportParseError(
366 obj.path,
367 "missing architecture in universal file, expected '{s}'",
368 .{@tagName(cpu_arch)},
369 ),
370 error.InvalidArch => try macho_file.reportParseError(
371 obj.path,
372 "invalid architecture '{s}', expected '{s}'",
373 .{ @tagName(parse_error_ctx.detected_arch), @tagName(cpu_arch) },
374 ),
375 else => |e| try macho_file.reportParseError(
376 obj.path,
377 "parsing positional argument failed with error '{s}'",
378 .{@errorName(e)},
379 ),
362380 };
363381 }
364382
......@@ -372,15 +390,28 @@ pub fn linkWithZld(
372390 lib,
373391 false,
374392 &dependent_libs,
375 options,
376 ) catch |err| {
377 // TODO convert to error
378 log.err("{s}: parsing library failed with err {s}", .{ path, @errorName(err) });
379 continue;
393 &parse_error_ctx,
394 ) catch |err| switch (err) {
395 error.UnknownFileType => try macho_file.reportParseError(path, "unknown file type", .{}),
396 error.MissingArchFatLib => try macho_file.reportParseError(
397 path,
398 "missing architecture in universal file, expected '{s}'",
399 .{@tagName(cpu_arch)},
400 ),
401 error.InvalidArch => try macho_file.reportParseError(
402 path,
403 "invalid architecture '{s}', expected '{s}'",
404 .{ @tagName(parse_error_ctx.detected_arch), @tagName(cpu_arch) },
405 ),
406 else => |e| try macho_file.reportParseError(
407 path,
408 "parsing library failed with error '{s}'",
409 .{@errorName(e)},
410 ),
380411 };
381412 }
382413
383 macho_file.parseDependentLibs(&dependent_libs, options) catch |err| {
414 macho_file.parseDependentLibs(&dependent_libs, &parse_error_ctx) catch |err| {
384415 // TODO convert to error
385416 log.err("parsing dependent libraries failed with err {s}", .{@errorName(err)});
386417 };