| 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 | 38 | |
| 39 | 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 | 45 | // skip my own exe name |
| 42 | 46 | var arg_idx: usize = 1; |
| 43 | 47 | |
| ... | ... | @@ -68,6 +72,7 @@ pub fn main() !void { |
| 68 | 72 | }; |
| 69 | 73 | |
| 70 | 74 | var graph: std.Build.Graph = .{ |
| 75 | .io = io, | |
| 71 | 76 | .arena = arena, |
| 72 | 77 | .cache = .{ |
| 73 | 78 | .gpa = arena, |
lib/std/Build.zig+6-2| ... | ... | @@ -1,5 +1,7 @@ |
| 1 | const std = @import("std.zig"); | |
| 2 | 1 | const builtin = @import("builtin"); |
| 2 | ||
| 3 | const std = @import("std.zig"); | |
| 4 | const Io = std.Io; | |
| 3 | 5 | const fs = std.fs; |
| 4 | 6 | const mem = std.mem; |
| 5 | 7 | const debug = std.debug; |
| ... | ... | @@ -110,6 +112,7 @@ pub const ReleaseMode = enum { |
| 110 | 112 | /// Shared state among all Build instances. |
| 111 | 113 | /// Settings that are here rather than in Build are not configurable per-package. |
| 112 | 114 | pub const Graph = struct { |
| 115 | io: Io, | |
| 113 | 116 | arena: Allocator, |
| 114 | 117 | system_library_options: std.StringArrayHashMapUnmanaged(SystemLibraryMode) = .empty, |
| 115 | 118 | system_package_mode: bool = false, |
| ... | ... | @@ -2666,9 +2669,10 @@ pub fn resolveTargetQuery(b: *Build, query: Target.Query) ResolvedTarget { |
| 2666 | 2669 | // Hot path. This is faster than querying the native CPU and OS again. |
| 2667 | 2670 | return b.graph.host; |
| 2668 | 2671 | } |
| 2672 | const io = b.graph.io; | |
| 2669 | 2673 | return .{ |
| 2670 | 2674 | .query = query, |
| 2671 | .result = std.zig.system.resolveTargetQuery(query) catch | |
| 2675 | .result = std.zig.system.resolveTargetQuery(io, query) catch | |
| 2672 | 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 | 532 | test Options { |
| 533 | 533 | if (builtin.os.tag == .wasi) return error.SkipZigTest; |
| 534 | 534 | |
| 535 | const io = std.testing.io; | |
| 536 | ||
| 535 | 537 | var arena = std.heap.ArenaAllocator.init(std.testing.allocator); |
| 536 | 538 | defer arena.deinit(); |
| 537 | 539 | |
| ... | ... | @@ -546,7 +548,7 @@ test Options { |
| 546 | 548 | .global_cache_root = .{ .path = "test", .handle = std.fs.cwd() }, |
| 547 | 549 | .host = .{ |
| 548 | 550 | .query = .{}, |
| 549 | .result = try std.zig.system.resolveTargetQuery(.{}), | |
| 551 | .result = try std.zig.system.resolveTargetQuery(io, .{}), | |
| 550 | 552 | }, |
| 551 | 553 | .zig_lib_directory = std.Build.Cache.Directory.cwd(), |
| 552 | 554 | .time_report = false, |
lib/std/Build/WebServer.zig+2-1| ... | ... | @@ -516,6 +516,7 @@ pub fn serveTarFile( |
| 516 | 516 | } |
| 517 | 517 | |
| 518 | 518 | fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.OptimizeMode) !Cache.Path { |
| 519 | const io = ws.graph.io; | |
| 519 | 520 | const root_name = "build-web"; |
| 520 | 521 | const arch_os_abi = "wasm32-freestanding"; |
| 521 | 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 | 660 | }; |
| 660 | 661 | const bin_name = try std.zig.binNameAlloc(arena, .{ |
| 661 | 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 | 664 | .arch_os_abi = arch_os_abi, |
| 664 | 665 | .cpu_features = cpu_features, |
| 665 | 666 | }) catch unreachable) catch unreachable), |
lib/std/Io.zig+3-3| ... | ... | @@ -738,9 +738,9 @@ pub const Timestamp = struct { |
| 738 | 738 | /// * On Linux, corresponds `CLOCK_MONOTONIC`. |
| 739 | 739 | /// * On macOS, corresponds to `CLOCK_UPTIME_RAW`. |
| 740 | 740 | awake, |
| 741 | /// Identical to `awake` except it expresses intent to include time | |
| 742 | /// that the system is suspended, however, it may be implemented | |
| 743 | /// identically to `awake`. | |
| 741 | /// Identical to `awake` except it expresses intent to **include time | |
| 742 | /// that the system is suspended**, however, due to limitations it may | |
| 743 | /// behave identically to `awake`. | |
| 744 | 744 | /// |
| 745 | 745 | /// * On Linux, corresponds `CLOCK_BOOTTIME`. |
| 746 | 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 | 1054 | fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 1055 | 1055 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1056 | 1056 | const clock_id: posix.clockid_t = clockToPosix(switch (timeout) { |
| 1057 | .none => .monotonic, | |
| 1057 | .none => .awake, | |
| 1058 | 1058 | .duration => |d| d.clock, |
| 1059 | 1059 | .deadline => |d| d.clock, |
| 1060 | 1060 | }); |
| ... | ... | @@ -1087,7 +1087,6 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 1087 | 1087 | const ms = ms: { |
| 1088 | 1088 | const duration_and_clock = (try timeout.toDurationFromNow(pool.io())) orelse |
| 1089 | 1089 | break :ms std.math.maxInt(windows.DWORD); |
| 1090 | if (duration_and_clock.clock != .monotonic) return error.UnsupportedClock; | |
| 1091 | 1090 | break :ms std.math.lossyCast(windows.DWORD, duration_and_clock.duration.toMilliseconds()); |
| 1092 | 1091 | }; |
| 1093 | 1092 | windows.kernel32.Sleep(ms); |
| ... | ... | @@ -1132,8 +1131,6 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 1132 | 1131 | .sec = std.math.maxInt(sec_type), |
| 1133 | 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 | 1134 | const ns = d.duration.nanoseconds; |
| 1138 | 1135 | break :t .{ |
| 1139 | 1136 | .sec = @intCast(@divFloor(ns, std.time.ns_per_s)), |
| ... | ... | @@ -2046,9 +2043,9 @@ fn clockToPosix(clock: Io.Timestamp.Clock) posix.clockid_t { |
| 2046 | 2043 | fn clockToWasi(clock: Io.Timestamp.Clock) std.os.wasi.clockid_t { |
| 2047 | 2044 | return switch (clock) { |
| 2048 | 2045 | .realtime => .REALTIME, |
| 2049 | .monotonic => .MONOTONIC, | |
| 2050 | .uptime => .MONOTONIC, | |
| 2051 | .process_cputime_id => .PROCESS_CPUTIME_ID, | |
| 2052 | .thread_cputime_id => .THREAD_CPUTIME_ID, | |
| 2046 | .awake => .MONOTONIC, | |
| 2047 | .boot => .MONOTONIC, | |
| 2048 | .cpu_process => .PROCESS_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 | 228 | /// |
| 229 | 229 | /// One bound `Socket` can be used to receive messages from multiple |
| 230 | 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 | 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 | 612 | } |
| 613 | 613 | |
| 614 | 614 | test parse { |
| 615 | const io = std.testing.io; | |
| 616 | ||
| 615 | 617 | if (builtin.target.isGnuLibC()) { |
| 616 | 618 | var query = try Query.parse(.{}); |
| 617 | 619 | query.setGnuLibCVersion(2, 1, 1); |
| ... | ... | @@ -654,7 +656,7 @@ test parse { |
| 654 | 656 | .arch_os_abi = "x86_64-linux-gnu", |
| 655 | 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 | 661 | try std.testing.expect(target.os.tag == .linux); |
| 660 | 662 | try std.testing.expect(target.abi == .gnu); |
| ... | ... | @@ -679,7 +681,7 @@ test parse { |
| 679 | 681 | .arch_os_abi = "arm-linux-musleabihf", |
| 680 | 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 | 686 | try std.testing.expect(target.os.tag == .linux); |
| 685 | 687 | try std.testing.expect(target.abi == .musleabihf); |
| ... | ... | @@ -696,7 +698,7 @@ test parse { |
| 696 | 698 | .arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27", |
| 697 | 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 | 703 | try std.testing.expect(target.cpu.arch == .aarch64); |
| 702 | 704 | try std.testing.expect(target.os.tag == .linux); |
| ... | ... | @@ -719,7 +721,7 @@ test parse { |
| 719 | 721 | const query = try Query.parse(.{ |
| 720 | 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 | 726 | try std.testing.expect(target.cpu.arch == .aarch64); |
| 725 | 727 | try std.testing.expect(target.os.tag == .linux); |
| ... | ... | @@ -740,7 +742,7 @@ test parse { |
| 740 | 742 | const query = try Query.parse(.{ |
| 741 | 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 | 747 | try std.testing.expect(target.cpu.arch == .x86); |
| 746 | 748 | try std.testing.expect(target.os.tag == .windows); |
lib/std/elf.zig+121-45| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | //! Executable and Linkable Format. |
| 2 | 2 | |
| 3 | 3 | const std = @import("std.zig"); |
| 4 | const Io = std.Io; | |
| 4 | 5 | const math = std.math; |
| 5 | 6 | const mem = std.mem; |
| 6 | 7 | const assert = std.debug.assert; |
| 8 | const Endian = std.builtin.Endian; | |
| 7 | 9 | const native_endian = @import("builtin").target.cpu.arch.endian(); |
| 8 | 10 | |
| 9 | 11 | pub const AT_NULL = 0; |
| ... | ... | @@ -568,7 +570,7 @@ pub const ET = enum(u16) { |
| 568 | 570 | /// All integers are native endian. |
| 569 | 571 | pub const Header = struct { |
| 570 | 572 | is_64: bool, |
| 571 | endian: std.builtin.Endian, | |
| 573 | endian: Endian, | |
| 572 | 574 | os_abi: OSABI, |
| 573 | 575 | /// The meaning of this value depends on `os_abi`. |
| 574 | 576 | abi_version: u8, |
| ... | ... | @@ -583,48 +585,76 @@ pub const Header = struct { |
| 583 | 585 | shnum: u16, |
| 584 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 644 | InvalidElfMagic, |
| 616 | 645 | InvalidElfVersion, |
| 617 | 646 | InvalidElfClass, |
| 618 | 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 | 652 | const buf = try r.peek(@sizeOf(Elf64_Ehdr)); |
| 623 | 653 | |
| 624 | 654 | if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic; |
| 625 | 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 | 658 | ELFDATA2LSB => .little, |
| 629 | 659 | ELFDATA2MSB => .big, |
| 630 | 660 | else => return error.InvalidElfEndian, |
| ... | ... | @@ -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 | 671 | // Converting integers to exhaustive enums using `@enumFromInt` could cause a panic. |
| 642 | 672 | comptime assert(!@typeInfo(OSABI).@"enum".is_exhaustive); |
| 643 | 673 | return .{ |
| ... | ... | @@ -664,46 +694,54 @@ pub const Header = struct { |
| 664 | 694 | }; |
| 665 | 695 | |
| 666 | 696 | pub const ProgramHeaderIterator = struct { |
| 667 | elf_header: Header, | |
| 668 | file_reader: *std.fs.File.Reader, | |
| 697 | is_64: bool, | |
| 698 | endian: Endian, | |
| 699 | phnum: u16, | |
| 700 | phoff: u64, | |
| 701 | ||
| 702 | file_reader: *Io.File.Reader, | |
| 669 | 703 | index: usize = 0, |
| 670 | 704 | |
| 671 | 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 | 707 | defer it.index += 1; |
| 674 | 708 | |
| 675 | const size: u64 = if (it.elf_header.is_64) @sizeOf(Elf64_Phdr) else @sizeOf(Elf32_Phdr); | |
| 676 | const offset = it.elf_header.phoff + size * it.index; | |
| 709 | const size: u64 = if (it.is_64) @sizeOf(Elf64_Phdr) else @sizeOf(Elf32_Phdr); | |
| 710 | const offset = it.phoff + size * it.index; | |
| 677 | 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 | 717 | pub const ProgramHeaderBufferIterator = struct { |
| 684 | elf_header: Header, | |
| 718 | is_64: bool, | |
| 719 | endian: Endian, | |
| 720 | phnum: u16, | |
| 721 | phoff: u64, | |
| 722 | ||
| 685 | 723 | buf: []const u8, |
| 686 | 724 | index: usize = 0, |
| 687 | 725 | |
| 688 | 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 | 728 | defer it.index += 1; |
| 691 | 729 | |
| 692 | const size: u64 = if (it.elf_header.is_64) @sizeOf(Elf64_Phdr) else @sizeOf(Elf32_Phdr); | |
| 693 | const offset = it.elf_header.phoff + size * it.index; | |
| 694 | var reader = std.Io.Reader.fixed(it.buf[offset..]); | |
| 730 | const size: u64 = if (it.is_64) @sizeOf(Elf64_Phdr) else @sizeOf(Elf32_Phdr); | |
| 731 | const offset = it.phoff + size * it.index; | |
| 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 { | |
| 701 | if (elf_header.is_64) { | |
| 702 | const phdr = try reader.takeStruct(Elf64_Phdr, elf_header.endian); | |
| 738 | pub fn takeProgramHeader(reader: *Io.Reader, is_64: bool, endian: Endian) !Elf64_Phdr { | |
| 739 | if (is_64) { | |
| 740 | const phdr = try reader.takeStruct(Elf64_Phdr, endian); | |
| 703 | 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 | 745 | return .{ |
| 708 | 746 | .p_type = phdr.p_type, |
| 709 | 747 | .p_offset = phdr.p_offset, |
| ... | ... | @@ -717,47 +755,55 @@ fn takePhdr(reader: *std.Io.Reader, elf_header: Header) !?Elf64_Phdr { |
| 717 | 755 | } |
| 718 | 756 | |
| 719 | 757 | pub const SectionHeaderIterator = struct { |
| 720 | elf_header: Header, | |
| 721 | file_reader: *std.fs.File.Reader, | |
| 758 | is_64: bool, | |
| 759 | endian: Endian, | |
| 760 | shnum: u16, | |
| 761 | shoff: u64, | |
| 762 | ||
| 763 | file_reader: *Io.File.Reader, | |
| 722 | 764 | index: usize = 0, |
| 723 | 765 | |
| 724 | 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 | 768 | defer it.index += 1; |
| 727 | 769 | |
| 728 | const size: u64 = if (it.elf_header.is_64) @sizeOf(Elf64_Shdr) else @sizeOf(Elf32_Shdr); | |
| 729 | const offset = it.elf_header.shoff + size * it.index; | |
| 770 | const size: u64 = if (it.is_64) @sizeOf(Elf64_Shdr) else @sizeOf(Elf32_Shdr); | |
| 771 | const offset = it.shoff + size * it.index; | |
| 730 | 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 | 778 | pub const SectionHeaderBufferIterator = struct { |
| 737 | elf_header: Header, | |
| 779 | is_64: bool, | |
| 780 | endian: Endian, | |
| 781 | shnum: u16, | |
| 782 | shoff: u64, | |
| 783 | ||
| 738 | 784 | buf: []const u8, |
| 739 | 785 | index: usize = 0, |
| 740 | 786 | |
| 741 | 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 | 789 | defer it.index += 1; |
| 744 | 790 | |
| 745 | const size: u64 = if (it.elf_header.is_64) @sizeOf(Elf64_Shdr) else @sizeOf(Elf32_Shdr); | |
| 746 | const offset = it.elf_header.shoff + size * it.index; | |
| 791 | const size: u64 = if (it.is_64) @sizeOf(Elf64_Shdr) else @sizeOf(Elf32_Shdr); | |
| 792 | const offset = it.shoff + size * it.index; | |
| 747 | 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 { | |
| 755 | if (elf_header.is_64) { | |
| 756 | const shdr = try reader.takeStruct(Elf64_Shdr, elf_header.endian); | |
| 800 | pub fn takeSectionHeader(reader: *Io.Reader, is_64: bool, endian: Endian) !Elf64_Shdr { | |
| 801 | if (is_64) { | |
| 802 | const shdr = try reader.takeStruct(Elf64_Shdr, endian); | |
| 757 | 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 | 807 | return .{ |
| 762 | 808 | .sh_name = shdr.sh_name, |
| 763 | 809 | .sh_type = shdr.sh_type, |
| ... | ... | @@ -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 | 851 | pub const EI = struct { |
| 776 | 852 | pub const CLASS = 4; |
| 777 | 853 | pub const DATA = 5; |
lib/std/zig.zig+6-5| ... | ... | @@ -6,6 +6,7 @@ const std = @import("std.zig"); |
| 6 | 6 | const tokenizer = @import("zig/tokenizer.zig"); |
| 7 | 7 | const assert = std.debug.assert; |
| 8 | 8 | const Allocator = std.mem.Allocator; |
| 9 | const Io = std.Io; | |
| 9 | 10 | const Writer = std.Io.Writer; |
| 10 | 11 | |
| 11 | 12 | pub const ErrorBundle = @import("zig/ErrorBundle.zig"); |
| ... | ... | @@ -52,9 +53,9 @@ pub const Color = enum { |
| 52 | 53 | /// Assume stderr is a terminal. |
| 53 | 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 | 57 | return switch (color) { |
| 57 | .auto => std.Io.tty.detectConfig(std.fs.File.stderr()), | |
| 58 | .auto => Io.tty.detectConfig(std.fs.File.stderr()), | |
| 58 | 59 | .on => .escape_codes, |
| 59 | 60 | .off => .no_color, |
| 60 | 61 | }; |
| ... | ... | @@ -323,7 +324,7 @@ pub const BuildId = union(enum) { |
| 323 | 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 | 328 | switch (id) { |
| 328 | 329 | .none, .fast, .uuid, .sha1, .md5 => { |
| 329 | 330 | try writer.writeAll(@tagName(id)); |
| ... | ... | @@ -620,8 +621,8 @@ pub fn putAstErrorsIntoBundle( |
| 620 | 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 | return std.zig.system.resolveTargetQuery(target_query) catch |err| | |
| 624 | pub fn resolveTargetQueryOrFatal(io: Io, target_query: std.Target.Query) std.Target { | |
| 625 | return std.zig.system.resolveTargetQuery(io, target_query) catch |err| | |
| 625 | 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 | 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 | 12 | pub const NativePaths = @import("system/NativePaths.zig"); |
| 2 | 13 | |
| 3 | 14 | pub const windows = @import("system/windows.zig"); |
| ... | ... | @@ -199,14 +210,14 @@ pub const DetectError = error{ |
| 199 | 210 | OSVersionDetectionFail, |
| 200 | 211 | Unexpected, |
| 201 | 212 | ProcessNotFound, |
| 202 | }; | |
| 213 | } || Io.Cancelable; | |
| 203 | 214 | |
| 204 | 215 | /// Given a `Target.Query`, which specifies in detail which parts of the |
| 205 | 216 | /// target should be detected natively, which should be standard or default, |
| 206 | 217 | /// and which are provided explicitly, this function resolves the native |
| 207 | 218 | /// components by detecting the native system, and then resolves |
| 208 | 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 | 221 | // Until https://github.com/ziglang/zig/issues/4592 is implemented (support detecting the |
| 211 | 222 | // native CPU architecture as being different than the current target), we use this: |
| 212 | 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 | 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 | 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 | 542 | return null; |
| 506 | 543 | } |
| 507 | 544 | |
| 508 | 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 | }; | |
| 545 | pub const AbiAndDynamicLinkerFromFileError = error{}; | |
| 526 | 546 | |
| 527 | 547 | pub fn abiAndDynamicLinkerFromFile( |
| 528 | file: fs.File, | |
| 548 | file_reader: *Io.File.Reader, | |
| 549 | header: *const elf.Header, | |
| 529 | 550 | cpu: Target.Cpu, |
| 530 | 551 | os: Target.Os, |
| 531 | 552 | ld_info_list: []const LdInfo, |
| 532 | 553 | query: Target.Query, |
| 533 | 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 | 555 | var result: Target = .{ |
| 557 | 556 | .cpu = cpu, |
| 558 | 557 | .os = os, |
| ... | ... | @@ -563,167 +562,87 @@ pub fn abiAndDynamicLinkerFromFile( |
| 563 | 562 | var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC |
| 564 | 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 | 565 | var got_dyn_section: bool = false; |
| 571 | ||
| 572 | while (ph_i < phnum) { | |
| 573 | // Reserve some bytes so that we can deref the 64-bit struct fields | |
| 574 | // even when the ELF file is 32-bits. | |
| 575 | const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr); | |
| 576 | const ph_read_byte_len = try preadAtLeast(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize); | |
| 577 | var ph_buf_i: usize = 0; | |
| 578 | while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({ | |
| 579 | ph_i += 1; | |
| 580 | phoff += phentsize; | |
| 581 | ph_buf_i += phentsize; | |
| 582 | }) { | |
| 583 | const ph32: *elf.Elf32_Phdr = @ptrCast(@alignCast(&ph_buf[ph_buf_i])); | |
| 584 | const ph64: *elf.Elf64_Phdr = @ptrCast(@alignCast(&ph_buf[ph_buf_i])); | |
| 585 | const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type); | |
| 586 | switch (p_type) { | |
| 587 | elf.PT_INTERP => { | |
| 588 | got_dyn_section = true; | |
| 589 | ||
| 590 | if (look_for_ld) { | |
| 591 | const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); | |
| 592 | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); | |
| 593 | if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; | |
| 594 | const filesz: usize = @intCast(p_filesz); | |
| 595 | _ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz); | |
| 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 | } | |
| 566 | { | |
| 567 | var it = header.iterateProgramHeaders(file_reader); | |
| 568 | while (try it.next()) |phdr| switch (phdr.p_type) { | |
| 569 | elf.PT_INTERP => { | |
| 570 | got_dyn_section = true; | |
| 571 | ||
| 572 | if (look_for_ld) { | |
| 573 | const p_filesz = phdr.p_filesz; | |
| 574 | if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; | |
| 575 | const filesz: usize = @intCast(p_filesz); | |
| 576 | try file_reader.seekTo(phdr.p_offset); | |
| 577 | try file_reader.interface.readSliceAll(result.dynamic_linker.buffer[0..filesz]); | |
| 578 | // PT_INTERP includes a null byte in filesz. | |
| 579 | const len = filesz - 1; | |
| 580 | // dynamic_linker.max_byte is "max", not "len". | |
| 581 | // We know it will fit in u8 because we check against dynamic_linker.buffer.len above. | |
| 582 | result.dynamic_linker.len = @intCast(len); | |
| 583 | ||
| 584 | // Use it to determine ABI. | |
| 585 | const full_ld_path = result.dynamic_linker.buffer[0..len]; | |
| 586 | for (ld_info_list) |ld_info| { | |
| 587 | const standard_ld_basename = fs.path.basename(ld_info.ld.get().?); | |
| 588 | if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) { | |
| 589 | result.abi = ld_info.abi; | |
| 590 | break; | |
| 610 | 591 | } |
| 611 | 592 | } |
| 612 | }, | |
| 613 | // We only need this for detecting glibc version. | |
| 614 | elf.PT_DYNAMIC => { | |
| 615 | got_dyn_section = true; | |
| 616 | ||
| 617 | if (builtin.target.os.tag == .linux and result.isGnuLibC() and | |
| 618 | query.glibc_version == null) | |
| 619 | { | |
| 620 | var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); | |
| 621 | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); | |
| 622 | const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn); | |
| 623 | const dyn_num = p_filesz / dyn_size; | |
| 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 | } | |
| 593 | } | |
| 594 | }, | |
| 595 | // We only need this for detecting glibc version. | |
| 596 | elf.PT_DYNAMIC => { | |
| 597 | got_dyn_section = true; | |
| 598 | ||
| 599 | if (builtin.target.os.tag == .linux and result.isGnuLibC() and query.glibc_version == null) { | |
| 600 | var dyn_it = header.iterateDynamicSection(file_reader, phdr.p_offset, phdr.p_filesz); | |
| 601 | while (try dyn_it.next()) |dyn| { | |
| 602 | if (dyn.d_tag == elf.DT_RUNPATH) { | |
| 603 | rpath_offset = dyn.d_val; | |
| 604 | break; | |
| 651 | 605 | } |
| 652 | 606 | } |
| 653 | }, | |
| 654 | else => continue, | |
| 655 | } | |
| 656 | } | |
| 607 | } | |
| 608 | }, | |
| 609 | else => continue, | |
| 610 | }; | |
| 657 | 611 | } |
| 658 | 612 | |
| 659 | 613 | if (!got_dyn_section) { |
| 660 | 614 | return error.StaticElfFile; |
| 661 | 615 | } |
| 662 | 616 | |
| 663 | if (builtin.target.os.tag == .linux and result.isGnuLibC() and | |
| 664 | query.glibc_version == null) | |
| 665 | { | |
| 666 | const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx); | |
| 667 | ||
| 668 | var shoff = elfInt(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff); | |
| 669 | const shentsize = elfInt(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize); | |
| 670 | const str_section_off = shoff + @as(u64, shentsize) * @as(u64, shstrndx); | |
| 671 | ||
| 672 | var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined; | |
| 673 | if (sh_buf.len < shentsize) return error.InvalidElfFile; | |
| 674 | ||
| 675 | _ = try preadAtLeast(file, &sh_buf, str_section_off, shentsize); | |
| 676 | const shstr32: *elf.Elf32_Shdr = @ptrCast(@alignCast(&sh_buf)); | |
| 677 | const shstr64: *elf.Elf64_Shdr = @ptrCast(@alignCast(&sh_buf)); | |
| 678 | const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset); | |
| 679 | const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size); | |
| 680 | var strtab_buf: [4096:0]u8 = undefined; | |
| 681 | const shstrtab_len = @min(shstrtab_size, strtab_buf.len); | |
| 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 | ||
| 617 | if (builtin.target.os.tag == .linux and result.isGnuLibC() and query.glibc_version == null) { | |
| 618 | const str_section_off = header.shoff + @as(u64, header.shentsize) * @as(u64, header.shstrndx); | |
| 619 | try file_reader.seekTo(str_section_off); | |
| 620 | const shstr = try elf.takeSectionHeader(&file_reader.interface, header.is_64, header.endian); | |
| 621 | var strtab_buf: [4096]u8 = undefined; | |
| 622 | const shstrtab = strtab_buf[0..@min(shstr.sh_size, strtab_buf.len)]; | |
| 623 | try file_reader.seekTo(shstr.sh_offset); | |
| 624 | try file_reader.interface.readSliceAll(shstrtab); | |
| 625 | const dynstr: ?struct { offset: u64, size: u64 } = find_dyn_str: { | |
| 626 | var it = header.iterateSectionHeaders(&file_reader.interface); | |
| 627 | while (it.next()) |shdr| { | |
| 628 | const end = mem.findScalarPos(u8, shstrtab, shdr.sh_name, 0) orelse continue; | |
| 629 | const sh_name = shstrtab[shdr.sh_name..end :0]; | |
| 630 | if (mem.eql(u8, sh_name, ".dynstr")) break :find_dyn_str .{ | |
| 631 | .offset = shdr.sh_offset, | |
| 632 | .size = shdr.sh_size, | |
| 633 | }; | |
| 634 | } else break :find_dyn_str null; | |
| 635 | }; | |
| 716 | 636 | if (dynstr) |ds| { |
| 717 | 637 | if (rpath_offset) |rpoff| { |
| 718 | 638 | if (rpoff > ds.size) return error.InvalidElfFile; |
| 719 | 639 | const rpoff_file = ds.offset + rpoff; |
| 720 | 640 | const rp_max_size = ds.size - rpoff; |
| 721 | 641 | |
| 722 | const strtab_len = @min(rp_max_size, strtab_buf.len); | |
| 723 | const strtab_read_len = try preadAtLeast(file, &strtab_buf, rpoff_file, strtab_len); | |
| 724 | const strtab = strtab_buf[0..strtab_read_len]; | |
| 642 | try file_reader.seekTo(rpoff_file); | |
| 643 | const rpath_list = try file_reader.interface.takeSentinel(0); | |
| 644 | if (rpath_list.len > rp_max_size) return error.StreamTooLong; | |
| 725 | 645 | |
| 726 | const rpath_list = mem.sliceTo(strtab, 0); | |
| 727 | 646 | var it = mem.tokenizeScalar(u8, rpath_list, ':'); |
| 728 | 647 | while (it.next()) |rpath| { |
| 729 | 648 | if (glibcVerFromRPath(rpath)) |ver| { |
| ... | ... | @@ -845,7 +764,7 @@ test glibcVerFromLinkName { |
| 845 | 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 | 768 | var dir = fs.cwd().openDir(rpath, .{}) catch |err| switch (err) { |
| 850 | 769 | error.NameTooLong => unreachable, |
| 851 | 770 | error.InvalidUtf8 => unreachable, // WASI only |
| ... | ... | @@ -879,7 +798,7 @@ fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion { |
| 879 | 798 | // .dynstr section, and finding the max version number of symbols |
| 880 | 799 | // that start with "GLIBC_2.". |
| 881 | 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 | 802 | error.NameTooLong => unreachable, |
| 884 | 803 | error.InvalidUtf8 => unreachable, // WASI only |
| 885 | 804 | error.InvalidWtf8 => unreachable, // Windows only |
| ... | ... | @@ -913,16 +832,20 @@ fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion { |
| 913 | 832 | error.Unexpected, |
| 914 | 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 | 842 | error.InvalidElfMagic, |
| 920 | 843 | error.InvalidElfEndian, |
| 921 | 844 | error.InvalidElfClass, |
| 922 | 845 | error.InvalidElfFile, |
| 923 | 846 | error.InvalidElfVersion, |
| 924 | 847 | error.InvalidGnuLibCVersion, |
| 925 | error.UnexpectedEndOfFile, | |
| 848 | error.EndOfStream, | |
| 926 | 849 | => return error.GLibCNotFound, |
| 927 | 850 | |
| 928 | 851 | error.SystemResources, |
| ... | ... | @@ -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 { | |
| 938 | var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined; | |
| 939 | _ = try preadAtLeast(file, &hdr_buf, 0, hdr_buf.len); | |
| 940 | const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf); | |
| 941 | const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf); | |
| 942 | if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; | |
| 943 | const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI.DATA]) { | |
| 944 | elf.ELFDATA2LSB => .little, | |
| 945 | elf.ELFDATA2MSB => .big, | |
| 946 | else => return error.InvalidElfEndian, | |
| 947 | }; | |
| 948 | const need_bswap = elf_endian != native_endian; | |
| 949 | if (hdr32.e_ident[elf.EI.VERSION] != 1) return error.InvalidElfVersion; | |
| 950 | ||
| 951 | const is_64 = switch (hdr32.e_ident[elf.EI.CLASS]) { | |
| 952 | elf.ELFCLASS32 => false, | |
| 953 | elf.ELFCLASS64 => true, | |
| 954 | else => return error.InvalidElfClass, | |
| 860 | fn glibcVerFromSoFile(file_reader: *Io.File.Reader) !std.SemanticVersion { | |
| 861 | const header = try elf.Header.read(&file_reader.interface); | |
| 862 | const str_section_off = header.shoff + @as(u64, header.shentsize) * @as(u64, header.shstrndx); | |
| 863 | try file_reader.seekTo(str_section_off); | |
| 864 | const shstr = try elf.takeSectionHeader(&file_reader.interface, header.is_64, header.endian); | |
| 865 | var strtab_buf: [4096]u8 = undefined; | |
| 866 | const shstrtab = strtab_buf[0..@min(shstr.sh_size, strtab_buf.len)]; | |
| 867 | try file_reader.seekTo(shstr.sh_offset); | |
| 868 | try file_reader.interface.readSliceAll(shstrtab); | |
| 869 | const dynstr: struct { offset: u64, size: u64 } = find_dyn_str: { | |
| 870 | var it = header.iterateSectionHeaders(&file_reader.interface); | |
| 871 | while (it.next()) |shdr| { | |
| 872 | const end = mem.findScalarPos(u8, shstrtab, shdr.sh_name, 0) orelse continue; | |
| 873 | const sh_name = shstrtab[shdr.sh_name..end :0]; | |
| 874 | if (mem.eql(u8, sh_name, ".dynstr")) break :find_dyn_str .{ | |
| 875 | .offset = shdr.sh_offset, | |
| 876 | .size = shdr.sh_size, | |
| 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 | 881 | // Here we loop over all the strings in the dynstr string table, assuming that any |
| 1004 | 882 | // strings that start with "GLIBC_2." indicate the existence of such a glibc version, |
| 1005 | 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 | 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 | 888 | if (mem.startsWith(u8, s, "GLIBC_2.")) { |
| 1020 | 889 | const chopped = s["GLIBC_".len..]; |
| 1021 | 890 | const ver = Target.Query.parseVersion(chopped) catch |err| switch (err) { |
| ... | ... | @@ -1028,6 +897,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion { |
| 1028 | 897 | } |
| 1029 | 898 | } |
| 1030 | 899 | } |
| 900 | ||
| 1031 | 901 | return max_ver; |
| 1032 | 902 | } |
| 1033 | 903 | |
| ... | ... | @@ -1044,11 +914,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion { |
| 1044 | 914 | /// answer to these questions, or if there is a shebang line, then it chases the referenced |
| 1045 | 915 | /// file recursively. If that does not provide the answer, then the function falls back to |
| 1046 | 916 | /// defaults. |
| 1047 | fn detectAbiAndDynamicLinker( | |
| 1048 | cpu: Target.Cpu, | |
| 1049 | os: Target.Os, | |
| 1050 | query: Target.Query, | |
| 1051 | ) DetectError!Target { | |
| 917 | fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Target.Query) !Target { | |
| 1052 | 918 | const native_target_has_ld = comptime Target.DynamicLinker.kind(builtin.os.tag) != .none; |
| 1053 | 919 | const is_linux = builtin.target.os.tag == .linux; |
| 1054 | 920 | const is_illumos = builtin.target.os.tag == .illumos; |
| ... | ... | @@ -1111,49 +977,52 @@ fn detectAbiAndDynamicLinker( |
| 1111 | 977 | |
| 1112 | 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 | 996 | // Best case scenario: the executable is dynamically linked, and we can iterate |
| 1115 | 997 | // over our own shared objects and find a dynamic linker. |
| 1116 | const elf_file = elf_file: { | |
| 1117 | // This block looks for a shebang line in /usr/bin/env, | |
| 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, | |
| 1119 | // doing the same logic recursively in case it finds another shebang line. | |
| 998 | const header = elf_file: { | |
| 999 | // This block looks for a shebang line in "/usr/bin/env". If it finds | |
| 1000 | // one, then instead of using "/usr/bin/env" as the ELF file to examine, | |
| 1001 | // it uses the file it references instead, doing the same logic | |
| 1002 | // recursively in case it finds another shebang line. | |
| 1120 | 1003 | |
| 1121 | 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 | |
| 1123 | // reasonably reliable path to start with. | |
| 1005 | // Since /usr/bin/env is hard-coded into the shebang line of many | |
| 1006 | // portable scripts, it's a reasonably reliable path to start with. | |
| 1124 | 1007 | else => "/usr/bin/env", |
| 1125 | 1008 | // Haiku does not have a /usr root directory. |
| 1126 | 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 | 1012 | while (true) { |
| 1142 | // Interpreter path can be relative on Linux, but | |
| 1143 | // for simplicity we are asserting it is an absolute path. | |
| 1144 | 1013 | const file = fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) { |
| 1145 | error.NoSpaceLeft => unreachable, | |
| 1146 | error.NameTooLong => unreachable, | |
| 1147 | error.PathAlreadyExists => unreachable, | |
| 1148 | error.SharingViolation => unreachable, | |
| 1149 | error.InvalidUtf8 => unreachable, // WASI only | |
| 1150 | error.InvalidWtf8 => unreachable, // Windows only | |
| 1151 | error.BadPathName => unreachable, | |
| 1152 | error.PipeBusy => unreachable, | |
| 1153 | error.FileLocksNotSupported => unreachable, | |
| 1154 | error.WouldBlock => unreachable, | |
| 1155 | error.FileBusy => unreachable, // opened without write permissions | |
| 1156 | error.AntivirusInterference => unreachable, // Windows-only error | |
| 1014 | error.NoSpaceLeft => return error.Unexpected, | |
| 1015 | error.NameTooLong => return error.Unexpected, | |
| 1016 | error.PathAlreadyExists => return error.Unexpected, | |
| 1017 | error.SharingViolation => return error.Unexpected, | |
| 1018 | error.InvalidUtf8 => return error.Unexpected, // WASI only | |
| 1019 | error.InvalidWtf8 => return error.Unexpected, // Windows only | |
| 1020 | error.BadPathName => return error.Unexpected, | |
| 1021 | error.PipeBusy => return error.Unexpected, | |
| 1022 | error.FileLocksNotSupported => return error.Unexpected, | |
| 1023 | error.WouldBlock => return error.Unexpected, | |
| 1024 | error.FileBusy => return error.Unexpected, // opened without write permissions | |
| 1025 | error.AntivirusInterference => return error.Unexpected, // Windows-only error | |
| 1157 | 1026 | |
| 1158 | 1027 | error.IsDir, |
| 1159 | 1028 | error.NotDir, |
| ... | ... | @@ -1164,66 +1033,58 @@ fn detectAbiAndDynamicLinker( |
| 1164 | 1033 | error.NetworkNotFound, |
| 1165 | 1034 | error.FileTooBig, |
| 1166 | 1035 | error.Unexpected, |
| 1167 | => |e| { | |
| 1168 | std.log.warn("Encountered error: {s}, falling back to default ABI and dynamic linker.", .{@errorName(e)}); | |
| 1169 | return defaultAbiAndDynamicLinker(cpu, os, query); | |
| 1170 | }, | |
| 1036 | => return error.UnableToOpenElfFile, | |
| 1171 | 1037 | |
| 1172 | 1038 | else => |e| return e, |
| 1173 | 1039 | }; |
| 1174 | 1040 | var is_elf_file = false; |
| 1175 | defer if (is_elf_file == false) file.close(); | |
| 1176 | ||
| 1177 | // Shortest working interpreter path is "#!/i" (4) | |
| 1178 | // (interpreter is "/i", assuming all paths are absolute, like in above comment). | |
| 1179 | // ELF magic number length is also 4. | |
| 1180 | // | |
| 1181 | // If file is shorter than that, it is definitely not ELF file | |
| 1182 | // nor file with "shebang" line. | |
| 1183 | const min_len: usize = 4; | |
| 1184 | ||
| 1185 | const len = preadAtLeast(file, &buffer, 0, min_len) catch |err| switch (err) { | |
| 1186 | error.UnexpectedEndOfFile, | |
| 1187 | error.UnableToReadElfFile, | |
| 1188 | error.ProcessNotFound, | |
| 1189 | => return defaultAbiAndDynamicLinker(cpu, os, query), | |
| 1041 | defer if (!is_elf_file) file.close(); | |
| 1042 | ||
| 1043 | file_reader = .initAdapted(file, io, &file_reader_buffer); | |
| 1044 | file_name = undefined; // it aliases file_reader_buffer | |
| 1045 | ||
| 1046 | const header = elf.Header.read(&file_reader.interface) catch |hdr_err| switch (hdr_err) { | |
| 1047 | error.EndOfStream, | |
| 1048 | error.InvalidElfMagic, | |
| 1049 | => { | |
| 1050 | const shebang_line = file_reader.interface.takeSentinel('\n') catch |err| switch (err) { | |
| 1051 | error.ReadFailed => return file_reader.err.?, | |
| 1052 | // It's neither an ELF file nor file with shebang line. | |
| 1053 | error.EndOfStream, error.StreamTooLong => return error.UnhelpfulFile, | |
| 1054 | }; | |
| 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]; | |
| 1194 | ||
| 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 | } | |
| 1081 | is_elf_file = true; | |
| 1082 | break :elf_file header; | |
| 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 | |
| 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) { | |
| 1087 | return abiAndDynamicLinkerFromFile(&file_reader, &header, cpu, os, ld_info_list, query) catch |err| switch (err) { | |
| 1227 | 1088 | error.FileSystem, |
| 1228 | 1089 | error.SystemResources, |
| 1229 | 1090 | error.SymLinkLoop, |
| ... | ... | @@ -1232,6 +1093,8 @@ fn detectAbiAndDynamicLinker( |
| 1232 | 1093 | error.ProcessNotFound, |
| 1233 | 1094 | => |e| return e, |
| 1234 | 1095 | |
| 1096 | error.ReadFailed => return file_reader.err.?, | |
| 1097 | ||
| 1235 | 1098 | error.UnableToReadElfFile, |
| 1236 | 1099 | error.InvalidElfClass, |
| 1237 | 1100 | error.InvalidElfVersion, |
| ... | ... | @@ -1239,12 +1102,12 @@ fn detectAbiAndDynamicLinker( |
| 1239 | 1102 | error.InvalidElfFile, |
| 1240 | 1103 | error.InvalidElfMagic, |
| 1241 | 1104 | error.Unexpected, |
| 1242 | error.UnexpectedEndOfFile, | |
| 1105 | error.EndOfStream, | |
| 1243 | 1106 | error.NameTooLong, |
| 1244 | 1107 | error.StaticElfFile, |
| 1245 | 1108 | // Finally, we fall back on the standard path. |
| 1246 | 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 | 1111 | return defaultAbiAndDynamicLinker(cpu, os, query); |
| 1249 | 1112 | }, |
| 1250 | 1113 | }; |
| ... | ... | @@ -1269,59 +1132,6 @@ const LdInfo = struct { |
| 1269 | 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 | 1135 | test { |
| 1326 | 1136 | _ = NativePaths; |
| 1327 | 1137 |
src/main.zig+53-36| ... | ... | @@ -1,5 +1,8 @@ |
| 1 | const std = @import("std"); | |
| 2 | 1 | const builtin = @import("builtin"); |
| 2 | const native_os = builtin.os.tag; | |
| 3 | ||
| 4 | const std = @import("std"); | |
| 5 | const Io = std.Io; | |
| 3 | 6 | const assert = std.debug.assert; |
| 4 | 7 | const fs = std.fs; |
| 5 | 8 | const mem = std.mem; |
| ... | ... | @@ -10,7 +13,6 @@ const Color = std.zig.Color; |
| 10 | 13 | const warn = std.log.warn; |
| 11 | 14 | const ThreadPool = std.Thread.Pool; |
| 12 | 15 | const cleanExit = std.process.cleanExit; |
| 13 | const native_os = builtin.os.tag; | |
| 14 | 16 | const Cache = std.Build.Cache; |
| 15 | 17 | const Path = std.Build.Cache.Path; |
| 16 | 18 | const Directory = std.Build.Cache.Directory; |
| ... | ... | @@ -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 | 254 | const cmd = args[1]; |
| 249 | 255 | const cmd_args = args[2..]; |
| 250 | 256 | if (mem.eql(u8, cmd, "build-exe")) { |
| 251 | 257 | dev.check(.build_exe_command); |
| 252 | return buildOutputType(gpa, arena, args, .{ .build = .Exe }); | |
| 258 | return buildOutputType(gpa, arena, io, args, .{ .build = .Exe }); | |
| 253 | 259 | } else if (mem.eql(u8, cmd, "build-lib")) { |
| 254 | 260 | dev.check(.build_lib_command); |
| 255 | return buildOutputType(gpa, arena, args, .{ .build = .Lib }); | |
| 261 | return buildOutputType(gpa, arena, io, args, .{ .build = .Lib }); | |
| 256 | 262 | } else if (mem.eql(u8, cmd, "build-obj")) { |
| 257 | 263 | dev.check(.build_obj_command); |
| 258 | return buildOutputType(gpa, arena, args, .{ .build = .Obj }); | |
| 264 | return buildOutputType(gpa, arena, io, args, .{ .build = .Obj }); | |
| 259 | 265 | } else if (mem.eql(u8, cmd, "test")) { |
| 260 | 266 | dev.check(.test_command); |
| 261 | return buildOutputType(gpa, arena, args, .zig_test); | |
| 267 | return buildOutputType(gpa, arena, io, args, .zig_test); | |
| 262 | 268 | } else if (mem.eql(u8, cmd, "test-obj")) { |
| 263 | 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 | 271 | } else if (mem.eql(u8, cmd, "run")) { |
| 266 | 272 | dev.check(.run_command); |
| 267 | return buildOutputType(gpa, arena, args, .run); | |
| 273 | return buildOutputType(gpa, arena, io, args, .run); | |
| 268 | 274 | } else if (mem.eql(u8, cmd, "dlltool") or |
| 269 | 275 | mem.eql(u8, cmd, "ranlib") or |
| 270 | 276 | mem.eql(u8, cmd, "lib") or |
| ... | ... | @@ -274,7 +280,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 274 | 280 | return process.exit(try llvmArMain(arena, args)); |
| 275 | 281 | } else if (mem.eql(u8, cmd, "build")) { |
| 276 | 282 | dev.check(.build_command); |
| 277 | return cmdBuild(gpa, arena, cmd_args); | |
| 283 | return cmdBuild(gpa, arena, io, cmd_args); | |
| 278 | 284 | } else if (mem.eql(u8, cmd, "clang") or |
| 279 | 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 | 294 | return process.exit(try lldMain(arena, args, true)); |
| 289 | 295 | } else if (mem.eql(u8, cmd, "cc")) { |
| 290 | 296 | dev.check(.cc_command); |
| 291 | return buildOutputType(gpa, arena, args, .cc); | |
| 297 | return buildOutputType(gpa, arena, io, args, .cc); | |
| 292 | 298 | } else if (mem.eql(u8, cmd, "c++")) { |
| 293 | 299 | dev.check(.cc_command); |
| 294 | return buildOutputType(gpa, arena, args, .cpp); | |
| 300 | return buildOutputType(gpa, arena, io, args, .cpp); | |
| 295 | 301 | } else if (mem.eql(u8, cmd, "translate-c")) { |
| 296 | 302 | dev.check(.translate_c_command); |
| 297 | return buildOutputType(gpa, arena, args, .translate_c); | |
| 303 | return buildOutputType(gpa, arena, io, args, .translate_c); | |
| 298 | 304 | } else if (mem.eql(u8, cmd, "rc")) { |
| 299 | 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 | 307 | .cmd_name = "resinator", |
| 302 | 308 | .root_src_path = "resinator/main.zig", |
| 303 | 309 | .depend_on_aro = true, |
| ... | ... | @@ -308,20 +314,20 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 308 | 314 | dev.check(.fmt_command); |
| 309 | 315 | return @import("fmt.zig").run(gpa, arena, cmd_args); |
| 310 | 316 | } else if (mem.eql(u8, cmd, "objcopy")) { |
| 311 | return jitCmd(gpa, arena, cmd_args, .{ | |
| 317 | return jitCmd(gpa, arena, io, cmd_args, .{ | |
| 312 | 318 | .cmd_name = "objcopy", |
| 313 | 319 | .root_src_path = "objcopy.zig", |
| 314 | 320 | }); |
| 315 | 321 | } else if (mem.eql(u8, cmd, "fetch")) { |
| 316 | 322 | return cmdFetch(gpa, arena, cmd_args); |
| 317 | 323 | } else if (mem.eql(u8, cmd, "libc")) { |
| 318 | return jitCmd(gpa, arena, cmd_args, .{ | |
| 324 | return jitCmd(gpa, arena, io, cmd_args, .{ | |
| 319 | 325 | .cmd_name = "libc", |
| 320 | 326 | .root_src_path = "libc.zig", |
| 321 | 327 | .prepend_zig_lib_dir_path = true, |
| 322 | 328 | }); |
| 323 | 329 | } else if (mem.eql(u8, cmd, "std")) { |
| 324 | return jitCmd(gpa, arena, cmd_args, .{ | |
| 330 | return jitCmd(gpa, arena, io, cmd_args, .{ | |
| 325 | 331 | .cmd_name = "std", |
| 326 | 332 | .root_src_path = "std-docs.zig", |
| 327 | 333 | .prepend_zig_lib_dir_path = true, |
| ... | ... | @@ -332,7 +338,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 332 | 338 | return cmdInit(gpa, arena, cmd_args); |
| 333 | 339 | } else if (mem.eql(u8, cmd, "targets")) { |
| 334 | 340 | dev.check(.targets_command); |
| 335 | const host = std.zig.resolveTargetQueryOrFatal(.{}); | |
| 341 | const host = std.zig.resolveTargetQueryOrFatal(io, .{}); | |
| 336 | 342 | var stdout_writer = fs.File.stdout().writer(&stdout_buffer); |
| 337 | 343 | try @import("print_targets.zig").cmdTargets(arena, cmd_args, &stdout_writer.interface, &host); |
| 338 | 344 | return stdout_writer.interface.flush(); |
| ... | ... | @@ -351,7 +357,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 351 | 357 | ); |
| 352 | 358 | return stdout_writer.interface.flush(); |
| 353 | 359 | } else if (mem.eql(u8, cmd, "reduce")) { |
| 354 | return jitCmd(gpa, arena, cmd_args, .{ | |
| 360 | return jitCmd(gpa, arena, io, cmd_args, .{ | |
| 355 | 361 | .cmd_name = "reduce", |
| 356 | 362 | .root_src_path = "reduce.zig", |
| 357 | 363 | }); |
| ... | ... | @@ -364,7 +370,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 364 | 370 | } else if (mem.eql(u8, cmd, "ast-check")) { |
| 365 | 371 | return cmdAstCheck(arena, cmd_args); |
| 366 | 372 | } else if (mem.eql(u8, cmd, "detect-cpu")) { |
| 367 | return cmdDetectCpu(cmd_args); | |
| 373 | return cmdDetectCpu(io, cmd_args); | |
| 368 | 374 | } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "changelist")) { |
| 369 | 375 | return cmdChangelist(arena, cmd_args); |
| 370 | 376 | } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "dump-zir")) { |
| ... | ... | @@ -792,6 +798,7 @@ const CliModule = struct { |
| 792 | 798 | fn buildOutputType( |
| 793 | 799 | gpa: Allocator, |
| 794 | 800 | arena: Allocator, |
| 801 | io: Io, | |
| 795 | 802 | all_args: []const []const u8, |
| 796 | 803 | arg_mode: ArgMode, |
| 797 | 804 | ) !void { |
| ... | ... | @@ -3017,7 +3024,7 @@ fn buildOutputType( |
| 3017 | 3024 | create_module.opts.emit_bin = emit_bin != .no; |
| 3018 | 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 | 3028 | for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| { |
| 3022 | 3029 | if (cli_mod.resolved == null) |
| 3023 | 3030 | fatal("module '{s}' declared but not used", .{key}); |
| ... | ... | @@ -3545,6 +3552,7 @@ fn buildOutputType( |
| 3545 | 3552 | var stdin_reader = fs.File.stdin().reader(&stdin_buffer); |
| 3546 | 3553 | var stdout_writer = fs.File.stdout().writer(&stdout_buffer); |
| 3547 | 3554 | try serve( |
| 3555 | io, | |
| 3548 | 3556 | comp, |
| 3549 | 3557 | &stdin_reader.interface, |
| 3550 | 3558 | &stdout_writer.interface, |
| ... | ... | @@ -3571,6 +3579,7 @@ fn buildOutputType( |
| 3571 | 3579 | var output = conn.stream.writer(&stdout_buffer); |
| 3572 | 3580 | |
| 3573 | 3581 | try serve( |
| 3582 | io, | |
| 3574 | 3583 | comp, |
| 3575 | 3584 | input.interface(), |
| 3576 | 3585 | &output.interface, |
| ... | ... | @@ -3646,6 +3655,7 @@ fn buildOutputType( |
| 3646 | 3655 | comp, |
| 3647 | 3656 | gpa, |
| 3648 | 3657 | arena, |
| 3658 | io, | |
| 3649 | 3659 | test_exec_args.items, |
| 3650 | 3660 | self_exe_path, |
| 3651 | 3661 | arg_mode, |
| ... | ... | @@ -3704,6 +3714,7 @@ const CreateModule = struct { |
| 3704 | 3714 | fn createModule( |
| 3705 | 3715 | gpa: Allocator, |
| 3706 | 3716 | arena: Allocator, |
| 3717 | io: Io, | |
| 3707 | 3718 | create_module: *CreateModule, |
| 3708 | 3719 | index: usize, |
| 3709 | 3720 | parent: ?*Package.Module, |
| ... | ... | @@ -3777,7 +3788,7 @@ fn createModule( |
| 3777 | 3788 | } |
| 3778 | 3789 | |
| 3779 | 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 | 3792 | break :t .{ |
| 3782 | 3793 | .result = target, |
| 3783 | 3794 | .is_native_os = target_query.isNativeOs(), |
| ... | ... | @@ -4022,7 +4033,7 @@ fn createModule( |
| 4022 | 4033 | for (cli_mod.deps) |dep| { |
| 4023 | 4034 | const dep_index = create_module.modules.getIndex(dep.value) orelse |
| 4024 | 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 | 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 | 4049 | } |
| 4039 | 4050 | |
| 4040 | 4051 | fn serve( |
| 4052 | io: Io, | |
| 4041 | 4053 | comp: *Compilation, |
| 4042 | in: *std.Io.Reader, | |
| 4043 | out: *std.Io.Writer, | |
| 4054 | in: *Io.Reader, | |
| 4055 | out: *Io.Writer, | |
| 4044 | 4056 | test_exec_args: []const ?[]const u8, |
| 4045 | 4057 | self_exe_path: ?[]const u8, |
| 4046 | 4058 | arg_mode: ArgMode, |
| ... | ... | @@ -4090,7 +4102,7 @@ fn serve( |
| 4090 | 4102 | defer arena_instance.deinit(); |
| 4091 | 4103 | const arena = arena_instance.allocator(); |
| 4092 | 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 | 4106 | defer output.deinit(gpa); |
| 4095 | 4107 | |
| 4096 | 4108 | if (file_system_inputs.items.len != 0) { |
| ... | ... | @@ -4126,6 +4138,7 @@ fn serve( |
| 4126 | 4138 | // comp, |
| 4127 | 4139 | // gpa, |
| 4128 | 4140 | // arena, |
| 4141 | // io, | |
| 4129 | 4142 | // test_exec_args, |
| 4130 | 4143 | // self_exe_path.?, |
| 4131 | 4144 | // arg_mode, |
| ... | ... | @@ -4280,6 +4293,7 @@ fn runOrTest( |
| 4280 | 4293 | comp: *Compilation, |
| 4281 | 4294 | gpa: Allocator, |
| 4282 | 4295 | arena: Allocator, |
| 4296 | io: Io, | |
| 4283 | 4297 | test_exec_args: []const ?[]const u8, |
| 4284 | 4298 | self_exe_path: []const u8, |
| 4285 | 4299 | arg_mode: ArgMode, |
| ... | ... | @@ -4334,7 +4348,7 @@ fn runOrTest( |
| 4334 | 4348 | std.debug.lockStdErr(); |
| 4335 | 4349 | const err = process.execve(gpa, argv.items, &env_map); |
| 4336 | 4350 | std.debug.unlockStdErr(); |
| 4337 | try warnAboutForeignBinaries(arena, arg_mode, target, link_libc); | |
| 4351 | try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc); | |
| 4338 | 4352 | const cmd = try std.mem.join(arena, " ", argv.items); |
| 4339 | 4353 | fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd }); |
| 4340 | 4354 | } else if (process.can_spawn) { |
| ... | ... | @@ -4355,7 +4369,7 @@ fn runOrTest( |
| 4355 | 4369 | break :t child.spawnAndWait(); |
| 4356 | 4370 | }; |
| 4357 | 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 | 4373 | const cmd = try std.mem.join(arena, " ", argv.items); |
| 4360 | 4374 | fatal("the following command failed with '{s}':\n{s}", .{ @errorName(err), cmd }); |
| 4361 | 4375 | }; |
| ... | ... | @@ -4594,11 +4608,12 @@ fn cmdTranslateC( |
| 4594 | 4608 | pub fn translateC( |
| 4595 | 4609 | gpa: Allocator, |
| 4596 | 4610 | arena: Allocator, |
| 4611 | io: Io, | |
| 4597 | 4612 | argv: []const []const u8, |
| 4598 | 4613 | prog_node: std.Progress.Node, |
| 4599 | 4614 | capture: ?*[]u8, |
| 4600 | 4615 | ) !void { |
| 4601 | try jitCmd(gpa, arena, argv, .{ | |
| 4616 | try jitCmd(gpa, arena, io, argv, .{ | |
| 4602 | 4617 | .cmd_name = "translate-c", |
| 4603 | 4618 | .root_src_path = "translate-c/main.zig", |
| 4604 | 4619 | .depend_on_aro = true, |
| ... | ... | @@ -4755,7 +4770,7 @@ test sanitizeExampleName { |
| 4755 | 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 | 4774 | dev.check(.build_command); |
| 4760 | 4775 | |
| 4761 | 4776 | var build_file: ?[]const u8 = null; |
| ... | ... | @@ -4983,7 +4998,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 4983 | 4998 | .arch_os_abi = triple, |
| 4984 | 4999 | }); |
| 4985 | 5000 | break :t .{ |
| 4986 | .result = std.zig.resolveTargetQueryOrFatal(target_query), | |
| 5001 | .result = std.zig.resolveTargetQueryOrFatal(io, target_query), | |
| 4987 | 5002 | .is_native_os = false, |
| 4988 | 5003 | .is_native_abi = false, |
| 4989 | 5004 | .is_explicit_dynamic_linker = false, |
| ... | ... | @@ -4991,7 +5006,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 4991 | 5006 | } |
| 4992 | 5007 | } |
| 4993 | 5008 | break :t .{ |
| 4994 | .result = std.zig.resolveTargetQueryOrFatal(.{}), | |
| 5009 | .result = std.zig.resolveTargetQueryOrFatal(io, .{}), | |
| 4995 | 5010 | .is_native_os = true, |
| 4996 | 5011 | .is_native_abi = true, |
| 4997 | 5012 | .is_explicit_dynamic_linker = false, |
| ... | ... | @@ -5400,6 +5415,7 @@ const JitCmdOptions = struct { |
| 5400 | 5415 | fn jitCmd( |
| 5401 | 5416 | gpa: Allocator, |
| 5402 | 5417 | arena: Allocator, |
| 5418 | io: Io, | |
| 5403 | 5419 | args: []const []const u8, |
| 5404 | 5420 | options: JitCmdOptions, |
| 5405 | 5421 | ) !void { |
| ... | ... | @@ -5412,7 +5428,7 @@ fn jitCmd( |
| 5412 | 5428 | |
| 5413 | 5429 | const target_query: std.Target.Query = .{}; |
| 5414 | 5430 | const resolved_target: Package.Module.ResolvedTarget = .{ |
| 5415 | .result = std.zig.resolveTargetQueryOrFatal(target_query), | |
| 5431 | .result = std.zig.resolveTargetQueryOrFatal(io, target_query), | |
| 5416 | 5432 | .is_native_os = true, |
| 5417 | 5433 | .is_native_abi = true, |
| 5418 | 5434 | .is_explicit_dynamic_linker = false, |
| ... | ... | @@ -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 | 6229 | dev.check(.detect_cpu_command); |
| 6214 | 6230 | |
| 6215 | 6231 | const detect_cpu_usage = |
| ... | ... | @@ -6254,7 +6270,7 @@ fn cmdDetectCpu(args: []const []const u8) !void { |
| 6254 | 6270 | const cpu = try detectNativeCpuWithLLVM(builtin.cpu.arch, name, features); |
| 6255 | 6271 | try printCpu(cpu); |
| 6256 | 6272 | } else { |
| 6257 | const host_target = std.zig.resolveTargetQueryOrFatal(.{}); | |
| 6273 | const host_target = std.zig.resolveTargetQueryOrFatal(io, .{}); | |
| 6258 | 6274 | try printCpu(host_target.cpu); |
| 6259 | 6275 | } |
| 6260 | 6276 | } |
| ... | ... | @@ -6521,13 +6537,14 @@ fn prefixedIntArg(arg: []const u8, prefix: []const u8) ?u64 { |
| 6521 | 6537 | } |
| 6522 | 6538 | |
| 6523 | 6539 | fn warnAboutForeignBinaries( |
| 6540 | io: Io, | |
| 6524 | 6541 | arena: Allocator, |
| 6525 | 6542 | arg_mode: ArgMode, |
| 6526 | 6543 | target: *const std.Target, |
| 6527 | 6544 | link_libc: bool, |
| 6528 | 6545 | ) !void { |
| 6529 | 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 | 6549 | switch (std.zig.system.getExternalExecutor(&host_target, target, .{ .link_libc = link_libc })) { |
| 6533 | 6550 | .native => return, |
| ... | ... | @@ -7080,7 +7097,7 @@ fn cmdFetch( |
| 7080 | 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 | 7101 | defer aw.deinit(); |
| 7085 | 7102 | try ast.render(gpa, &aw.writer, fixups); |
| 7086 | 7103 | const rendered = aw.written(); |