| author | |
| committer | |
| log | 066864a0bf59bc1a926412b3c6e4d2d0c65e5642 |
| tree | f9336243c45e2209205baa3bf48ae9836e04ee8b |
| parent | b428612a202a76f7a0aee18bde00c104753f3e60 |
12 files changed, 433 insertions(+), 518 deletions(-)
lib/compiler/build_runner.zig+5| ... | @@ -38,6 +38,10 @@ pub fn main() !void { | ... | @@ -38,6 +38,10 @@ pub fn main() !void { |
| 38 | 38 | ||
| 39 | const args = try process.argsAlloc(arena); | 39 | const args = try process.argsAlloc(arena); |
| 40 | 40 | ||
| 41 | var threaded: std.Io.Threaded = .init(gpa); | ||
| 42 | defer threaded.deinit(); | ||
| 43 | const io = threaded.io(); | ||
| 44 | |||
| 41 | // skip my own exe name | 45 | // skip my own exe name |
| 42 | var arg_idx: usize = 1; | 46 | var arg_idx: usize = 1; |
| 43 | 47 | ||
| ... | @@ -68,6 +72,7 @@ pub fn main() !void { | ... | @@ -68,6 +72,7 @@ pub fn main() !void { |
| 68 | }; | 72 | }; |
| 69 | 73 | ||
| 70 | var graph: std.Build.Graph = .{ | 74 | var graph: std.Build.Graph = .{ |
| 75 | .io = io, | ||
| 71 | .arena = arena, | 76 | .arena = arena, |
| 72 | .cache = .{ | 77 | .cache = .{ |
| 73 | .gpa = arena, | 78 | .gpa = arena, |
lib/std/Build.zig+6-2| ... | @@ -1,5 +1,7 @@ | ... | @@ -1,5 +1,7 @@ |
| 1 | const std = @import("std.zig"); | ||
| 2 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | |||
| 3 | const std = @import("std.zig"); | ||
| 4 | const Io = std.Io; | ||
| 3 | const fs = std.fs; | 5 | const fs = std.fs; |
| 4 | const mem = std.mem; | 6 | const mem = std.mem; |
| 5 | const debug = std.debug; | 7 | const debug = std.debug; |
| ... | @@ -110,6 +112,7 @@ pub const ReleaseMode = enum { | ... | @@ -110,6 +112,7 @@ pub const ReleaseMode = enum { |
| 110 | /// Shared state among all Build instances. | 112 | /// Shared state among all Build instances. |
| 111 | /// Settings that are here rather than in Build are not configurable per-package. | 113 | /// Settings that are here rather than in Build are not configurable per-package. |
| 112 | pub const Graph = struct { | 114 | pub const Graph = struct { |
| 115 | io: Io, | ||
| 113 | arena: Allocator, | 116 | arena: Allocator, |
| 114 | system_library_options: std.StringArrayHashMapUnmanaged(SystemLibraryMode) = .empty, | 117 | system_library_options: std.StringArrayHashMapUnmanaged(SystemLibraryMode) = .empty, |
| 115 | system_package_mode: bool = false, | 118 | system_package_mode: bool = false, |
| ... | @@ -2666,9 +2669,10 @@ pub fn resolveTargetQuery(b: *Build, query: Target.Query) ResolvedTarget { | ... | @@ -2666,9 +2669,10 @@ pub fn resolveTargetQuery(b: *Build, query: Target.Query) ResolvedTarget { |
| 2666 | // Hot path. This is faster than querying the native CPU and OS again. | 2669 | // Hot path. This is faster than querying the native CPU and OS again. |
| 2667 | return b.graph.host; | 2670 | return b.graph.host; |
| 2668 | } | 2671 | } |
| 2672 | const io = b.graph.io; | ||
| 2669 | return .{ | 2673 | return .{ |
| 2670 | .query = query, | 2674 | .query = query, |
| 2671 | .result = std.zig.system.resolveTargetQuery(query) catch | 2675 | .result = std.zig.system.resolveTargetQuery(io, query) catch |
| 2672 | @panic("unable to resolve target query"), | 2676 | @panic("unable to resolve target query"), |
| 2673 | }; | 2677 | }; |
| 2674 | } | 2678 | } |
lib/std/Build/Step/Options.zig+3-1| ... | @@ -532,6 +532,8 @@ const Arg = struct { | ... | @@ -532,6 +532,8 @@ const Arg = struct { |
| 532 | test Options { | 532 | test Options { |
| 533 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 533 | if (builtin.os.tag == .wasi) return error.SkipZigTest; |
| 534 | 534 | ||
| 535 | const io = std.testing.io; | ||
| 536 | |||
| 535 | var arena = std.heap.ArenaAllocator.init(std.testing.allocator); | 537 | var arena = std.heap.ArenaAllocator.init(std.testing.allocator); |
| 536 | defer arena.deinit(); | 538 | defer arena.deinit(); |
| 537 | 539 | ||
| ... | @@ -546,7 +548,7 @@ test Options { | ... | @@ -546,7 +548,7 @@ test Options { |
| 546 | .global_cache_root = .{ .path = "test", .handle = std.fs.cwd() }, | 548 | .global_cache_root = .{ .path = "test", .handle = std.fs.cwd() }, |
| 547 | .host = .{ | 549 | .host = .{ |
| 548 | .query = .{}, | 550 | .query = .{}, |
| 549 | .result = try std.zig.system.resolveTargetQuery(.{}), | 551 | .result = try std.zig.system.resolveTargetQuery(io, .{}), |
| 550 | }, | 552 | }, |
| 551 | .zig_lib_directory = std.Build.Cache.Directory.cwd(), | 553 | .zig_lib_directory = std.Build.Cache.Directory.cwd(), |
| 552 | .time_report = false, | 554 | .time_report = false, |
lib/std/Build/WebServer.zig+2-1| ... | @@ -516,6 +516,7 @@ pub fn serveTarFile( | ... | @@ -516,6 +516,7 @@ pub fn serveTarFile( |
| 516 | } | 516 | } |
| 517 | 517 | ||
| 518 | fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.OptimizeMode) !Cache.Path { | 518 | fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.OptimizeMode) !Cache.Path { |
| 519 | const io = ws.graph.io; | ||
| 519 | const root_name = "build-web"; | 520 | const root_name = "build-web"; |
| 520 | const arch_os_abi = "wasm32-freestanding"; | 521 | const arch_os_abi = "wasm32-freestanding"; |
| 521 | const cpu_features = "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext"; | 522 | const cpu_features = "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext"; |
| ... | @@ -659,7 +660,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim | ... | @@ -659,7 +660,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim |
| 659 | }; | 660 | }; |
| 660 | const bin_name = try std.zig.binNameAlloc(arena, .{ | 661 | const bin_name = try std.zig.binNameAlloc(arena, .{ |
| 661 | .root_name = root_name, | 662 | .root_name = root_name, |
| 662 | .target = &(std.zig.system.resolveTargetQuery(std.Build.parseTargetQuery(.{ | 663 | .target = &(std.zig.system.resolveTargetQuery(io, std.Build.parseTargetQuery(.{ |
| 663 | .arch_os_abi = arch_os_abi, | 664 | .arch_os_abi = arch_os_abi, |
| 664 | .cpu_features = cpu_features, | 665 | .cpu_features = cpu_features, |
| 665 | }) catch unreachable) catch unreachable), | 666 | }) catch unreachable) catch unreachable), |
lib/std/Io.zig+3-3| ... | @@ -738,9 +738,9 @@ pub const Timestamp = struct { | ... | @@ -738,9 +738,9 @@ pub const Timestamp = struct { |
| 738 | /// * On Linux, corresponds `CLOCK_MONOTONIC`. | 738 | /// * On Linux, corresponds `CLOCK_MONOTONIC`. |
| 739 | /// * On macOS, corresponds to `CLOCK_UPTIME_RAW`. | 739 | /// * On macOS, corresponds to `CLOCK_UPTIME_RAW`. |
| 740 | awake, | 740 | awake, |
| 741 | /// Identical to `awake` except it expresses intent to include time | 741 | /// Identical to `awake` except it expresses intent to **include time |
| 742 | /// that the system is suspended, however, it may be implemented | 742 | /// that the system is suspended**, however, due to limitations it may |
| 743 | /// identically to `awake`. | 743 | /// behave identically to `awake`. |
| 744 | /// | 744 | /// |
| 745 | /// * On Linux, corresponds `CLOCK_BOOTTIME`. | 745 | /// * On Linux, corresponds `CLOCK_BOOTTIME`. |
| 746 | /// * On macOS, corresponds to `CLOCK_MONOTONIC_RAW`. | 746 | /// * On macOS, corresponds to `CLOCK_MONOTONIC_RAW`. |
lib/std/Io/Threaded.zig+5-8| ... | @@ -1054,7 +1054,7 @@ fn nowWasi(userdata: ?*anyopaque, clock: Io.Timestamp.Clock) Io.Timestamp.Error! | ... | @@ -1054,7 +1054,7 @@ fn nowWasi(userdata: ?*anyopaque, clock: Io.Timestamp.Clock) Io.Timestamp.Error! |
| 1054 | fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { | 1054 | fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 1055 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 1055 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1056 | const clock_id: posix.clockid_t = clockToPosix(switch (timeout) { | 1056 | const clock_id: posix.clockid_t = clockToPosix(switch (timeout) { |
| 1057 | .none => .monotonic, | 1057 | .none => .awake, |
| 1058 | .duration => |d| d.clock, | 1058 | .duration => |d| d.clock, |
| 1059 | .deadline => |d| d.clock, | 1059 | .deadline => |d| d.clock, |
| 1060 | }); | 1060 | }); |
| ... | @@ -1087,7 +1087,6 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { | ... | @@ -1087,7 +1087,6 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 1087 | const ms = ms: { | 1087 | const ms = ms: { |
| 1088 | const duration_and_clock = (try timeout.toDurationFromNow(pool.io())) orelse | 1088 | const duration_and_clock = (try timeout.toDurationFromNow(pool.io())) orelse |
| 1089 | break :ms std.math.maxInt(windows.DWORD); | 1089 | break :ms std.math.maxInt(windows.DWORD); |
| 1090 | if (duration_and_clock.clock != .monotonic) return error.UnsupportedClock; | ||
| 1091 | break :ms std.math.lossyCast(windows.DWORD, duration_and_clock.duration.toMilliseconds()); | 1090 | break :ms std.math.lossyCast(windows.DWORD, duration_and_clock.duration.toMilliseconds()); |
| 1092 | }; | 1091 | }; |
| 1093 | windows.kernel32.Sleep(ms); | 1092 | windows.kernel32.Sleep(ms); |
| ... | @@ -1132,8 +1131,6 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { | ... | @@ -1132,8 +1131,6 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 1132 | .sec = std.math.maxInt(sec_type), | 1131 | .sec = std.math.maxInt(sec_type), |
| 1133 | .nsec = std.math.maxInt(nsec_type), | 1132 | .nsec = std.math.maxInt(nsec_type), |
| 1134 | }; | 1133 | }; |
| 1135 | // TODO check which clock nanosleep uses on this host | ||
| 1136 | // and return error.UnsupportedClock if it does not match | ||
| 1137 | const ns = d.duration.nanoseconds; | 1134 | const ns = d.duration.nanoseconds; |
| 1138 | break :t .{ | 1135 | break :t .{ |
| 1139 | .sec = @intCast(@divFloor(ns, std.time.ns_per_s)), | 1136 | .sec = @intCast(@divFloor(ns, std.time.ns_per_s)), |
| ... | @@ -2046,9 +2043,9 @@ fn clockToPosix(clock: Io.Timestamp.Clock) posix.clockid_t { | ... | @@ -2046,9 +2043,9 @@ fn clockToPosix(clock: Io.Timestamp.Clock) posix.clockid_t { |
| 2046 | fn clockToWasi(clock: Io.Timestamp.Clock) std.os.wasi.clockid_t { | 2043 | fn clockToWasi(clock: Io.Timestamp.Clock) std.os.wasi.clockid_t { |
| 2047 | return switch (clock) { | 2044 | return switch (clock) { |
| 2048 | .realtime => .REALTIME, | 2045 | .realtime => .REALTIME, |
| 2049 | .monotonic => .MONOTONIC, | 2046 | .awake => .MONOTONIC, |
| 2050 | .uptime => .MONOTONIC, | 2047 | .boot => .MONOTONIC, |
| 2051 | .process_cputime_id => .PROCESS_CPUTIME_ID, | 2048 | .cpu_process => .PROCESS_CPUTIME_ID, |
| 2052 | .thread_cputime_id => .THREAD_CPUTIME_ID, | 2049 | .cpu_thread => .THREAD_CPUTIME_ID, |
| 2053 | }; | 2050 | }; |
| 2054 | } | 2051 | } |
lib/std/Io/net.zig+1-1| ... | @@ -228,7 +228,7 @@ pub const IpAddress = union(enum) { | ... | @@ -228,7 +228,7 @@ pub const IpAddress = union(enum) { |
| 228 | /// | 228 | /// |
| 229 | /// One bound `Socket` can be used to receive messages from multiple | 229 | /// One bound `Socket` can be used to receive messages from multiple |
| 230 | /// different addresses. | 230 | /// different addresses. |
| 231 | pub fn bind(address: IpAddress, io: Io, options: BindOptions) BindError!Socket { | 231 | pub fn bind(address: *const IpAddress, io: Io, options: BindOptions) BindError!Socket { |
| 232 | return io.vtable.ipBind(io.userdata, address, options); | 232 | return io.vtable.ipBind(io.userdata, address, options); |
| 233 | } | 233 | } |
| 234 | 234 |
lib/std/Target/Query.zig+7-5| ... | @@ -612,6 +612,8 @@ fn versionEqualOpt(a: ?SemanticVersion, b: ?SemanticVersion) bool { | ... | @@ -612,6 +612,8 @@ fn versionEqualOpt(a: ?SemanticVersion, b: ?SemanticVersion) bool { |
| 612 | } | 612 | } |
| 613 | 613 | ||
| 614 | test parse { | 614 | test parse { |
| 615 | const io = std.testing.io; | ||
| 616 | |||
| 615 | if (builtin.target.isGnuLibC()) { | 617 | if (builtin.target.isGnuLibC()) { |
| 616 | var query = try Query.parse(.{}); | 618 | var query = try Query.parse(.{}); |
| 617 | query.setGnuLibCVersion(2, 1, 1); | 619 | query.setGnuLibCVersion(2, 1, 1); |
| ... | @@ -654,7 +656,7 @@ test parse { | ... | @@ -654,7 +656,7 @@ test parse { |
| 654 | .arch_os_abi = "x86_64-linux-gnu", | 656 | .arch_os_abi = "x86_64-linux-gnu", |
| 655 | .cpu_features = "x86_64-sse-sse2-avx-cx8", | 657 | .cpu_features = "x86_64-sse-sse2-avx-cx8", |
| 656 | }); | 658 | }); |
| 657 | const target = try std.zig.system.resolveTargetQuery(query); | 659 | const target = try std.zig.system.resolveTargetQuery(io, query); |
| 658 | 660 | ||
| 659 | try std.testing.expect(target.os.tag == .linux); | 661 | try std.testing.expect(target.os.tag == .linux); |
| 660 | try std.testing.expect(target.abi == .gnu); | 662 | try std.testing.expect(target.abi == .gnu); |
| ... | @@ -679,7 +681,7 @@ test parse { | ... | @@ -679,7 +681,7 @@ test parse { |
| 679 | .arch_os_abi = "arm-linux-musleabihf", | 681 | .arch_os_abi = "arm-linux-musleabihf", |
| 680 | .cpu_features = "generic+v8a", | 682 | .cpu_features = "generic+v8a", |
| 681 | }); | 683 | }); |
| 682 | const target = try std.zig.system.resolveTargetQuery(query); | 684 | const target = try std.zig.system.resolveTargetQuery(io, query); |
| 683 | 685 | ||
| 684 | try std.testing.expect(target.os.tag == .linux); | 686 | try std.testing.expect(target.os.tag == .linux); |
| 685 | try std.testing.expect(target.abi == .musleabihf); | 687 | try std.testing.expect(target.abi == .musleabihf); |
| ... | @@ -696,7 +698,7 @@ test parse { | ... | @@ -696,7 +698,7 @@ test parse { |
| 696 | .arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27", | 698 | .arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27", |
| 697 | .cpu_features = "generic+v8a", | 699 | .cpu_features = "generic+v8a", |
| 698 | }); | 700 | }); |
| 699 | const target = try std.zig.system.resolveTargetQuery(query); | 701 | const target = try std.zig.system.resolveTargetQuery(io, query); |
| 700 | 702 | ||
| 701 | try std.testing.expect(target.cpu.arch == .aarch64); | 703 | try std.testing.expect(target.cpu.arch == .aarch64); |
| 702 | try std.testing.expect(target.os.tag == .linux); | 704 | try std.testing.expect(target.os.tag == .linux); |
| ... | @@ -719,7 +721,7 @@ test parse { | ... | @@ -719,7 +721,7 @@ test parse { |
| 719 | const query = try Query.parse(.{ | 721 | const query = try Query.parse(.{ |
| 720 | .arch_os_abi = "aarch64-linux.3.10...4.4.1-android.30", | 722 | .arch_os_abi = "aarch64-linux.3.10...4.4.1-android.30", |
| 721 | }); | 723 | }); |
| 722 | const target = try std.zig.system.resolveTargetQuery(query); | 724 | const target = try std.zig.system.resolveTargetQuery(io, query); |
| 723 | 725 | ||
| 724 | try std.testing.expect(target.cpu.arch == .aarch64); | 726 | try std.testing.expect(target.cpu.arch == .aarch64); |
| 725 | try std.testing.expect(target.os.tag == .linux); | 727 | try std.testing.expect(target.os.tag == .linux); |
| ... | @@ -740,7 +742,7 @@ test parse { | ... | @@ -740,7 +742,7 @@ test parse { |
| 740 | const query = try Query.parse(.{ | 742 | const query = try Query.parse(.{ |
| 741 | .arch_os_abi = "x86-windows.xp...win8-msvc", | 743 | .arch_os_abi = "x86-windows.xp...win8-msvc", |
| 742 | }); | 744 | }); |
| 743 | const target = try std.zig.system.resolveTargetQuery(query); | 745 | const target = try std.zig.system.resolveTargetQuery(io, query); |
| 744 | 746 | ||
| 745 | try std.testing.expect(target.cpu.arch == .x86); | 747 | try std.testing.expect(target.cpu.arch == .x86); |
| 746 | try std.testing.expect(target.os.tag == .windows); | 748 | try std.testing.expect(target.os.tag == .windows); |
lib/std/elf.zig+121-45| ... | @@ -1,9 +1,11 @@ | ... | @@ -1,9 +1,11 @@ |
| 1 | //! Executable and Linkable Format. | 1 | //! Executable and Linkable Format. |
| 2 | 2 | ||
| 3 | const std = @import("std.zig"); | 3 | const std = @import("std.zig"); |
| 4 | const Io = std.Io; | ||
| 4 | const math = std.math; | 5 | const math = std.math; |
| 5 | const mem = std.mem; | 6 | const mem = std.mem; |
| 6 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 8 | const Endian = std.builtin.Endian; | ||
| 7 | const native_endian = @import("builtin").target.cpu.arch.endian(); | 9 | const native_endian = @import("builtin").target.cpu.arch.endian(); |
| 8 | 10 | ||
| 9 | pub const AT_NULL = 0; | 11 | pub const AT_NULL = 0; |
| ... | @@ -568,7 +570,7 @@ pub const ET = enum(u16) { | ... | @@ -568,7 +570,7 @@ pub const ET = enum(u16) { |
| 568 | /// All integers are native endian. | 570 | /// All integers are native endian. |
| 569 | pub const Header = struct { | 571 | pub const Header = struct { |
| 570 | is_64: bool, | 572 | is_64: bool, |
| 571 | endian: std.builtin.Endian, | 573 | endian: Endian, |
| 572 | os_abi: OSABI, | 574 | os_abi: OSABI, |
| 573 | /// The meaning of this value depends on `os_abi`. | 575 | /// The meaning of this value depends on `os_abi`. |
| 574 | abi_version: u8, | 576 | abi_version: u8, |
| ... | @@ -583,48 +585,76 @@ pub const Header = struct { | ... | @@ -583,48 +585,76 @@ pub const Header = struct { |
| 583 | shnum: u16, | 585 | shnum: u16, |
| 584 | shstrndx: u16, | 586 | shstrndx: u16, |
| 585 | 587 | ||
| 586 | pub fn iterateProgramHeaders(h: Header, file_reader: *std.fs.File.Reader) ProgramHeaderIterator { | 588 | pub fn iterateProgramHeaders(h: *const Header, file_reader: *Io.File.Reader) ProgramHeaderIterator { |
| 587 | return .{ | 589 | return .{ |
| 588 | .elf_header = h, | 590 | .is_64 = h.is_64, |
| 591 | .endian = h.endian, | ||
| 592 | .phnum = h.phnum, | ||
| 593 | .phoff = h.phoff, | ||
| 589 | .file_reader = file_reader, | 594 | .file_reader = file_reader, |
| 590 | }; | 595 | }; |
| 591 | } | 596 | } |
| 592 | 597 | ||
| 593 | pub fn iterateProgramHeadersBuffer(h: Header, buf: []const u8) ProgramHeaderBufferIterator { | 598 | pub fn iterateProgramHeadersBuffer(h: *const Header, buf: []const u8) ProgramHeaderBufferIterator { |
| 594 | return .{ | 599 | return .{ |
| 595 | .elf_header = h, | 600 | .is_64 = h.is_64, |
| 601 | .endian = h.endian, | ||
| 602 | .phnum = h.phnum, | ||
| 603 | .phoff = h.phoff, | ||
| 596 | .buf = buf, | 604 | .buf = buf, |
| 597 | }; | 605 | }; |
| 598 | } | 606 | } |
| 599 | 607 | ||
| 600 | pub fn iterateSectionHeaders(h: Header, file_reader: *std.fs.File.Reader) SectionHeaderIterator { | 608 | pub fn iterateSectionHeaders(h: *const Header, file_reader: *Io.File.Reader) SectionHeaderIterator { |
| 601 | return .{ | 609 | return .{ |
| 602 | .elf_header = h, | 610 | .is_64 = h.is_64, |
| 611 | .endian = h.endian, | ||
| 612 | .shnum = h.shnum, | ||
| 613 | .shoff = h.shoff, | ||
| 603 | .file_reader = file_reader, | 614 | .file_reader = file_reader, |
| 604 | }; | 615 | }; |
| 605 | } | 616 | } |
| 606 | 617 | ||
| 607 | pub fn iterateSectionHeadersBuffer(h: Header, buf: []const u8) SectionHeaderBufferIterator { | 618 | pub fn iterateSectionHeadersBuffer(h: *const Header, buf: []const u8) SectionHeaderBufferIterator { |
| 608 | return .{ | 619 | return .{ |
| 609 | .elf_header = h, | 620 | .is_64 = h.is_64, |
| 621 | .endian = h.endian, | ||
| 622 | .shnum = h.shnum, | ||
| 623 | .shoff = h.shoff, | ||
| 610 | .buf = buf, | 624 | .buf = buf, |
| 611 | }; | 625 | }; |
| 612 | } | 626 | } |
| 613 | 627 | ||
| 614 | pub const ReadError = std.Io.Reader.Error || error{ | 628 | pub fn iterateDynamicSection( |
| 629 | h: *const Header, | ||
| 630 | file_reader: *Io.File.Reader, | ||
| 631 | offset: u64, | ||
| 632 | size: u64, | ||
| 633 | ) DynamicSectionIterator { | ||
| 634 | return .{ | ||
| 635 | .is_64 = h.is_64, | ||
| 636 | .endian = h.endian, | ||
| 637 | .offset = offset, | ||
| 638 | .end_offset = offset + size, | ||
| 639 | .file_reader = file_reader, | ||
| 640 | }; | ||
| 641 | } | ||
| 642 | |||
| 643 | pub const ReadError = Io.Reader.Error || error{ | ||
| 615 | InvalidElfMagic, | 644 | InvalidElfMagic, |
| 616 | InvalidElfVersion, | 645 | InvalidElfVersion, |
| 617 | InvalidElfClass, | 646 | InvalidElfClass, |
| 618 | InvalidElfEndian, | 647 | InvalidElfEndian, |
| 619 | }; | 648 | }; |
| 620 | 649 | ||
| 621 | pub fn read(r: *std.Io.Reader) ReadError!Header { | 650 | /// If this function fails, seek position of `r` is unchanged. |
| 651 | pub fn read(r: *Io.Reader) ReadError!Header { | ||
| 622 | const buf = try r.peek(@sizeOf(Elf64_Ehdr)); | 652 | const buf = try r.peek(@sizeOf(Elf64_Ehdr)); |
| 623 | 653 | ||
| 624 | if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic; | 654 | if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic; |
| 625 | if (buf[EI.VERSION] != 1) return error.InvalidElfVersion; | 655 | if (buf[EI.VERSION] != 1) return error.InvalidElfVersion; |
| 626 | 656 | ||
| 627 | const endian: std.builtin.Endian = switch (buf[EI.DATA]) { | 657 | const endian: Endian = switch (buf[EI.DATA]) { |
| 628 | ELFDATA2LSB => .little, | 658 | ELFDATA2LSB => .little, |
| 629 | ELFDATA2MSB => .big, | 659 | ELFDATA2MSB => .big, |
| 630 | else => return error.InvalidElfEndian, | 660 | else => return error.InvalidElfEndian, |
| ... | @@ -637,7 +667,7 @@ pub const Header = struct { | ... | @@ -637,7 +667,7 @@ pub const Header = struct { |
| 637 | }; | 667 | }; |
| 638 | } | 668 | } |
| 639 | 669 | ||
| 640 | pub fn init(hdr: anytype, endian: std.builtin.Endian) Header { | 670 | pub fn init(hdr: anytype, endian: Endian) Header { |
| 641 | // Converting integers to exhaustive enums using `@enumFromInt` could cause a panic. | 671 | // Converting integers to exhaustive enums using `@enumFromInt` could cause a panic. |
| 642 | comptime assert(!@typeInfo(OSABI).@"enum".is_exhaustive); | 672 | comptime assert(!@typeInfo(OSABI).@"enum".is_exhaustive); |
| 643 | return .{ | 673 | return .{ |
| ... | @@ -664,46 +694,54 @@ pub const Header = struct { | ... | @@ -664,46 +694,54 @@ pub const Header = struct { |
| 664 | }; | 694 | }; |
| 665 | 695 | ||
| 666 | pub const ProgramHeaderIterator = struct { | 696 | pub const ProgramHeaderIterator = struct { |
| 667 | elf_header: Header, | 697 | is_64: bool, |
| 668 | file_reader: *std.fs.File.Reader, | 698 | endian: Endian, |
| 699 | phnum: u16, | ||
| 700 | phoff: u64, | ||
| 701 | |||
| 702 | file_reader: *Io.File.Reader, | ||
| 669 | index: usize = 0, | 703 | index: usize = 0, |
| 670 | 704 | ||
| 671 | pub fn next(it: *ProgramHeaderIterator) !?Elf64_Phdr { | 705 | pub fn next(it: *ProgramHeaderIterator) !?Elf64_Phdr { |
| 672 | if (it.index >= it.elf_header.phnum) return null; | 706 | if (it.index >= it.phnum) return null; |
| 673 | defer it.index += 1; | 707 | defer it.index += 1; |
| 674 | 708 | ||
| 675 | const size: u64 = if (it.elf_header.is_64) @sizeOf(Elf64_Phdr) else @sizeOf(Elf32_Phdr); | 709 | const size: u64 = if (it.is_64) @sizeOf(Elf64_Phdr) else @sizeOf(Elf32_Phdr); |
| 676 | const offset = it.elf_header.phoff + size * it.index; | 710 | const offset = it.phoff + size * it.index; |
| 677 | try it.file_reader.seekTo(offset); | 711 | try it.file_reader.seekTo(offset); |
| 678 | 712 | ||
| 679 | return takePhdr(&it.file_reader.interface, it.elf_header); | 713 | return takeProgramHeader(&it.file_reader.interface, it.is_64, it.endian); |
| 680 | } | 714 | } |
| 681 | }; | 715 | }; |
| 682 | 716 | ||
| 683 | pub const ProgramHeaderBufferIterator = struct { | 717 | pub const ProgramHeaderBufferIterator = struct { |
| 684 | elf_header: Header, | 718 | is_64: bool, |
| 719 | endian: Endian, | ||
| 720 | phnum: u16, | ||
| 721 | phoff: u64, | ||
| 722 | |||
| 685 | buf: []const u8, | 723 | buf: []const u8, |
| 686 | index: usize = 0, | 724 | index: usize = 0, |
| 687 | 725 | ||
| 688 | pub fn next(it: *ProgramHeaderBufferIterator) !?Elf64_Phdr { | 726 | pub fn next(it: *ProgramHeaderBufferIterator) !?Elf64_Phdr { |
| 689 | if (it.index >= it.elf_header.phnum) return null; | 727 | if (it.index >= it.phnum) return null; |
| 690 | defer it.index += 1; | 728 | defer it.index += 1; |
| 691 | 729 | ||
| 692 | const size: u64 = if (it.elf_header.is_64) @sizeOf(Elf64_Phdr) else @sizeOf(Elf32_Phdr); | 730 | const size: u64 = if (it.is_64) @sizeOf(Elf64_Phdr) else @sizeOf(Elf32_Phdr); |
| 693 | const offset = it.elf_header.phoff + size * it.index; | 731 | const offset = it.phoff + size * it.index; |
| 694 | var reader = std.Io.Reader.fixed(it.buf[offset..]); | 732 | var reader = Io.Reader.fixed(it.buf[offset..]); |
| 695 | 733 | ||
| 696 | return takePhdr(&reader, it.elf_header); | 734 | return takeProgramHeader(&reader, it.is_64, it.endian); |
| 697 | } | 735 | } |
| 698 | }; | 736 | }; |
| 699 | 737 | ||
| 700 | fn takePhdr(reader: *std.Io.Reader, elf_header: Header) !?Elf64_Phdr { | 738 | pub fn takeProgramHeader(reader: *Io.Reader, is_64: bool, endian: Endian) !Elf64_Phdr { |
| 701 | if (elf_header.is_64) { | 739 | if (is_64) { |
| 702 | const phdr = try reader.takeStruct(Elf64_Phdr, elf_header.endian); | 740 | const phdr = try reader.takeStruct(Elf64_Phdr, endian); |
| 703 | return phdr; | 741 | return phdr; |
| 704 | } | 742 | } |
| 705 | 743 | ||
| 706 | const phdr = try reader.takeStruct(Elf32_Phdr, elf_header.endian); | 744 | const phdr = try reader.takeStruct(Elf32_Phdr, endian); |
| 707 | return .{ | 745 | return .{ |
| 708 | .p_type = phdr.p_type, | 746 | .p_type = phdr.p_type, |
| 709 | .p_offset = phdr.p_offset, | 747 | .p_offset = phdr.p_offset, |
| ... | @@ -717,47 +755,55 @@ fn takePhdr(reader: *std.Io.Reader, elf_header: Header) !?Elf64_Phdr { | ... | @@ -717,47 +755,55 @@ fn takePhdr(reader: *std.Io.Reader, elf_header: Header) !?Elf64_Phdr { |
| 717 | } | 755 | } |
| 718 | 756 | ||
| 719 | pub const SectionHeaderIterator = struct { | 757 | pub const SectionHeaderIterator = struct { |
| 720 | elf_header: Header, | 758 | is_64: bool, |
| 721 | file_reader: *std.fs.File.Reader, | 759 | endian: Endian, |
| 760 | shnum: u16, | ||
| 761 | shoff: u64, | ||
| 762 | |||
| 763 | file_reader: *Io.File.Reader, | ||
| 722 | index: usize = 0, | 764 | index: usize = 0, |
| 723 | 765 | ||
| 724 | pub fn next(it: *SectionHeaderIterator) !?Elf64_Shdr { | 766 | pub fn next(it: *SectionHeaderIterator) !?Elf64_Shdr { |
| 725 | if (it.index >= it.elf_header.shnum) return null; | 767 | if (it.index >= it.shnum) return null; |
| 726 | defer it.index += 1; | 768 | defer it.index += 1; |
| 727 | 769 | ||
| 728 | const size: u64 = if (it.elf_header.is_64) @sizeOf(Elf64_Shdr) else @sizeOf(Elf32_Shdr); | 770 | const size: u64 = if (it.is_64) @sizeOf(Elf64_Shdr) else @sizeOf(Elf32_Shdr); |
| 729 | const offset = it.elf_header.shoff + size * it.index; | 771 | const offset = it.shoff + size * it.index; |
| 730 | try it.file_reader.seekTo(offset); | 772 | try it.file_reader.seekTo(offset); |
| 731 | 773 | ||
| 732 | return takeShdr(&it.file_reader.interface, it.elf_header); | 774 | return takeSectionHeader(&it.file_reader.interface, it.is_64, it.endian); |
| 733 | } | 775 | } |
| 734 | }; | 776 | }; |
| 735 | 777 | ||
| 736 | pub const SectionHeaderBufferIterator = struct { | 778 | pub const SectionHeaderBufferIterator = struct { |
| 737 | elf_header: Header, | 779 | is_64: bool, |
| 780 | endian: Endian, | ||
| 781 | shnum: u16, | ||
| 782 | shoff: u64, | ||
| 783 | |||
| 738 | buf: []const u8, | 784 | buf: []const u8, |
| 739 | index: usize = 0, | 785 | index: usize = 0, |
| 740 | 786 | ||
| 741 | pub fn next(it: *SectionHeaderBufferIterator) !?Elf64_Shdr { | 787 | pub fn next(it: *SectionHeaderBufferIterator) !?Elf64_Shdr { |
| 742 | if (it.index >= it.elf_header.shnum) return null; | 788 | if (it.index >= it.shnum) return null; |
| 743 | defer it.index += 1; | 789 | defer it.index += 1; |
| 744 | 790 | ||
| 745 | const size: u64 = if (it.elf_header.is_64) @sizeOf(Elf64_Shdr) else @sizeOf(Elf32_Shdr); | 791 | const size: u64 = if (it.is_64) @sizeOf(Elf64_Shdr) else @sizeOf(Elf32_Shdr); |
| 746 | const offset = it.elf_header.shoff + size * it.index; | 792 | const offset = it.shoff + size * it.index; |
| 747 | if (offset > it.buf.len) return error.EndOfStream; | 793 | if (offset > it.buf.len) return error.EndOfStream; |
| 748 | var reader = std.Io.Reader.fixed(it.buf[@intCast(offset)..]); | 794 | var reader = Io.Reader.fixed(it.buf[@intCast(offset)..]); |
| 749 | 795 | ||
| 750 | return takeShdr(&reader, it.elf_header); | 796 | return takeSectionHeader(&reader, it.is_64, it.endian); |
| 751 | } | 797 | } |
| 752 | }; | 798 | }; |
| 753 | 799 | ||
| 754 | fn takeShdr(reader: *std.Io.Reader, elf_header: Header) !?Elf64_Shdr { | 800 | pub fn takeSectionHeader(reader: *Io.Reader, is_64: bool, endian: Endian) !Elf64_Shdr { |
| 755 | if (elf_header.is_64) { | 801 | if (is_64) { |
| 756 | const shdr = try reader.takeStruct(Elf64_Shdr, elf_header.endian); | 802 | const shdr = try reader.takeStruct(Elf64_Shdr, endian); |
| 757 | return shdr; | 803 | return shdr; |
| 758 | } | 804 | } |
| 759 | 805 | ||
| 760 | const shdr = try reader.takeStruct(Elf32_Shdr, elf_header.endian); | 806 | const shdr = try reader.takeStruct(Elf32_Shdr, endian); |
| 761 | return .{ | 807 | return .{ |
| 762 | .sh_name = shdr.sh_name, | 808 | .sh_name = shdr.sh_name, |
| 763 | .sh_type = shdr.sh_type, | 809 | .sh_type = shdr.sh_type, |
| ... | @@ -772,6 +818,36 @@ fn takeShdr(reader: *std.Io.Reader, elf_header: Header) !?Elf64_Shdr { | ... | @@ -772,6 +818,36 @@ fn takeShdr(reader: *std.Io.Reader, elf_header: Header) !?Elf64_Shdr { |
| 772 | }; | 818 | }; |
| 773 | } | 819 | } |
| 774 | 820 | ||
| 821 | pub const DynamicSectionIterator = struct { | ||
| 822 | is_64: bool, | ||
| 823 | endian: Endian, | ||
| 824 | offset: u64, | ||
| 825 | end_offset: u64, | ||
| 826 | |||
| 827 | file_reader: *Io.File.Reader, | ||
| 828 | |||
| 829 | pub fn next(it: *SectionHeaderIterator) !?Elf64_Dyn { | ||
| 830 | if (it.offset >= it.end_offset) return null; | ||
| 831 | const size: u64 = if (it.is_64) @sizeOf(Elf64_Dyn) else @sizeOf(Elf32_Dyn); | ||
| 832 | defer it.offset += size; | ||
| 833 | try it.file_reader.seekTo(it.offset); | ||
| 834 | return takeDynamicSection(&it.file_reader.interface, it.is_64, it.endian); | ||
| 835 | } | ||
| 836 | }; | ||
| 837 | |||
| 838 | pub fn takeDynamicSection(reader: *Io.Reader, is_64: bool, endian: Endian) !Elf64_Dyn { | ||
| 839 | if (is_64) { | ||
| 840 | const dyn = try reader.takeStruct(Elf64_Dyn, endian); | ||
| 841 | return dyn; | ||
| 842 | } | ||
| 843 | |||
| 844 | const dyn = try reader.takeStruct(Elf32_Dyn, endian); | ||
| 845 | return .{ | ||
| 846 | .d_tag = dyn.d_tag, | ||
| 847 | .d_val = dyn.d_val, | ||
| 848 | }; | ||
| 849 | } | ||
| 850 | |||
| 775 | pub const EI = struct { | 851 | pub const EI = struct { |
| 776 | pub const CLASS = 4; | 852 | pub const CLASS = 4; |
| 777 | pub const DATA = 5; | 853 | pub const DATA = 5; |
lib/std/zig.zig+6-5| ... | @@ -6,6 +6,7 @@ const std = @import("std.zig"); | ... | @@ -6,6 +6,7 @@ const std = @import("std.zig"); |
| 6 | const tokenizer = @import("zig/tokenizer.zig"); | 6 | const tokenizer = @import("zig/tokenizer.zig"); |
| 7 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 8 | const Allocator = std.mem.Allocator; | 8 | const Allocator = std.mem.Allocator; |
| 9 | const Io = std.Io; | ||
| 9 | const Writer = std.Io.Writer; | 10 | const Writer = std.Io.Writer; |
| 10 | 11 | ||
| 11 | pub const ErrorBundle = @import("zig/ErrorBundle.zig"); | 12 | pub const ErrorBundle = @import("zig/ErrorBundle.zig"); |
| ... | @@ -52,9 +53,9 @@ pub const Color = enum { | ... | @@ -52,9 +53,9 @@ pub const Color = enum { |
| 52 | /// Assume stderr is a terminal. | 53 | /// Assume stderr is a terminal. |
| 53 | on, | 54 | on, |
| 54 | 55 | ||
| 55 | pub fn get_tty_conf(color: Color) std.Io.tty.Config { | 56 | pub fn get_tty_conf(color: Color) Io.tty.Config { |
| 56 | return switch (color) { | 57 | return switch (color) { |
| 57 | .auto => std.Io.tty.detectConfig(std.fs.File.stderr()), | 58 | .auto => Io.tty.detectConfig(std.fs.File.stderr()), |
| 58 | .on => .escape_codes, | 59 | .on => .escape_codes, |
| 59 | .off => .no_color, | 60 | .off => .no_color, |
| 60 | }; | 61 | }; |
| ... | @@ -323,7 +324,7 @@ pub const BuildId = union(enum) { | ... | @@ -323,7 +324,7 @@ pub const BuildId = union(enum) { |
| 323 | try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx")); | 324 | try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx")); |
| 324 | } | 325 | } |
| 325 | 326 | ||
| 326 | pub fn format(id: BuildId, writer: *std.Io.Writer) std.Io.Writer.Error!void { | 327 | pub fn format(id: BuildId, writer: *Writer) Writer.Error!void { |
| 327 | switch (id) { | 328 | switch (id) { |
| 328 | .none, .fast, .uuid, .sha1, .md5 => { | 329 | .none, .fast, .uuid, .sha1, .md5 => { |
| 329 | try writer.writeAll(@tagName(id)); | 330 | try writer.writeAll(@tagName(id)); |
| ... | @@ -620,8 +621,8 @@ pub fn putAstErrorsIntoBundle( | ... | @@ -620,8 +621,8 @@ pub fn putAstErrorsIntoBundle( |
| 620 | try wip_errors.addZirErrorMessages(zir, tree, tree.source, path); | 621 | try wip_errors.addZirErrorMessages(zir, tree, tree.source, path); |
| 621 | } | 622 | } |
| 622 | 623 | ||
| 623 | pub fn resolveTargetQueryOrFatal(target_query: std.Target.Query) std.Target { | 624 | pub fn resolveTargetQueryOrFatal(io: Io, target_query: std.Target.Query) std.Target { |
| 624 | return std.zig.system.resolveTargetQuery(target_query) catch |err| | 625 | return std.zig.system.resolveTargetQuery(io, target_query) catch |err| |
| 625 | std.process.fatal("unable to resolve target: {s}", .{@errorName(err)}); | 626 | std.process.fatal("unable to resolve target: {s}", .{@errorName(err)}); |
| 626 | } | 627 | } |
| 627 | 628 |
lib/std/zig/system.zig+221-411| ... | @@ -1,3 +1,14 @@ | ... | @@ -1,3 +1,14 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("../std.zig"); | ||
| 3 | const mem = std.mem; | ||
| 4 | const elf = std.elf; | ||
| 5 | const fs = std.fs; | ||
| 6 | const assert = std.debug.assert; | ||
| 7 | const Target = std.Target; | ||
| 8 | const native_endian = builtin.cpu.arch.endian(); | ||
| 9 | const posix = std.posix; | ||
| 10 | const Io = std.Io; | ||
| 11 | |||
| 1 | pub const NativePaths = @import("system/NativePaths.zig"); | 12 | pub const NativePaths = @import("system/NativePaths.zig"); |
| 2 | 13 | ||
| 3 | pub const windows = @import("system/windows.zig"); | 14 | pub const windows = @import("system/windows.zig"); |
| ... | @@ -199,14 +210,14 @@ pub const DetectError = error{ | ... | @@ -199,14 +210,14 @@ pub const DetectError = error{ |
| 199 | OSVersionDetectionFail, | 210 | OSVersionDetectionFail, |
| 200 | Unexpected, | 211 | Unexpected, |
| 201 | ProcessNotFound, | 212 | ProcessNotFound, |
| 202 | }; | 213 | } || Io.Cancelable; |
| 203 | 214 | ||
| 204 | /// Given a `Target.Query`, which specifies in detail which parts of the | 215 | /// Given a `Target.Query`, which specifies in detail which parts of the |
| 205 | /// target should be detected natively, which should be standard or default, | 216 | /// target should be detected natively, which should be standard or default, |
| 206 | /// and which are provided explicitly, this function resolves the native | 217 | /// and which are provided explicitly, this function resolves the native |
| 207 | /// components by detecting the native system, and then resolves | 218 | /// components by detecting the native system, and then resolves |
| 208 | /// standard/default parts relative to that. | 219 | /// standard/default parts relative to that. |
| 209 | pub fn resolveTargetQuery(query: Target.Query) DetectError!Target { | 220 | pub fn resolveTargetQuery(io: Io, query: Target.Query) DetectError!Target { |
| 210 | // Until https://github.com/ziglang/zig/issues/4592 is implemented (support detecting the | 221 | // Until https://github.com/ziglang/zig/issues/4592 is implemented (support detecting the |
| 211 | // native CPU architecture as being different than the current target), we use this: | 222 | // native CPU architecture as being different than the current target), we use this: |
| 212 | const query_cpu_arch = query.cpu_arch orelse builtin.cpu.arch; | 223 | const query_cpu_arch = query.cpu_arch orelse builtin.cpu.arch; |
| ... | @@ -411,7 +422,33 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target { | ... | @@ -411,7 +422,33 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target { |
| 411 | query.cpu_features_sub, | 422 | query.cpu_features_sub, |
| 412 | ); | 423 | ); |
| 413 | 424 | ||
| 414 | var result = try detectAbiAndDynamicLinker(cpu, os, query); | 425 | var result = detectAbiAndDynamicLinker(io, cpu, os, query) catch |err| switch (err) { |
| 426 | error.Canceled => |e| return e, | ||
| 427 | error.Unexpected => |e| return e, | ||
| 428 | error.WouldBlock => return error.Unexpected, | ||
| 429 | error.BrokenPipe => return error.Unexpected, | ||
| 430 | error.ConnectionResetByPeer => return error.Unexpected, | ||
| 431 | error.ConnectionTimedOut => return error.Unexpected, | ||
| 432 | error.NotOpenForReading => return error.Unexpected, | ||
| 433 | error.SocketUnconnected => return error.Unexpected, | ||
| 434 | |||
| 435 | error.AccessDenied, | ||
| 436 | error.ProcessNotFound, | ||
| 437 | error.SymLinkLoop, | ||
| 438 | error.ProcessFdQuotaExceeded, | ||
| 439 | error.SystemFdQuotaExceeded, | ||
| 440 | error.SystemResources, | ||
| 441 | error.IsDir, | ||
| 442 | error.DeviceBusy, | ||
| 443 | error.InputOutput, | ||
| 444 | error.LockViolation, | ||
| 445 | |||
| 446 | error.UnableToOpenElfFile, | ||
| 447 | error.UnhelpfulFile, | ||
| 448 | error.InvalidElfFile, | ||
| 449 | error.RelativeShebang, | ||
| 450 | => return defaultAbiAndDynamicLinker(cpu, os, query), | ||
| 451 | }; | ||
| 415 | 452 | ||
| 416 | // These CPU feature hacks have to come after ABI detection. | 453 | // These CPU feature hacks have to come after ABI detection. |
| 417 | { | 454 | { |
| ... | @@ -505,54 +542,16 @@ fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, query: T | ... | @@ -505,54 +542,16 @@ fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, query: T |
| 505 | return null; | 542 | return null; |
| 506 | } | 543 | } |
| 507 | 544 | ||
| 508 | pub const AbiAndDynamicLinkerFromFileError = error{ | 545 | pub const AbiAndDynamicLinkerFromFileError = error{}; |
| 509 | FileSystem, | ||
| 510 | SystemResources, | ||
| 511 | SymLinkLoop, | ||
| 512 | ProcessFdQuotaExceeded, | ||
| 513 | SystemFdQuotaExceeded, | ||
| 514 | UnableToReadElfFile, | ||
| 515 | InvalidElfClass, | ||
| 516 | InvalidElfVersion, | ||
| 517 | InvalidElfEndian, | ||
| 518 | InvalidElfFile, | ||
| 519 | InvalidElfMagic, | ||
| 520 | Unexpected, | ||
| 521 | UnexpectedEndOfFile, | ||
| 522 | NameTooLong, | ||
| 523 | ProcessNotFound, | ||
| 524 | StaticElfFile, | ||
| 525 | }; | ||
| 526 | 546 | ||
| 527 | pub fn abiAndDynamicLinkerFromFile( | 547 | pub fn abiAndDynamicLinkerFromFile( |
| 528 | file: fs.File, | 548 | file_reader: *Io.File.Reader, |
| 549 | header: *const elf.Header, | ||
| 529 | cpu: Target.Cpu, | 550 | cpu: Target.Cpu, |
| 530 | os: Target.Os, | 551 | os: Target.Os, |
| 531 | ld_info_list: []const LdInfo, | 552 | ld_info_list: []const LdInfo, |
| 532 | query: Target.Query, | 553 | query: Target.Query, |
| 533 | ) AbiAndDynamicLinkerFromFileError!Target { | 554 | ) AbiAndDynamicLinkerFromFileError!Target { |
| 534 | var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined; | ||
| 535 | _ = try preadAtLeast(file, &hdr_buf, 0, hdr_buf.len); | ||
| 536 | const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf); | ||
| 537 | const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf); | ||
| 538 | if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; | ||
| 539 | const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI.DATA]) { | ||
| 540 | elf.ELFDATA2LSB => .little, | ||
| 541 | elf.ELFDATA2MSB => .big, | ||
| 542 | else => return error.InvalidElfEndian, | ||
| 543 | }; | ||
| 544 | const need_bswap = elf_endian != native_endian; | ||
| 545 | if (hdr32.e_ident[elf.EI.VERSION] != 1) return error.InvalidElfVersion; | ||
| 546 | |||
| 547 | const is_64 = switch (hdr32.e_ident[elf.EI.CLASS]) { | ||
| 548 | elf.ELFCLASS32 => false, | ||
| 549 | elf.ELFCLASS64 => true, | ||
| 550 | else => return error.InvalidElfClass, | ||
| 551 | }; | ||
| 552 | var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff); | ||
| 553 | const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize); | ||
| 554 | const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum); | ||
| 555 | |||
| 556 | var result: Target = .{ | 555 | var result: Target = .{ |
| 557 | .cpu = cpu, | 556 | .cpu = cpu, |
| 558 | .os = os, | 557 | .os = os, |
| ... | @@ -563,167 +562,87 @@ pub fn abiAndDynamicLinkerFromFile( | ... | @@ -563,167 +562,87 @@ pub fn abiAndDynamicLinkerFromFile( |
| 563 | var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC | 562 | var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC |
| 564 | const look_for_ld = query.dynamic_linker.get() == null; | 563 | const look_for_ld = query.dynamic_linker.get() == null; |
| 565 | 564 | ||
| 566 | var ph_buf: [16 * @sizeOf(elf.Elf64_Phdr)]u8 align(@alignOf(elf.Elf64_Phdr)) = undefined; | ||
| 567 | if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile; | ||
| 568 | |||
| 569 | var ph_i: u16 = 0; | ||
| 570 | var got_dyn_section: bool = false; | 565 | var got_dyn_section: bool = false; |
| 571 | 566 | { | |
| 572 | while (ph_i < phnum) { | 567 | var it = header.iterateProgramHeaders(file_reader); |
| 573 | // Reserve some bytes so that we can deref the 64-bit struct fields | 568 | while (try it.next()) |phdr| switch (phdr.p_type) { |
| 574 | // even when the ELF file is 32-bits. | 569 | elf.PT_INTERP => { |
| 575 | const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr); | 570 | got_dyn_section = true; |
| 576 | const ph_read_byte_len = try preadAtLeast(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize); | 571 | |
| 577 | var ph_buf_i: usize = 0; | 572 | if (look_for_ld) { |
| 578 | while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({ | 573 | const p_filesz = phdr.p_filesz; |
| 579 | ph_i += 1; | 574 | if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; |
| 580 | phoff += phentsize; | 575 | const filesz: usize = @intCast(p_filesz); |
| 581 | ph_buf_i += phentsize; | 576 | try file_reader.seekTo(phdr.p_offset); |
| 582 | }) { | 577 | try file_reader.interface.readSliceAll(result.dynamic_linker.buffer[0..filesz]); |
| 583 | const ph32: *elf.Elf32_Phdr = @ptrCast(@alignCast(&ph_buf[ph_buf_i])); | 578 | // PT_INTERP includes a null byte in filesz. |
| 584 | const ph64: *elf.Elf64_Phdr = @ptrCast(@alignCast(&ph_buf[ph_buf_i])); | 579 | const len = filesz - 1; |
| 585 | const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type); | 580 | // dynamic_linker.max_byte is "max", not "len". |
| 586 | switch (p_type) { | 581 | // We know it will fit in u8 because we check against dynamic_linker.buffer.len above. |
| 587 | elf.PT_INTERP => { | 582 | result.dynamic_linker.len = @intCast(len); |
| 588 | got_dyn_section = true; | 583 | |
| 589 | 584 | // Use it to determine ABI. | |
| 590 | if (look_for_ld) { | 585 | const full_ld_path = result.dynamic_linker.buffer[0..len]; |
| 591 | const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); | 586 | for (ld_info_list) |ld_info| { |
| 592 | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); | 587 | const standard_ld_basename = fs.path.basename(ld_info.ld.get().?); |
| 593 | if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; | 588 | if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) { |
| 594 | const filesz: usize = @intCast(p_filesz); | 589 | result.abi = ld_info.abi; |
| 595 | _ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz); | 590 | break; |
| 596 | // PT_INTERP includes a null byte in filesz. | ||
| 597 | const len = filesz - 1; | ||
| 598 | // dynamic_linker.max_byte is "max", not "len". | ||
| 599 | // We know it will fit in u8 because we check against dynamic_linker.buffer.len above. | ||
| 600 | result.dynamic_linker.len = @intCast(len); | ||
| 601 | |||
| 602 | // Use it to determine ABI. | ||
| 603 | const full_ld_path = result.dynamic_linker.buffer[0..len]; | ||
| 604 | for (ld_info_list) |ld_info| { | ||
| 605 | const standard_ld_basename = fs.path.basename(ld_info.ld.get().?); | ||
| 606 | if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) { | ||
| 607 | result.abi = ld_info.abi; | ||
| 608 | break; | ||
| 609 | } | ||
| 610 | } | 591 | } |
| 611 | } | 592 | } |
| 612 | }, | 593 | } |
| 613 | // We only need this for detecting glibc version. | 594 | }, |
| 614 | elf.PT_DYNAMIC => { | 595 | // We only need this for detecting glibc version. |
| 615 | got_dyn_section = true; | 596 | elf.PT_DYNAMIC => { |
| 616 | 597 | got_dyn_section = true; | |
| 617 | if (builtin.target.os.tag == .linux and result.isGnuLibC() and | 598 | |
| 618 | query.glibc_version == null) | 599 | if (builtin.target.os.tag == .linux and result.isGnuLibC() and query.glibc_version == null) { |
| 619 | { | 600 | var dyn_it = header.iterateDynamicSection(file_reader, phdr.p_offset, phdr.p_filesz); |
| 620 | var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); | 601 | while (try dyn_it.next()) |dyn| { |
| 621 | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); | 602 | if (dyn.d_tag == elf.DT_RUNPATH) { |
| 622 | const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn); | 603 | rpath_offset = dyn.d_val; |
| 623 | const dyn_num = p_filesz / dyn_size; | 604 | break; |
| 624 | var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined; | ||
| 625 | var dyn_i: usize = 0; | ||
| 626 | dyn: while (dyn_i < dyn_num) { | ||
| 627 | // Reserve some bytes so that we can deref the 64-bit struct fields | ||
| 628 | // even when the ELF file is 32-bits. | ||
| 629 | const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn); | ||
| 630 | const dyn_read_byte_len = try preadAtLeast( | ||
| 631 | file, | ||
| 632 | dyn_buf[0 .. dyn_buf.len - dyn_reserve], | ||
| 633 | dyn_off, | ||
| 634 | dyn_size, | ||
| 635 | ); | ||
| 636 | var dyn_buf_i: usize = 0; | ||
| 637 | while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({ | ||
| 638 | dyn_i += 1; | ||
| 639 | dyn_off += dyn_size; | ||
| 640 | dyn_buf_i += dyn_size; | ||
| 641 | }) { | ||
| 642 | const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i])); | ||
| 643 | const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i])); | ||
| 644 | const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag); | ||
| 645 | const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val); | ||
| 646 | if (tag == elf.DT_RUNPATH) { | ||
| 647 | rpath_offset = val; | ||
| 648 | break :dyn; | ||
| 649 | } | ||
| 650 | } | ||
| 651 | } | 605 | } |
| 652 | } | 606 | } |
| 653 | }, | 607 | } |
| 654 | else => continue, | 608 | }, |
| 655 | } | 609 | else => continue, |
| 656 | } | 610 | }; |
| 657 | } | 611 | } |
| 658 | 612 | ||
| 659 | if (!got_dyn_section) { | 613 | if (!got_dyn_section) { |
| 660 | return error.StaticElfFile; | 614 | return error.StaticElfFile; |
| 661 | } | 615 | } |
| 662 | 616 | ||
| 663 | if (builtin.target.os.tag == .linux and result.isGnuLibC() and | 617 | if (builtin.target.os.tag == .linux and result.isGnuLibC() and query.glibc_version == null) { |
| 664 | query.glibc_version == null) | 618 | const str_section_off = header.shoff + @as(u64, header.shentsize) * @as(u64, header.shstrndx); |
| 665 | { | 619 | try file_reader.seekTo(str_section_off); |
| 666 | const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx); | 620 | const shstr = try elf.takeSectionHeader(&file_reader.interface, header.is_64, header.endian); |
| 667 | 621 | var strtab_buf: [4096]u8 = undefined; | |
| 668 | var shoff = elfInt(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff); | 622 | const shstrtab = strtab_buf[0..@min(shstr.sh_size, strtab_buf.len)]; |
| 669 | const shentsize = elfInt(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize); | 623 | try file_reader.seekTo(shstr.sh_offset); |
| 670 | const str_section_off = shoff + @as(u64, shentsize) * @as(u64, shstrndx); | 624 | try file_reader.interface.readSliceAll(shstrtab); |
| 671 | 625 | const dynstr: ?struct { offset: u64, size: u64 } = find_dyn_str: { | |
| 672 | var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined; | 626 | var it = header.iterateSectionHeaders(&file_reader.interface); |
| 673 | if (sh_buf.len < shentsize) return error.InvalidElfFile; | 627 | while (it.next()) |shdr| { |
| 674 | 628 | const end = mem.findScalarPos(u8, shstrtab, shdr.sh_name, 0) orelse continue; | |
| 675 | _ = try preadAtLeast(file, &sh_buf, str_section_off, shentsize); | 629 | const sh_name = shstrtab[shdr.sh_name..end :0]; |
| 676 | const shstr32: *elf.Elf32_Shdr = @ptrCast(@alignCast(&sh_buf)); | 630 | if (mem.eql(u8, sh_name, ".dynstr")) break :find_dyn_str .{ |
| 677 | const shstr64: *elf.Elf64_Shdr = @ptrCast(@alignCast(&sh_buf)); | 631 | .offset = shdr.sh_offset, |
| 678 | const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset); | 632 | .size = shdr.sh_size, |
| 679 | const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size); | 633 | }; |
| 680 | var strtab_buf: [4096:0]u8 = undefined; | 634 | } else break :find_dyn_str null; |
| 681 | const shstrtab_len = @min(shstrtab_size, strtab_buf.len); | 635 | }; |
| 682 | const shstrtab_read_len = try preadAtLeast(file, &strtab_buf, shstrtab_off, shstrtab_len); | ||
| 683 | const shstrtab = strtab_buf[0..shstrtab_read_len]; | ||
| 684 | |||
| 685 | const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum); | ||
| 686 | var sh_i: u16 = 0; | ||
| 687 | const dynstr: ?struct { offset: u64, size: u64 } = find_dyn_str: while (sh_i < shnum) { | ||
| 688 | // Reserve some bytes so that we can deref the 64-bit struct fields | ||
| 689 | // even when the ELF file is 32-bits. | ||
| 690 | const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr); | ||
| 691 | const sh_read_byte_len = try preadAtLeast( | ||
| 692 | file, | ||
| 693 | sh_buf[0 .. sh_buf.len - sh_reserve], | ||
| 694 | shoff, | ||
| 695 | shentsize, | ||
| 696 | ); | ||
| 697 | var sh_buf_i: usize = 0; | ||
| 698 | while (sh_buf_i < sh_read_byte_len and sh_i < shnum) : ({ | ||
| 699 | sh_i += 1; | ||
| 700 | shoff += shentsize; | ||
| 701 | sh_buf_i += shentsize; | ||
| 702 | }) { | ||
| 703 | const sh32: *elf.Elf32_Shdr = @ptrCast(@alignCast(&sh_buf[sh_buf_i])); | ||
| 704 | const sh64: *elf.Elf64_Shdr = @ptrCast(@alignCast(&sh_buf[sh_buf_i])); | ||
| 705 | const sh_name_off = elfInt(is_64, need_bswap, sh32.sh_name, sh64.sh_name); | ||
| 706 | const sh_name = mem.sliceTo(shstrtab[sh_name_off..], 0); | ||
| 707 | if (mem.eql(u8, sh_name, ".dynstr")) { | ||
| 708 | break :find_dyn_str .{ | ||
| 709 | .offset = elfInt(is_64, need_bswap, sh32.sh_offset, sh64.sh_offset), | ||
| 710 | .size = elfInt(is_64, need_bswap, sh32.sh_size, sh64.sh_size), | ||
| 711 | }; | ||
| 712 | } | ||
| 713 | } | ||
| 714 | } else null; | ||
| 715 | |||
| 716 | if (dynstr) |ds| { | 636 | if (dynstr) |ds| { |
| 717 | if (rpath_offset) |rpoff| { | 637 | if (rpath_offset) |rpoff| { |
| 718 | if (rpoff > ds.size) return error.InvalidElfFile; | 638 | if (rpoff > ds.size) return error.InvalidElfFile; |
| 719 | const rpoff_file = ds.offset + rpoff; | 639 | const rpoff_file = ds.offset + rpoff; |
| 720 | const rp_max_size = ds.size - rpoff; | 640 | const rp_max_size = ds.size - rpoff; |
| 721 | 641 | ||
| 722 | const strtab_len = @min(rp_max_size, strtab_buf.len); | 642 | try file_reader.seekTo(rpoff_file); |
| 723 | const strtab_read_len = try preadAtLeast(file, &strtab_buf, rpoff_file, strtab_len); | 643 | const rpath_list = try file_reader.interface.takeSentinel(0); |
| 724 | const strtab = strtab_buf[0..strtab_read_len]; | 644 | if (rpath_list.len > rp_max_size) return error.StreamTooLong; |
| 725 | 645 | ||
| 726 | const rpath_list = mem.sliceTo(strtab, 0); | ||
| 727 | var it = mem.tokenizeScalar(u8, rpath_list, ':'); | 646 | var it = mem.tokenizeScalar(u8, rpath_list, ':'); |
| 728 | while (it.next()) |rpath| { | 647 | while (it.next()) |rpath| { |
| 729 | if (glibcVerFromRPath(rpath)) |ver| { | 648 | if (glibcVerFromRPath(rpath)) |ver| { |
| ... | @@ -845,7 +764,7 @@ test glibcVerFromLinkName { | ... | @@ -845,7 +764,7 @@ test glibcVerFromLinkName { |
| 845 | try std.testing.expectError(error.InvalidGnuLibCVersion, glibcVerFromLinkName("ld-2.37.4.5.so", "ld-")); | 764 | try std.testing.expectError(error.InvalidGnuLibCVersion, glibcVerFromLinkName("ld-2.37.4.5.so", "ld-")); |
| 846 | } | 765 | } |
| 847 | 766 | ||
| 848 | fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion { | 767 | fn glibcVerFromRPath(io: Io, rpath: []const u8) !std.SemanticVersion { |
| 849 | var dir = fs.cwd().openDir(rpath, .{}) catch |err| switch (err) { | 768 | var dir = fs.cwd().openDir(rpath, .{}) catch |err| switch (err) { |
| 850 | error.NameTooLong => unreachable, | 769 | error.NameTooLong => unreachable, |
| 851 | error.InvalidUtf8 => unreachable, // WASI only | 770 | error.InvalidUtf8 => unreachable, // WASI only |
| ... | @@ -879,7 +798,7 @@ fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion { | ... | @@ -879,7 +798,7 @@ fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion { |
| 879 | // .dynstr section, and finding the max version number of symbols | 798 | // .dynstr section, and finding the max version number of symbols |
| 880 | // that start with "GLIBC_2.". | 799 | // that start with "GLIBC_2.". |
| 881 | const glibc_so_basename = "libc.so.6"; | 800 | const glibc_so_basename = "libc.so.6"; |
| 882 | var f = dir.openFile(glibc_so_basename, .{}) catch |err| switch (err) { | 801 | var file = dir.openFile(glibc_so_basename, .{}) catch |err| switch (err) { |
| 883 | error.NameTooLong => unreachable, | 802 | error.NameTooLong => unreachable, |
| 884 | error.InvalidUtf8 => unreachable, // WASI only | 803 | error.InvalidUtf8 => unreachable, // WASI only |
| 885 | error.InvalidWtf8 => unreachable, // Windows only | 804 | error.InvalidWtf8 => unreachable, // Windows only |
| ... | @@ -913,16 +832,20 @@ fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion { | ... | @@ -913,16 +832,20 @@ fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion { |
| 913 | error.Unexpected, | 832 | error.Unexpected, |
| 914 | => |e| return e, | 833 | => |e| return e, |
| 915 | }; | 834 | }; |
| 916 | defer f.close(); | 835 | defer file.close(); |
| 917 | 836 | ||
| 918 | return glibcVerFromSoFile(f) catch |err| switch (err) { | 837 | // Empirically, glibc 2.34 libc.so .dynstr section is 32441 bytes on my system. |
| 838 | var buffer: [8000]u8 = undefined; | ||
| 839 | var file_reader: Io.File.Reader = .initAdapted(file, io, &buffer); | ||
| 840 | |||
| 841 | return glibcVerFromSoFile(&file_reader) catch |err| switch (err) { | ||
| 919 | error.InvalidElfMagic, | 842 | error.InvalidElfMagic, |
| 920 | error.InvalidElfEndian, | 843 | error.InvalidElfEndian, |
| 921 | error.InvalidElfClass, | 844 | error.InvalidElfClass, |
| 922 | error.InvalidElfFile, | 845 | error.InvalidElfFile, |
| 923 | error.InvalidElfVersion, | 846 | error.InvalidElfVersion, |
| 924 | error.InvalidGnuLibCVersion, | 847 | error.InvalidGnuLibCVersion, |
| 925 | error.UnexpectedEndOfFile, | 848 | error.EndOfStream, |
| 926 | => return error.GLibCNotFound, | 849 | => return error.GLibCNotFound, |
| 927 | 850 | ||
| 928 | error.SystemResources, | 851 | error.SystemResources, |
| ... | @@ -934,88 +857,34 @@ fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion { | ... | @@ -934,88 +857,34 @@ fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion { |
| 934 | }; | 857 | }; |
| 935 | } | 858 | } |
| 936 | 859 | ||
| 937 | fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion { | 860 | fn glibcVerFromSoFile(file_reader: *Io.File.Reader) !std.SemanticVersion { |
| 938 | var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined; | 861 | const header = try elf.Header.read(&file_reader.interface); |
| 939 | _ = try preadAtLeast(file, &hdr_buf, 0, hdr_buf.len); | 862 | const str_section_off = header.shoff + @as(u64, header.shentsize) * @as(u64, header.shstrndx); |
| 940 | const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf); | 863 | try file_reader.seekTo(str_section_off); |
| 941 | const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf); | 864 | const shstr = try elf.takeSectionHeader(&file_reader.interface, header.is_64, header.endian); |
| 942 | if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; | 865 | var strtab_buf: [4096]u8 = undefined; |
| 943 | const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI.DATA]) { | 866 | const shstrtab = strtab_buf[0..@min(shstr.sh_size, strtab_buf.len)]; |
| 944 | elf.ELFDATA2LSB => .little, | 867 | try file_reader.seekTo(shstr.sh_offset); |
| 945 | elf.ELFDATA2MSB => .big, | 868 | try file_reader.interface.readSliceAll(shstrtab); |
| 946 | else => return error.InvalidElfEndian, | 869 | const dynstr: struct { offset: u64, size: u64 } = find_dyn_str: { |
| 947 | }; | 870 | var it = header.iterateSectionHeaders(&file_reader.interface); |
| 948 | const need_bswap = elf_endian != native_endian; | 871 | while (it.next()) |shdr| { |
| 949 | if (hdr32.e_ident[elf.EI.VERSION] != 1) return error.InvalidElfVersion; | 872 | const end = mem.findScalarPos(u8, shstrtab, shdr.sh_name, 0) orelse continue; |
| 950 | 873 | const sh_name = shstrtab[shdr.sh_name..end :0]; | |
| 951 | const is_64 = switch (hdr32.e_ident[elf.EI.CLASS]) { | 874 | if (mem.eql(u8, sh_name, ".dynstr")) break :find_dyn_str .{ |
| 952 | elf.ELFCLASS32 => false, | 875 | .offset = shdr.sh_offset, |
| 953 | elf.ELFCLASS64 => true, | 876 | .size = shdr.sh_size, |
| 954 | else => return error.InvalidElfClass, | 877 | }; |
| 878 | } else return error.InvalidGnuLibCVersion; | ||
| 955 | }; | 879 | }; |
| 956 | const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx); | ||
| 957 | var shoff = elfInt(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff); | ||
| 958 | const shentsize = elfInt(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize); | ||
| 959 | const str_section_off = shoff + @as(u64, shentsize) * @as(u64, shstrndx); | ||
| 960 | var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined; | ||
| 961 | if (sh_buf.len < shentsize) return error.InvalidElfFile; | ||
| 962 | |||
| 963 | _ = try preadAtLeast(file, &sh_buf, str_section_off, shentsize); | ||
| 964 | const shstr32: *elf.Elf32_Shdr = @ptrCast(@alignCast(&sh_buf)); | ||
| 965 | const shstr64: *elf.Elf64_Shdr = @ptrCast(@alignCast(&sh_buf)); | ||
| 966 | const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset); | ||
| 967 | const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size); | ||
| 968 | var strtab_buf: [4096:0]u8 = undefined; | ||
| 969 | const shstrtab_len = @min(shstrtab_size, strtab_buf.len); | ||
| 970 | const shstrtab_read_len = try preadAtLeast(file, &strtab_buf, shstrtab_off, shstrtab_len); | ||
| 971 | const shstrtab = strtab_buf[0..shstrtab_read_len]; | ||
| 972 | const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum); | ||
| 973 | var sh_i: u16 = 0; | ||
| 974 | const dynstr: struct { offset: u64, size: u64 } = find_dyn_str: while (sh_i < shnum) { | ||
| 975 | // Reserve some bytes so that we can deref the 64-bit struct fields | ||
| 976 | // even when the ELF file is 32-bits. | ||
| 977 | const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr); | ||
| 978 | const sh_read_byte_len = try preadAtLeast( | ||
| 979 | file, | ||
| 980 | sh_buf[0 .. sh_buf.len - sh_reserve], | ||
| 981 | shoff, | ||
| 982 | shentsize, | ||
| 983 | ); | ||
| 984 | var sh_buf_i: usize = 0; | ||
| 985 | while (sh_buf_i < sh_read_byte_len and sh_i < shnum) : ({ | ||
| 986 | sh_i += 1; | ||
| 987 | shoff += shentsize; | ||
| 988 | sh_buf_i += shentsize; | ||
| 989 | }) { | ||
| 990 | const sh32: *elf.Elf32_Shdr = @ptrCast(@alignCast(&sh_buf[sh_buf_i])); | ||
| 991 | const sh64: *elf.Elf64_Shdr = @ptrCast(@alignCast(&sh_buf[sh_buf_i])); | ||
| 992 | const sh_name_off = elfInt(is_64, need_bswap, sh32.sh_name, sh64.sh_name); | ||
| 993 | const sh_name = mem.sliceTo(shstrtab[sh_name_off..], 0); | ||
| 994 | if (mem.eql(u8, sh_name, ".dynstr")) { | ||
| 995 | break :find_dyn_str .{ | ||
| 996 | .offset = elfInt(is_64, need_bswap, sh32.sh_offset, sh64.sh_offset), | ||
| 997 | .size = elfInt(is_64, need_bswap, sh32.sh_size, sh64.sh_size), | ||
| 998 | }; | ||
| 999 | } | ||
| 1000 | } | ||
| 1001 | } else return error.InvalidGnuLibCVersion; | ||
| 1002 | 880 | ||
| 1003 | // Here we loop over all the strings in the dynstr string table, assuming that any | 881 | // Here we loop over all the strings in the dynstr string table, assuming that any |
| 1004 | // strings that start with "GLIBC_2." indicate the existence of such a glibc version, | 882 | // strings that start with "GLIBC_2." indicate the existence of such a glibc version, |
| 1005 | // and furthermore, that the system-installed glibc is at minimum that version. | 883 | // and furthermore, that the system-installed glibc is at minimum that version. |
| 1006 | |||
| 1007 | // Empirically, glibc 2.34 libc.so .dynstr section is 32441 bytes on my system. | ||
| 1008 | // Here I use double this value plus some headroom. This makes it only need | ||
| 1009 | // a single read syscall here. | ||
| 1010 | var buf: [80000]u8 = undefined; | ||
| 1011 | if (buf.len < dynstr.size) return error.InvalidGnuLibCVersion; | ||
| 1012 | |||
| 1013 | const dynstr_size: usize = @intCast(dynstr.size); | ||
| 1014 | const dynstr_bytes = buf[0..dynstr_size]; | ||
| 1015 | _ = try preadAtLeast(file, dynstr_bytes, dynstr.offset, dynstr_bytes.len); | ||
| 1016 | var it = mem.splitScalar(u8, dynstr_bytes, 0); | ||
| 1017 | var max_ver: std.SemanticVersion = .{ .major = 2, .minor = 2, .patch = 5 }; | 884 | var max_ver: std.SemanticVersion = .{ .major = 2, .minor = 2, .patch = 5 }; |
| 1018 | while (it.next()) |s| { | 885 | |
| 886 | try file_reader.seekTo(dynstr.offset); | ||
| 887 | while (file_reader.interface.takeSentinel(0)) |s| { | ||
| 1019 | if (mem.startsWith(u8, s, "GLIBC_2.")) { | 888 | if (mem.startsWith(u8, s, "GLIBC_2.")) { |
| 1020 | const chopped = s["GLIBC_".len..]; | 889 | const chopped = s["GLIBC_".len..]; |
| 1021 | const ver = Target.Query.parseVersion(chopped) catch |err| switch (err) { | 890 | const ver = Target.Query.parseVersion(chopped) catch |err| switch (err) { |
| ... | @@ -1028,6 +897,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion { | ... | @@ -1028,6 +897,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion { |
| 1028 | } | 897 | } |
| 1029 | } | 898 | } |
| 1030 | } | 899 | } |
| 900 | |||
| 1031 | return max_ver; | 901 | return max_ver; |
| 1032 | } | 902 | } |
| 1033 | 903 | ||
| ... | @@ -1044,11 +914,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion { | ... | @@ -1044,11 +914,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion { |
| 1044 | /// answer to these questions, or if there is a shebang line, then it chases the referenced | 914 | /// answer to these questions, or if there is a shebang line, then it chases the referenced |
| 1045 | /// file recursively. If that does not provide the answer, then the function falls back to | 915 | /// file recursively. If that does not provide the answer, then the function falls back to |
| 1046 | /// defaults. | 916 | /// defaults. |
| 1047 | fn detectAbiAndDynamicLinker( | 917 | fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Target.Query) !Target { |
| 1048 | cpu: Target.Cpu, | ||
| 1049 | os: Target.Os, | ||
| 1050 | query: Target.Query, | ||
| 1051 | ) DetectError!Target { | ||
| 1052 | const native_target_has_ld = comptime Target.DynamicLinker.kind(builtin.os.tag) != .none; | 918 | const native_target_has_ld = comptime Target.DynamicLinker.kind(builtin.os.tag) != .none; |
| 1053 | const is_linux = builtin.target.os.tag == .linux; | 919 | const is_linux = builtin.target.os.tag == .linux; |
| 1054 | const is_illumos = builtin.target.os.tag == .illumos; | 920 | const is_illumos = builtin.target.os.tag == .illumos; |
| ... | @@ -1111,49 +977,52 @@ fn detectAbiAndDynamicLinker( | ... | @@ -1111,49 +977,52 @@ fn detectAbiAndDynamicLinker( |
| 1111 | 977 | ||
| 1112 | const ld_info_list = ld_info_list_buffer[0..ld_info_list_len]; | 978 | const ld_info_list = ld_info_list_buffer[0..ld_info_list_len]; |
| 1113 | 979 | ||
| 980 | var file_reader: Io.File.Reader = undefined; | ||
| 981 | // According to `man 2 execve`: | ||
| 982 | // | ||
| 983 | // The kernel imposes a maximum length on the text | ||
| 984 | // that follows the "#!" characters at the start of a script; | ||
| 985 | // characters beyond the limit are ignored. | ||
| 986 | // Before Linux 5.1, the limit is 127 characters. | ||
| 987 | // Since Linux 5.1, the limit is 255 characters. | ||
| 988 | // | ||
| 989 | // Tests show that bash and zsh consider 255 as total limit, | ||
| 990 | // *including* "#!" characters and ignoring newline. | ||
| 991 | // For safety, we set max length as 255 + \n (1). | ||
| 992 | const max_shebang_line_size = 256; | ||
| 993 | var file_reader_buffer: [4096]u8 = undefined; | ||
| 994 | comptime assert(file_reader_buffer.len >= max_shebang_line_size); | ||
| 995 | |||
| 1114 | // Best case scenario: the executable is dynamically linked, and we can iterate | 996 | // Best case scenario: the executable is dynamically linked, and we can iterate |
| 1115 | // over our own shared objects and find a dynamic linker. | 997 | // over our own shared objects and find a dynamic linker. |
| 1116 | const elf_file = elf_file: { | 998 | const header = elf_file: { |
| 1117 | // This block looks for a shebang line in /usr/bin/env, | 999 | // This block looks for a shebang line in "/usr/bin/env". If it finds |
| 1118 | // if it finds one, then instead of using /usr/bin/env as the ELF file to examine, it uses the file it references instead, | 1000 | // one, then instead of using "/usr/bin/env" as the ELF file to examine, |
| 1119 | // doing the same logic recursively in case it finds another shebang line. | 1001 | // it uses the file it references instead, doing the same logic |
| 1002 | // recursively in case it finds another shebang line. | ||
| 1120 | 1003 | ||
| 1121 | var file_name: []const u8 = switch (os.tag) { | 1004 | var file_name: []const u8 = switch (os.tag) { |
| 1122 | // Since /usr/bin/env is hard-coded into the shebang line of many portable scripts, it's a | 1005 | // Since /usr/bin/env is hard-coded into the shebang line of many |
| 1123 | // reasonably reliable path to start with. | 1006 | // portable scripts, it's a reasonably reliable path to start with. |
| 1124 | else => "/usr/bin/env", | 1007 | else => "/usr/bin/env", |
| 1125 | // Haiku does not have a /usr root directory. | 1008 | // Haiku does not have a /usr root directory. |
| 1126 | .haiku => "/bin/env", | 1009 | .haiku => "/bin/env", |
| 1127 | }; | 1010 | }; |
| 1128 | 1011 | ||
| 1129 | // According to `man 2 execve`: | ||
| 1130 | // | ||
| 1131 | // The kernel imposes a maximum length on the text | ||
| 1132 | // that follows the "#!" characters at the start of a script; | ||
| 1133 | // characters beyond the limit are ignored. | ||
| 1134 | // Before Linux 5.1, the limit is 127 characters. | ||
| 1135 | // Since Linux 5.1, the limit is 255 characters. | ||
| 1136 | // | ||
| 1137 | // Tests show that bash and zsh consider 255 as total limit, | ||
| 1138 | // *including* "#!" characters and ignoring newline. | ||
| 1139 | // For safety, we set max length as 255 + \n (1). | ||
| 1140 | var buffer: [255 + 1]u8 = undefined; | ||
| 1141 | while (true) { | 1012 | while (true) { |
| 1142 | // Interpreter path can be relative on Linux, but | ||
| 1143 | // for simplicity we are asserting it is an absolute path. | ||
| 1144 | const file = fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) { | 1013 | const file = fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) { |
| 1145 | error.NoSpaceLeft => unreachable, | 1014 | error.NoSpaceLeft => return error.Unexpected, |
| 1146 | error.NameTooLong => unreachable, | 1015 | error.NameTooLong => return error.Unexpected, |
| 1147 | error.PathAlreadyExists => unreachable, | 1016 | error.PathAlreadyExists => return error.Unexpected, |
| 1148 | error.SharingViolation => unreachable, | 1017 | error.SharingViolation => return error.Unexpected, |
| 1149 | error.InvalidUtf8 => unreachable, // WASI only | 1018 | error.InvalidUtf8 => return error.Unexpected, // WASI only |
| 1150 | error.InvalidWtf8 => unreachable, // Windows only | 1019 | error.InvalidWtf8 => return error.Unexpected, // Windows only |
| 1151 | error.BadPathName => unreachable, | 1020 | error.BadPathName => return error.Unexpected, |
| 1152 | error.PipeBusy => unreachable, | 1021 | error.PipeBusy => return error.Unexpected, |
| 1153 | error.FileLocksNotSupported => unreachable, | 1022 | error.FileLocksNotSupported => return error.Unexpected, |
| 1154 | error.WouldBlock => unreachable, | 1023 | error.WouldBlock => return error.Unexpected, |
| 1155 | error.FileBusy => unreachable, // opened without write permissions | 1024 | error.FileBusy => return error.Unexpected, // opened without write permissions |
| 1156 | error.AntivirusInterference => unreachable, // Windows-only error | 1025 | error.AntivirusInterference => return error.Unexpected, // Windows-only error |
| 1157 | 1026 | ||
| 1158 | error.IsDir, | 1027 | error.IsDir, |
| 1159 | error.NotDir, | 1028 | error.NotDir, |
| ... | @@ -1164,66 +1033,58 @@ fn detectAbiAndDynamicLinker( | ... | @@ -1164,66 +1033,58 @@ fn detectAbiAndDynamicLinker( |
| 1164 | error.NetworkNotFound, | 1033 | error.NetworkNotFound, |
| 1165 | error.FileTooBig, | 1034 | error.FileTooBig, |
| 1166 | error.Unexpected, | 1035 | error.Unexpected, |
| 1167 | => |e| { | 1036 | => return error.UnableToOpenElfFile, |
| 1168 | std.log.warn("Encountered error: {s}, falling back to default ABI and dynamic linker.", .{@errorName(e)}); | ||
| 1169 | return defaultAbiAndDynamicLinker(cpu, os, query); | ||
| 1170 | }, | ||
| 1171 | 1037 | ||
| 1172 | else => |e| return e, | 1038 | else => |e| return e, |
| 1173 | }; | 1039 | }; |
| 1174 | var is_elf_file = false; | 1040 | var is_elf_file = false; |
| 1175 | defer if (is_elf_file == false) file.close(); | 1041 | defer if (!is_elf_file) file.close(); |
| 1176 | 1042 | ||
| 1177 | // Shortest working interpreter path is "#!/i" (4) | 1043 | file_reader = .initAdapted(file, io, &file_reader_buffer); |
| 1178 | // (interpreter is "/i", assuming all paths are absolute, like in above comment). | 1044 | file_name = undefined; // it aliases file_reader_buffer |
| 1179 | // ELF magic number length is also 4. | 1045 | |
| 1180 | // | 1046 | const header = elf.Header.read(&file_reader.interface) catch |hdr_err| switch (hdr_err) { |
| 1181 | // If file is shorter than that, it is definitely not ELF file | 1047 | error.EndOfStream, |
| 1182 | // nor file with "shebang" line. | 1048 | error.InvalidElfMagic, |
| 1183 | const min_len: usize = 4; | 1049 | => { |
| 1184 | 1050 | const shebang_line = file_reader.interface.takeSentinel('\n') catch |err| switch (err) { | |
| 1185 | const len = preadAtLeast(file, &buffer, 0, min_len) catch |err| switch (err) { | 1051 | error.ReadFailed => return file_reader.err.?, |
| 1186 | error.UnexpectedEndOfFile, | 1052 | // It's neither an ELF file nor file with shebang line. |
| 1187 | error.UnableToReadElfFile, | 1053 | error.EndOfStream, error.StreamTooLong => return error.UnhelpfulFile, |
| 1188 | error.ProcessNotFound, | 1054 | }; |
| 1189 | => return defaultAbiAndDynamicLinker(cpu, os, query), | 1055 | if (!mem.startsWith(u8, shebang_line, "#!")) return error.UnhelpfulFile; |
| 1056 | // We detected shebang, now parse entire line. | ||
| 1057 | |||
| 1058 | // Trim leading "#!", spaces and tabs. | ||
| 1059 | const trimmed_line = mem.trimStart(u8, shebang_line[2..], &.{ ' ', '\t' }); | ||
| 1060 | |||
| 1061 | // This line can have: | ||
| 1062 | // * Interpreter path only, | ||
| 1063 | // * Interpreter path and arguments, all separated by space, tab or NUL character. | ||
| 1064 | // And optionally newline at the end. | ||
| 1065 | const path_maybe_args = mem.trimEnd(u8, trimmed_line, "\n"); | ||
| 1066 | |||
| 1067 | // Separate path and args. | ||
| 1068 | const path_end = mem.indexOfAny(u8, path_maybe_args, &.{ ' ', '\t', 0 }) orelse path_maybe_args.len; | ||
| 1069 | const unvalidated_path = path_maybe_args[0..path_end]; | ||
| 1070 | file_name = if (fs.path.isAbsolute(unvalidated_path)) unvalidated_path else return error.RelativeShebang; | ||
| 1071 | continue; | ||
| 1072 | }, | ||
| 1190 | 1073 | ||
| 1191 | else => |e| return e, | 1074 | error.InvalidElfVersion, |
| 1075 | error.InvalidElfClass, | ||
| 1076 | error.InvalidElfEndian, | ||
| 1077 | => return error.InvalidElfFile, | ||
| 1078 | |||
| 1079 | error.ReadFailed => return file_reader.err.?, | ||
| 1192 | }; | 1080 | }; |
| 1193 | const content = buffer[0..len]; | 1081 | is_elf_file = true; |
| 1194 | 1082 | break :elf_file header; | |
| 1195 | if (mem.eql(u8, content[0..4], std.elf.MAGIC)) { | ||
| 1196 | // It is very likely ELF file! | ||
| 1197 | is_elf_file = true; | ||
| 1198 | break :elf_file file; | ||
| 1199 | } else if (mem.eql(u8, content[0..2], "#!")) { | ||
| 1200 | // We detected shebang, now parse entire line. | ||
| 1201 | |||
| 1202 | // Trim leading "#!", spaces and tabs. | ||
| 1203 | const trimmed_line = mem.trimStart(u8, content[2..], &.{ ' ', '\t' }); | ||
| 1204 | |||
| 1205 | // This line can have: | ||
| 1206 | // * Interpreter path only, | ||
| 1207 | // * Interpreter path and arguments, all separated by space, tab or NUL character. | ||
| 1208 | // And optionally newline at the end. | ||
| 1209 | const path_maybe_args = mem.trimEnd(u8, trimmed_line, "\n"); | ||
| 1210 | |||
| 1211 | // Separate path and args. | ||
| 1212 | const path_end = mem.indexOfAny(u8, path_maybe_args, &.{ ' ', '\t', 0 }) orelse path_maybe_args.len; | ||
| 1213 | |||
| 1214 | file_name = path_maybe_args[0..path_end]; | ||
| 1215 | continue; | ||
| 1216 | } else { | ||
| 1217 | // Not a ELF file, not a shell script with "shebang line", invalid duck. | ||
| 1218 | return defaultAbiAndDynamicLinker(cpu, os, query); | ||
| 1219 | } | ||
| 1220 | } | 1083 | } |
| 1221 | }; | 1084 | }; |
| 1222 | defer elf_file.close(); | 1085 | defer file_reader.file.close(io); |
| 1223 | 1086 | ||
| 1224 | // TODO: inline this function and combine the buffer we already read above to find | 1087 | return abiAndDynamicLinkerFromFile(&file_reader, &header, cpu, os, ld_info_list, query) catch |err| switch (err) { |
| 1225 | // the possible shebang line with the buffer we use for the ELF header. | ||
| 1226 | return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, query) catch |err| switch (err) { | ||
| 1227 | error.FileSystem, | 1088 | error.FileSystem, |
| 1228 | error.SystemResources, | 1089 | error.SystemResources, |
| 1229 | error.SymLinkLoop, | 1090 | error.SymLinkLoop, |
| ... | @@ -1232,6 +1093,8 @@ fn detectAbiAndDynamicLinker( | ... | @@ -1232,6 +1093,8 @@ fn detectAbiAndDynamicLinker( |
| 1232 | error.ProcessNotFound, | 1093 | error.ProcessNotFound, |
| 1233 | => |e| return e, | 1094 | => |e| return e, |
| 1234 | 1095 | ||
| 1096 | error.ReadFailed => return file_reader.err.?, | ||
| 1097 | |||
| 1235 | error.UnableToReadElfFile, | 1098 | error.UnableToReadElfFile, |
| 1236 | error.InvalidElfClass, | 1099 | error.InvalidElfClass, |
| 1237 | error.InvalidElfVersion, | 1100 | error.InvalidElfVersion, |
| ... | @@ -1239,12 +1102,12 @@ fn detectAbiAndDynamicLinker( | ... | @@ -1239,12 +1102,12 @@ fn detectAbiAndDynamicLinker( |
| 1239 | error.InvalidElfFile, | 1102 | error.InvalidElfFile, |
| 1240 | error.InvalidElfMagic, | 1103 | error.InvalidElfMagic, |
| 1241 | error.Unexpected, | 1104 | error.Unexpected, |
| 1242 | error.UnexpectedEndOfFile, | 1105 | error.EndOfStream, |
| 1243 | error.NameTooLong, | 1106 | error.NameTooLong, |
| 1244 | error.StaticElfFile, | 1107 | error.StaticElfFile, |
| 1245 | // Finally, we fall back on the standard path. | 1108 | // Finally, we fall back on the standard path. |
| 1246 | => |e| { | 1109 | => |e| { |
| 1247 | std.log.warn("Encountered error: {s}, falling back to default ABI and dynamic linker.", .{@errorName(e)}); | 1110 | std.log.warn("encountered {t}; falling back to default ABI and dynamic linker", .{e}); |
| 1248 | return defaultAbiAndDynamicLinker(cpu, os, query); | 1111 | return defaultAbiAndDynamicLinker(cpu, os, query); |
| 1249 | }, | 1112 | }, |
| 1250 | }; | 1113 | }; |
| ... | @@ -1269,59 +1132,6 @@ const LdInfo = struct { | ... | @@ -1269,59 +1132,6 @@ const LdInfo = struct { |
| 1269 | abi: Target.Abi, | 1132 | abi: Target.Abi, |
| 1270 | }; | 1133 | }; |
| 1271 | 1134 | ||
| 1272 | fn preadAtLeast(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize { | ||
| 1273 | var i: usize = 0; | ||
| 1274 | while (i < min_read_len) { | ||
| 1275 | const len = file.pread(buf[i..], offset + i) catch |err| switch (err) { | ||
| 1276 | error.OperationAborted => unreachable, // Windows-only | ||
| 1277 | error.WouldBlock => unreachable, // Did not request blocking mode | ||
| 1278 | error.Canceled => unreachable, // timerfd is unseekable | ||
| 1279 | error.NotOpenForReading => unreachable, | ||
| 1280 | error.SystemResources => return error.SystemResources, | ||
| 1281 | error.IsDir => return error.UnableToReadElfFile, | ||
| 1282 | error.BrokenPipe => return error.UnableToReadElfFile, | ||
| 1283 | error.Unseekable => return error.UnableToReadElfFile, | ||
| 1284 | error.ConnectionResetByPeer => return error.UnableToReadElfFile, | ||
| 1285 | error.ConnectionTimedOut => return error.UnableToReadElfFile, | ||
| 1286 | error.SocketUnconnected => return error.UnableToReadElfFile, | ||
| 1287 | error.Unexpected => return error.Unexpected, | ||
| 1288 | error.InputOutput => return error.FileSystem, | ||
| 1289 | error.AccessDenied => return error.Unexpected, | ||
| 1290 | error.ProcessNotFound => return error.ProcessNotFound, | ||
| 1291 | error.LockViolation => return error.UnableToReadElfFile, | ||
| 1292 | }; | ||
| 1293 | if (len == 0) return error.UnexpectedEndOfFile; | ||
| 1294 | i += len; | ||
| 1295 | } | ||
| 1296 | return i; | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | fn elfInt(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) { | ||
| 1300 | if (is_64) { | ||
| 1301 | if (need_bswap) { | ||
| 1302 | return @byteSwap(int_64); | ||
| 1303 | } else { | ||
| 1304 | return int_64; | ||
| 1305 | } | ||
| 1306 | } else { | ||
| 1307 | if (need_bswap) { | ||
| 1308 | return @byteSwap(int_32); | ||
| 1309 | } else { | ||
| 1310 | return int_32; | ||
| 1311 | } | ||
| 1312 | } | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | const builtin = @import("builtin"); | ||
| 1316 | const std = @import("../std.zig"); | ||
| 1317 | const mem = std.mem; | ||
| 1318 | const elf = std.elf; | ||
| 1319 | const fs = std.fs; | ||
| 1320 | const assert = std.debug.assert; | ||
| 1321 | const Target = std.Target; | ||
| 1322 | const native_endian = builtin.cpu.arch.endian(); | ||
| 1323 | const posix = std.posix; | ||
| 1324 | |||
| 1325 | test { | 1135 | test { |
| 1326 | _ = NativePaths; | 1136 | _ = NativePaths; |
| 1327 | 1137 |
src/main.zig+53-36| ... | @@ -1,5 +1,8 @@ | ... | @@ -1,5 +1,8 @@ |
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const native_os = builtin.os.tag; | ||
| 3 | |||
| 4 | const std = @import("std"); | ||
| 5 | const Io = std.Io; | ||
| 3 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 4 | const fs = std.fs; | 7 | const fs = std.fs; |
| 5 | const mem = std.mem; | 8 | const mem = std.mem; |
| ... | @@ -10,7 +13,6 @@ const Color = std.zig.Color; | ... | @@ -10,7 +13,6 @@ const Color = std.zig.Color; |
| 10 | const warn = std.log.warn; | 13 | const warn = std.log.warn; |
| 11 | const ThreadPool = std.Thread.Pool; | 14 | const ThreadPool = std.Thread.Pool; |
| 12 | const cleanExit = std.process.cleanExit; | 15 | const cleanExit = std.process.cleanExit; |
| 13 | const native_os = builtin.os.tag; | ||
| 14 | const Cache = std.Build.Cache; | 16 | const Cache = std.Build.Cache; |
| 15 | const Path = std.Build.Cache.Path; | 17 | const Path = std.Build.Cache.Path; |
| 16 | const Directory = std.Build.Cache.Directory; | 18 | const Directory = std.Build.Cache.Directory; |
| ... | @@ -245,26 +247,30 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -245,26 +247,30 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 245 | } | 247 | } |
| 246 | } | 248 | } |
| 247 | 249 | ||
| 250 | var threaded: Io.Threaded = .init(gpa); | ||
| 251 | defer threaded.deinit(); | ||
| 252 | const io = threaded.io(); | ||
| 253 | |||
| 248 | const cmd = args[1]; | 254 | const cmd = args[1]; |
| 249 | const cmd_args = args[2..]; | 255 | const cmd_args = args[2..]; |
| 250 | if (mem.eql(u8, cmd, "build-exe")) { | 256 | if (mem.eql(u8, cmd, "build-exe")) { |
| 251 | dev.check(.build_exe_command); | 257 | dev.check(.build_exe_command); |
| 252 | return buildOutputType(gpa, arena, args, .{ .build = .Exe }); | 258 | return buildOutputType(gpa, arena, io, args, .{ .build = .Exe }); |
| 253 | } else if (mem.eql(u8, cmd, "build-lib")) { | 259 | } else if (mem.eql(u8, cmd, "build-lib")) { |
| 254 | dev.check(.build_lib_command); | 260 | dev.check(.build_lib_command); |
| 255 | return buildOutputType(gpa, arena, args, .{ .build = .Lib }); | 261 | return buildOutputType(gpa, arena, io, args, .{ .build = .Lib }); |
| 256 | } else if (mem.eql(u8, cmd, "build-obj")) { | 262 | } else if (mem.eql(u8, cmd, "build-obj")) { |
| 257 | dev.check(.build_obj_command); | 263 | dev.check(.build_obj_command); |
| 258 | return buildOutputType(gpa, arena, args, .{ .build = .Obj }); | 264 | return buildOutputType(gpa, arena, io, args, .{ .build = .Obj }); |
| 259 | } else if (mem.eql(u8, cmd, "test")) { | 265 | } else if (mem.eql(u8, cmd, "test")) { |
| 260 | dev.check(.test_command); | 266 | dev.check(.test_command); |
| 261 | return buildOutputType(gpa, arena, args, .zig_test); | 267 | return buildOutputType(gpa, arena, io, args, .zig_test); |
| 262 | } else if (mem.eql(u8, cmd, "test-obj")) { | 268 | } else if (mem.eql(u8, cmd, "test-obj")) { |
| 263 | dev.check(.test_command); | 269 | dev.check(.test_command); |
| 264 | return buildOutputType(gpa, arena, args, .zig_test_obj); | 270 | return buildOutputType(gpa, arena, io, args, .zig_test_obj); |
| 265 | } else if (mem.eql(u8, cmd, "run")) { | 271 | } else if (mem.eql(u8, cmd, "run")) { |
| 266 | dev.check(.run_command); | 272 | dev.check(.run_command); |
| 267 | return buildOutputType(gpa, arena, args, .run); | 273 | return buildOutputType(gpa, arena, io, args, .run); |
| 268 | } else if (mem.eql(u8, cmd, "dlltool") or | 274 | } else if (mem.eql(u8, cmd, "dlltool") or |
| 269 | mem.eql(u8, cmd, "ranlib") or | 275 | mem.eql(u8, cmd, "ranlib") or |
| 270 | mem.eql(u8, cmd, "lib") or | 276 | mem.eql(u8, cmd, "lib") or |
| ... | @@ -274,7 +280,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -274,7 +280,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 274 | return process.exit(try llvmArMain(arena, args)); | 280 | return process.exit(try llvmArMain(arena, args)); |
| 275 | } else if (mem.eql(u8, cmd, "build")) { | 281 | } else if (mem.eql(u8, cmd, "build")) { |
| 276 | dev.check(.build_command); | 282 | dev.check(.build_command); |
| 277 | return cmdBuild(gpa, arena, cmd_args); | 283 | return cmdBuild(gpa, arena, io, cmd_args); |
| 278 | } else if (mem.eql(u8, cmd, "clang") or | 284 | } else if (mem.eql(u8, cmd, "clang") or |
| 279 | mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as")) | 285 | mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as")) |
| 280 | { | 286 | { |
| ... | @@ -288,16 +294,16 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -288,16 +294,16 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 288 | return process.exit(try lldMain(arena, args, true)); | 294 | return process.exit(try lldMain(arena, args, true)); |
| 289 | } else if (mem.eql(u8, cmd, "cc")) { | 295 | } else if (mem.eql(u8, cmd, "cc")) { |
| 290 | dev.check(.cc_command); | 296 | dev.check(.cc_command); |
| 291 | return buildOutputType(gpa, arena, args, .cc); | 297 | return buildOutputType(gpa, arena, io, args, .cc); |
| 292 | } else if (mem.eql(u8, cmd, "c++")) { | 298 | } else if (mem.eql(u8, cmd, "c++")) { |
| 293 | dev.check(.cc_command); | 299 | dev.check(.cc_command); |
| 294 | return buildOutputType(gpa, arena, args, .cpp); | 300 | return buildOutputType(gpa, arena, io, args, .cpp); |
| 295 | } else if (mem.eql(u8, cmd, "translate-c")) { | 301 | } else if (mem.eql(u8, cmd, "translate-c")) { |
| 296 | dev.check(.translate_c_command); | 302 | dev.check(.translate_c_command); |
| 297 | return buildOutputType(gpa, arena, args, .translate_c); | 303 | return buildOutputType(gpa, arena, io, args, .translate_c); |
| 298 | } else if (mem.eql(u8, cmd, "rc")) { | 304 | } else if (mem.eql(u8, cmd, "rc")) { |
| 299 | const use_server = cmd_args.len > 0 and std.mem.eql(u8, cmd_args[0], "--zig-integration"); | 305 | const use_server = cmd_args.len > 0 and std.mem.eql(u8, cmd_args[0], "--zig-integration"); |
| 300 | return jitCmd(gpa, arena, cmd_args, .{ | 306 | return jitCmd(gpa, arena, io, cmd_args, .{ |
| 301 | .cmd_name = "resinator", | 307 | .cmd_name = "resinator", |
| 302 | .root_src_path = "resinator/main.zig", | 308 | .root_src_path = "resinator/main.zig", |
| 303 | .depend_on_aro = true, | 309 | .depend_on_aro = true, |
| ... | @@ -308,20 +314,20 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -308,20 +314,20 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 308 | dev.check(.fmt_command); | 314 | dev.check(.fmt_command); |
| 309 | return @import("fmt.zig").run(gpa, arena, cmd_args); | 315 | return @import("fmt.zig").run(gpa, arena, cmd_args); |
| 310 | } else if (mem.eql(u8, cmd, "objcopy")) { | 316 | } else if (mem.eql(u8, cmd, "objcopy")) { |
| 311 | return jitCmd(gpa, arena, cmd_args, .{ | 317 | return jitCmd(gpa, arena, io, cmd_args, .{ |
| 312 | .cmd_name = "objcopy", | 318 | .cmd_name = "objcopy", |
| 313 | .root_src_path = "objcopy.zig", | 319 | .root_src_path = "objcopy.zig", |
| 314 | }); | 320 | }); |
| 315 | } else if (mem.eql(u8, cmd, "fetch")) { | 321 | } else if (mem.eql(u8, cmd, "fetch")) { |
| 316 | return cmdFetch(gpa, arena, cmd_args); | 322 | return cmdFetch(gpa, arena, cmd_args); |
| 317 | } else if (mem.eql(u8, cmd, "libc")) { | 323 | } else if (mem.eql(u8, cmd, "libc")) { |
| 318 | return jitCmd(gpa, arena, cmd_args, .{ | 324 | return jitCmd(gpa, arena, io, cmd_args, .{ |
| 319 | .cmd_name = "libc", | 325 | .cmd_name = "libc", |
| 320 | .root_src_path = "libc.zig", | 326 | .root_src_path = "libc.zig", |
| 321 | .prepend_zig_lib_dir_path = true, | 327 | .prepend_zig_lib_dir_path = true, |
| 322 | }); | 328 | }); |
| 323 | } else if (mem.eql(u8, cmd, "std")) { | 329 | } else if (mem.eql(u8, cmd, "std")) { |
| 324 | return jitCmd(gpa, arena, cmd_args, .{ | 330 | return jitCmd(gpa, arena, io, cmd_args, .{ |
| 325 | .cmd_name = "std", | 331 | .cmd_name = "std", |
| 326 | .root_src_path = "std-docs.zig", | 332 | .root_src_path = "std-docs.zig", |
| 327 | .prepend_zig_lib_dir_path = true, | 333 | .prepend_zig_lib_dir_path = true, |
| ... | @@ -332,7 +338,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -332,7 +338,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 332 | return cmdInit(gpa, arena, cmd_args); | 338 | return cmdInit(gpa, arena, cmd_args); |
| 333 | } else if (mem.eql(u8, cmd, "targets")) { | 339 | } else if (mem.eql(u8, cmd, "targets")) { |
| 334 | dev.check(.targets_command); | 340 | dev.check(.targets_command); |
| 335 | const host = std.zig.resolveTargetQueryOrFatal(.{}); | 341 | const host = std.zig.resolveTargetQueryOrFatal(io, .{}); |
| 336 | var stdout_writer = fs.File.stdout().writer(&stdout_buffer); | 342 | var stdout_writer = fs.File.stdout().writer(&stdout_buffer); |
| 337 | try @import("print_targets.zig").cmdTargets(arena, cmd_args, &stdout_writer.interface, &host); | 343 | try @import("print_targets.zig").cmdTargets(arena, cmd_args, &stdout_writer.interface, &host); |
| 338 | return stdout_writer.interface.flush(); | 344 | return stdout_writer.interface.flush(); |
| ... | @@ -351,7 +357,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -351,7 +357,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 351 | ); | 357 | ); |
| 352 | return stdout_writer.interface.flush(); | 358 | return stdout_writer.interface.flush(); |
| 353 | } else if (mem.eql(u8, cmd, "reduce")) { | 359 | } else if (mem.eql(u8, cmd, "reduce")) { |
| 354 | return jitCmd(gpa, arena, cmd_args, .{ | 360 | return jitCmd(gpa, arena, io, cmd_args, .{ |
| 355 | .cmd_name = "reduce", | 361 | .cmd_name = "reduce", |
| 356 | .root_src_path = "reduce.zig", | 362 | .root_src_path = "reduce.zig", |
| 357 | }); | 363 | }); |
| ... | @@ -364,7 +370,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -364,7 +370,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 364 | } else if (mem.eql(u8, cmd, "ast-check")) { | 370 | } else if (mem.eql(u8, cmd, "ast-check")) { |
| 365 | return cmdAstCheck(arena, cmd_args); | 371 | return cmdAstCheck(arena, cmd_args); |
| 366 | } else if (mem.eql(u8, cmd, "detect-cpu")) { | 372 | } else if (mem.eql(u8, cmd, "detect-cpu")) { |
| 367 | return cmdDetectCpu(cmd_args); | 373 | return cmdDetectCpu(io, cmd_args); |
| 368 | } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "changelist")) { | 374 | } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "changelist")) { |
| 369 | return cmdChangelist(arena, cmd_args); | 375 | return cmdChangelist(arena, cmd_args); |
| 370 | } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "dump-zir")) { | 376 | } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "dump-zir")) { |
| ... | @@ -792,6 +798,7 @@ const CliModule = struct { | ... | @@ -792,6 +798,7 @@ const CliModule = struct { |
| 792 | fn buildOutputType( | 798 | fn buildOutputType( |
| 793 | gpa: Allocator, | 799 | gpa: Allocator, |
| 794 | arena: Allocator, | 800 | arena: Allocator, |
| 801 | io: Io, | ||
| 795 | all_args: []const []const u8, | 802 | all_args: []const []const u8, |
| 796 | arg_mode: ArgMode, | 803 | arg_mode: ArgMode, |
| 797 | ) !void { | 804 | ) !void { |
| ... | @@ -3017,7 +3024,7 @@ fn buildOutputType( | ... | @@ -3017,7 +3024,7 @@ fn buildOutputType( |
| 3017 | create_module.opts.emit_bin = emit_bin != .no; | 3024 | create_module.opts.emit_bin = emit_bin != .no; |
| 3018 | create_module.opts.any_c_source_files = create_module.c_source_files.items.len != 0; | 3025 | create_module.opts.any_c_source_files = create_module.c_source_files.items.len != 0; |
| 3019 | 3026 | ||
| 3020 | const main_mod = try createModule(gpa, arena, &create_module, 0, null, color); | 3027 | const main_mod = try createModule(gpa, arena, io, &create_module, 0, null, color); |
| 3021 | for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| { | 3028 | for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| { |
| 3022 | if (cli_mod.resolved == null) | 3029 | if (cli_mod.resolved == null) |
| 3023 | fatal("module '{s}' declared but not used", .{key}); | 3030 | fatal("module '{s}' declared but not used", .{key}); |
| ... | @@ -3545,6 +3552,7 @@ fn buildOutputType( | ... | @@ -3545,6 +3552,7 @@ fn buildOutputType( |
| 3545 | var stdin_reader = fs.File.stdin().reader(&stdin_buffer); | 3552 | var stdin_reader = fs.File.stdin().reader(&stdin_buffer); |
| 3546 | var stdout_writer = fs.File.stdout().writer(&stdout_buffer); | 3553 | var stdout_writer = fs.File.stdout().writer(&stdout_buffer); |
| 3547 | try serve( | 3554 | try serve( |
| 3555 | io, | ||
| 3548 | comp, | 3556 | comp, |
| 3549 | &stdin_reader.interface, | 3557 | &stdin_reader.interface, |
| 3550 | &stdout_writer.interface, | 3558 | &stdout_writer.interface, |
| ... | @@ -3571,6 +3579,7 @@ fn buildOutputType( | ... | @@ -3571,6 +3579,7 @@ fn buildOutputType( |
| 3571 | var output = conn.stream.writer(&stdout_buffer); | 3579 | var output = conn.stream.writer(&stdout_buffer); |
| 3572 | 3580 | ||
| 3573 | try serve( | 3581 | try serve( |
| 3582 | io, | ||
| 3574 | comp, | 3583 | comp, |
| 3575 | input.interface(), | 3584 | input.interface(), |
| 3576 | &output.interface, | 3585 | &output.interface, |
| ... | @@ -3646,6 +3655,7 @@ fn buildOutputType( | ... | @@ -3646,6 +3655,7 @@ fn buildOutputType( |
| 3646 | comp, | 3655 | comp, |
| 3647 | gpa, | 3656 | gpa, |
| 3648 | arena, | 3657 | arena, |
| 3658 | io, | ||
| 3649 | test_exec_args.items, | 3659 | test_exec_args.items, |
| 3650 | self_exe_path, | 3660 | self_exe_path, |
| 3651 | arg_mode, | 3661 | arg_mode, |
| ... | @@ -3704,6 +3714,7 @@ const CreateModule = struct { | ... | @@ -3704,6 +3714,7 @@ const CreateModule = struct { |
| 3704 | fn createModule( | 3714 | fn createModule( |
| 3705 | gpa: Allocator, | 3715 | gpa: Allocator, |
| 3706 | arena: Allocator, | 3716 | arena: Allocator, |
| 3717 | io: Io, | ||
| 3707 | create_module: *CreateModule, | 3718 | create_module: *CreateModule, |
| 3708 | index: usize, | 3719 | index: usize, |
| 3709 | parent: ?*Package.Module, | 3720 | parent: ?*Package.Module, |
| ... | @@ -3777,7 +3788,7 @@ fn createModule( | ... | @@ -3777,7 +3788,7 @@ fn createModule( |
| 3777 | } | 3788 | } |
| 3778 | 3789 | ||
| 3779 | const target_query = std.zig.parseTargetQueryOrReportFatalError(arena, target_parse_options); | 3790 | const target_query = std.zig.parseTargetQueryOrReportFatalError(arena, target_parse_options); |
| 3780 | const target = std.zig.resolveTargetQueryOrFatal(target_query); | 3791 | const target = std.zig.resolveTargetQueryOrFatal(io, target_query); |
| 3781 | break :t .{ | 3792 | break :t .{ |
| 3782 | .result = target, | 3793 | .result = target, |
| 3783 | .is_native_os = target_query.isNativeOs(), | 3794 | .is_native_os = target_query.isNativeOs(), |
| ... | @@ -4022,7 +4033,7 @@ fn createModule( | ... | @@ -4022,7 +4033,7 @@ fn createModule( |
| 4022 | for (cli_mod.deps) |dep| { | 4033 | for (cli_mod.deps) |dep| { |
| 4023 | const dep_index = create_module.modules.getIndex(dep.value) orelse | 4034 | const dep_index = create_module.modules.getIndex(dep.value) orelse |
| 4024 | fatal("module '{s}' depends on non-existent module '{s}'", .{ name, dep.key }); | 4035 | fatal("module '{s}' depends on non-existent module '{s}'", .{ name, dep.key }); |
| 4025 | const dep_mod = try createModule(gpa, arena, create_module, dep_index, mod, color); | 4036 | const dep_mod = try createModule(gpa, arena, io, create_module, dep_index, mod, color); |
| 4026 | try mod.deps.put(arena, dep.key, dep_mod); | 4037 | try mod.deps.put(arena, dep.key, dep_mod); |
| 4027 | } | 4038 | } |
| 4028 | 4039 | ||
| ... | @@ -4038,9 +4049,10 @@ fn saveState(comp: *Compilation, incremental: bool) void { | ... | @@ -4038,9 +4049,10 @@ fn saveState(comp: *Compilation, incremental: bool) void { |
| 4038 | } | 4049 | } |
| 4039 | 4050 | ||
| 4040 | fn serve( | 4051 | fn serve( |
| 4052 | io: Io, | ||
| 4041 | comp: *Compilation, | 4053 | comp: *Compilation, |
| 4042 | in: *std.Io.Reader, | 4054 | in: *Io.Reader, |
| 4043 | out: *std.Io.Writer, | 4055 | out: *Io.Writer, |
| 4044 | test_exec_args: []const ?[]const u8, | 4056 | test_exec_args: []const ?[]const u8, |
| 4045 | self_exe_path: ?[]const u8, | 4057 | self_exe_path: ?[]const u8, |
| 4046 | arg_mode: ArgMode, | 4058 | arg_mode: ArgMode, |
| ... | @@ -4090,7 +4102,7 @@ fn serve( | ... | @@ -4090,7 +4102,7 @@ fn serve( |
| 4090 | defer arena_instance.deinit(); | 4102 | defer arena_instance.deinit(); |
| 4091 | const arena = arena_instance.allocator(); | 4103 | const arena = arena_instance.allocator(); |
| 4092 | var output: Compilation.CImportResult = undefined; | 4104 | var output: Compilation.CImportResult = undefined; |
| 4093 | try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node); | 4105 | try cmdTranslateC(io, comp, arena, &output, file_system_inputs, main_progress_node); |
| 4094 | defer output.deinit(gpa); | 4106 | defer output.deinit(gpa); |
| 4095 | 4107 | ||
| 4096 | if (file_system_inputs.items.len != 0) { | 4108 | if (file_system_inputs.items.len != 0) { |
| ... | @@ -4126,6 +4138,7 @@ fn serve( | ... | @@ -4126,6 +4138,7 @@ fn serve( |
| 4126 | // comp, | 4138 | // comp, |
| 4127 | // gpa, | 4139 | // gpa, |
| 4128 | // arena, | 4140 | // arena, |
| 4141 | // io, | ||
| 4129 | // test_exec_args, | 4142 | // test_exec_args, |
| 4130 | // self_exe_path.?, | 4143 | // self_exe_path.?, |
| 4131 | // arg_mode, | 4144 | // arg_mode, |
| ... | @@ -4280,6 +4293,7 @@ fn runOrTest( | ... | @@ -4280,6 +4293,7 @@ fn runOrTest( |
| 4280 | comp: *Compilation, | 4293 | comp: *Compilation, |
| 4281 | gpa: Allocator, | 4294 | gpa: Allocator, |
| 4282 | arena: Allocator, | 4295 | arena: Allocator, |
| 4296 | io: Io, | ||
| 4283 | test_exec_args: []const ?[]const u8, | 4297 | test_exec_args: []const ?[]const u8, |
| 4284 | self_exe_path: []const u8, | 4298 | self_exe_path: []const u8, |
| 4285 | arg_mode: ArgMode, | 4299 | arg_mode: ArgMode, |
| ... | @@ -4334,7 +4348,7 @@ fn runOrTest( | ... | @@ -4334,7 +4348,7 @@ fn runOrTest( |
| 4334 | std.debug.lockStdErr(); | 4348 | std.debug.lockStdErr(); |
| 4335 | const err = process.execve(gpa, argv.items, &env_map); | 4349 | const err = process.execve(gpa, argv.items, &env_map); |
| 4336 | std.debug.unlockStdErr(); | 4350 | std.debug.unlockStdErr(); |
| 4337 | try warnAboutForeignBinaries(arena, arg_mode, target, link_libc); | 4351 | try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc); |
| 4338 | const cmd = try std.mem.join(arena, " ", argv.items); | 4352 | const cmd = try std.mem.join(arena, " ", argv.items); |
| 4339 | fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd }); | 4353 | fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd }); |
| 4340 | } else if (process.can_spawn) { | 4354 | } else if (process.can_spawn) { |
| ... | @@ -4355,7 +4369,7 @@ fn runOrTest( | ... | @@ -4355,7 +4369,7 @@ fn runOrTest( |
| 4355 | break :t child.spawnAndWait(); | 4369 | break :t child.spawnAndWait(); |
| 4356 | }; | 4370 | }; |
| 4357 | const term = term_result catch |err| { | 4371 | const term = term_result catch |err| { |
| 4358 | try warnAboutForeignBinaries(arena, arg_mode, target, link_libc); | 4372 | try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc); |
| 4359 | const cmd = try std.mem.join(arena, " ", argv.items); | 4373 | const cmd = try std.mem.join(arena, " ", argv.items); |
| 4360 | fatal("the following command failed with '{s}':\n{s}", .{ @errorName(err), cmd }); | 4374 | fatal("the following command failed with '{s}':\n{s}", .{ @errorName(err), cmd }); |
| 4361 | }; | 4375 | }; |
| ... | @@ -4594,11 +4608,12 @@ fn cmdTranslateC( | ... | @@ -4594,11 +4608,12 @@ fn cmdTranslateC( |
| 4594 | pub fn translateC( | 4608 | pub fn translateC( |
| 4595 | gpa: Allocator, | 4609 | gpa: Allocator, |
| 4596 | arena: Allocator, | 4610 | arena: Allocator, |
| 4611 | io: Io, | ||
| 4597 | argv: []const []const u8, | 4612 | argv: []const []const u8, |
| 4598 | prog_node: std.Progress.Node, | 4613 | prog_node: std.Progress.Node, |
| 4599 | capture: ?*[]u8, | 4614 | capture: ?*[]u8, |
| 4600 | ) !void { | 4615 | ) !void { |
| 4601 | try jitCmd(gpa, arena, argv, .{ | 4616 | try jitCmd(gpa, arena, io, argv, .{ |
| 4602 | .cmd_name = "translate-c", | 4617 | .cmd_name = "translate-c", |
| 4603 | .root_src_path = "translate-c/main.zig", | 4618 | .root_src_path = "translate-c/main.zig", |
| 4604 | .depend_on_aro = true, | 4619 | .depend_on_aro = true, |
| ... | @@ -4755,7 +4770,7 @@ test sanitizeExampleName { | ... | @@ -4755,7 +4770,7 @@ test sanitizeExampleName { |
| 4755 | try std.testing.expectEqualStrings("test_project", try sanitizeExampleName(arena, "test project")); | 4770 | try std.testing.expectEqualStrings("test_project", try sanitizeExampleName(arena, "test project")); |
| 4756 | } | 4771 | } |
| 4757 | 4772 | ||
| 4758 | fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | 4773 | fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !void { |
| 4759 | dev.check(.build_command); | 4774 | dev.check(.build_command); |
| 4760 | 4775 | ||
| 4761 | var build_file: ?[]const u8 = null; | 4776 | var build_file: ?[]const u8 = null; |
| ... | @@ -4983,7 +4998,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -4983,7 +4998,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 4983 | .arch_os_abi = triple, | 4998 | .arch_os_abi = triple, |
| 4984 | }); | 4999 | }); |
| 4985 | break :t .{ | 5000 | break :t .{ |
| 4986 | .result = std.zig.resolveTargetQueryOrFatal(target_query), | 5001 | .result = std.zig.resolveTargetQueryOrFatal(io, target_query), |
| 4987 | .is_native_os = false, | 5002 | .is_native_os = false, |
| 4988 | .is_native_abi = false, | 5003 | .is_native_abi = false, |
| 4989 | .is_explicit_dynamic_linker = false, | 5004 | .is_explicit_dynamic_linker = false, |
| ... | @@ -4991,7 +5006,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -4991,7 +5006,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 4991 | } | 5006 | } |
| 4992 | } | 5007 | } |
| 4993 | break :t .{ | 5008 | break :t .{ |
| 4994 | .result = std.zig.resolveTargetQueryOrFatal(.{}), | 5009 | .result = std.zig.resolveTargetQueryOrFatal(io, .{}), |
| 4995 | .is_native_os = true, | 5010 | .is_native_os = true, |
| 4996 | .is_native_abi = true, | 5011 | .is_native_abi = true, |
| 4997 | .is_explicit_dynamic_linker = false, | 5012 | .is_explicit_dynamic_linker = false, |
| ... | @@ -5400,6 +5415,7 @@ const JitCmdOptions = struct { | ... | @@ -5400,6 +5415,7 @@ const JitCmdOptions = struct { |
| 5400 | fn jitCmd( | 5415 | fn jitCmd( |
| 5401 | gpa: Allocator, | 5416 | gpa: Allocator, |
| 5402 | arena: Allocator, | 5417 | arena: Allocator, |
| 5418 | io: Io, | ||
| 5403 | args: []const []const u8, | 5419 | args: []const []const u8, |
| 5404 | options: JitCmdOptions, | 5420 | options: JitCmdOptions, |
| 5405 | ) !void { | 5421 | ) !void { |
| ... | @@ -5412,7 +5428,7 @@ fn jitCmd( | ... | @@ -5412,7 +5428,7 @@ fn jitCmd( |
| 5412 | 5428 | ||
| 5413 | const target_query: std.Target.Query = .{}; | 5429 | const target_query: std.Target.Query = .{}; |
| 5414 | const resolved_target: Package.Module.ResolvedTarget = .{ | 5430 | const resolved_target: Package.Module.ResolvedTarget = .{ |
| 5415 | .result = std.zig.resolveTargetQueryOrFatal(target_query), | 5431 | .result = std.zig.resolveTargetQueryOrFatal(io, target_query), |
| 5416 | .is_native_os = true, | 5432 | .is_native_os = true, |
| 5417 | .is_native_abi = true, | 5433 | .is_native_abi = true, |
| 5418 | .is_explicit_dynamic_linker = false, | 5434 | .is_explicit_dynamic_linker = false, |
| ... | @@ -6209,7 +6225,7 @@ fn cmdAstCheck( | ... | @@ -6209,7 +6225,7 @@ fn cmdAstCheck( |
| 6209 | } | 6225 | } |
| 6210 | } | 6226 | } |
| 6211 | 6227 | ||
| 6212 | fn cmdDetectCpu(args: []const []const u8) !void { | 6228 | fn cmdDetectCpu(io: Io, args: []const []const u8) !void { |
| 6213 | dev.check(.detect_cpu_command); | 6229 | dev.check(.detect_cpu_command); |
| 6214 | 6230 | ||
| 6215 | const detect_cpu_usage = | 6231 | const detect_cpu_usage = |
| ... | @@ -6254,7 +6270,7 @@ fn cmdDetectCpu(args: []const []const u8) !void { | ... | @@ -6254,7 +6270,7 @@ fn cmdDetectCpu(args: []const []const u8) !void { |
| 6254 | const cpu = try detectNativeCpuWithLLVM(builtin.cpu.arch, name, features); | 6270 | const cpu = try detectNativeCpuWithLLVM(builtin.cpu.arch, name, features); |
| 6255 | try printCpu(cpu); | 6271 | try printCpu(cpu); |
| 6256 | } else { | 6272 | } else { |
| 6257 | const host_target = std.zig.resolveTargetQueryOrFatal(.{}); | 6273 | const host_target = std.zig.resolveTargetQueryOrFatal(io, .{}); |
| 6258 | try printCpu(host_target.cpu); | 6274 | try printCpu(host_target.cpu); |
| 6259 | } | 6275 | } |
| 6260 | } | 6276 | } |
| ... | @@ -6521,13 +6537,14 @@ fn prefixedIntArg(arg: []const u8, prefix: []const u8) ?u64 { | ... | @@ -6521,13 +6537,14 @@ fn prefixedIntArg(arg: []const u8, prefix: []const u8) ?u64 { |
| 6521 | } | 6537 | } |
| 6522 | 6538 | ||
| 6523 | fn warnAboutForeignBinaries( | 6539 | fn warnAboutForeignBinaries( |
| 6540 | io: Io, | ||
| 6524 | arena: Allocator, | 6541 | arena: Allocator, |
| 6525 | arg_mode: ArgMode, | 6542 | arg_mode: ArgMode, |
| 6526 | target: *const std.Target, | 6543 | target: *const std.Target, |
| 6527 | link_libc: bool, | 6544 | link_libc: bool, |
| 6528 | ) !void { | 6545 | ) !void { |
| 6529 | const host_query: std.Target.Query = .{}; | 6546 | const host_query: std.Target.Query = .{}; |
| 6530 | const host_target = std.zig.resolveTargetQueryOrFatal(host_query); | 6547 | const host_target = std.zig.resolveTargetQueryOrFatal(io, host_query); |
| 6531 | 6548 | ||
| 6532 | switch (std.zig.system.getExternalExecutor(&host_target, target, .{ .link_libc = link_libc })) { | 6549 | switch (std.zig.system.getExternalExecutor(&host_target, target, .{ .link_libc = link_libc })) { |
| 6533 | .native => return, | 6550 | .native => return, |
| ... | @@ -7080,7 +7097,7 @@ fn cmdFetch( | ... | @@ -7080,7 +7097,7 @@ fn cmdFetch( |
| 7080 | try fixups.append_string_after_node.put(gpa, manifest.version_node, dependencies_text); | 7097 | try fixups.append_string_after_node.put(gpa, manifest.version_node, dependencies_text); |
| 7081 | } | 7098 | } |
| 7082 | 7099 | ||
| 7083 | var aw: std.Io.Writer.Allocating = .init(gpa); | 7100 | var aw: Io.Writer.Allocating = .init(gpa); |
| 7084 | defer aw.deinit(); | 7101 | defer aw.deinit(); |
| 7085 | try ast.render(gpa, &aw.writer, fixups); | 7102 | try ast.render(gpa, &aw.writer, fixups); |
| 7086 | const rendered = aw.written(); | 7103 | const rendered = aw.written(); |