From 48cef8d5be24c40b4c845f6b07c78abd6c3d1b0d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 29 Feb 2020 21:31:03 -0500 Subject: [PATCH] refactor std.zig.system.NativeTargetInfo functions to make them a bit easier to test. --- lib/std/zig/system.zig | 65 ++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 7e23410fa..37834b441 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -399,17 +399,38 @@ pub const NativeTargetInfo = struct { return result; } + const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) { + error.NoSpaceLeft => unreachable, + error.NameTooLong => unreachable, + error.PathAlreadyExists => unreachable, + error.SharingViolation => unreachable, + error.InvalidUtf8 => unreachable, + error.BadPathName => unreachable, + error.PipeBusy => unreachable, + + error.IsDir, + error.NotDir, + error.AccessDenied, + error.NoDevice, + error.FileNotFound, + error.FileTooBig, + error.Unexpected, + => return defaultAbiAndDynamicLinker(cpu, os, cross_target), + + else => |e| return e, + }; + defer env_file.close(); + // If Zig is statically linked, such as via distributed binary static builds, the above // trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env. // Since that path is hard-coded into the shebang line of many portable scripts, it's a // reasonably reliable path to check for. - return abiAndDynamicLinkerFromUsrBinEnv(cpu, os, ld_info_list, cross_target) catch |err| switch (err) { + return abiAndDynamicLinkerFromFile(env_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) { error.FileSystem, error.SystemResources, error.SymLinkLoop, error.ProcessFdQuotaExceeded, error.SystemFdQuotaExceeded, - error.DeviceBusy, => |e| return e, error.UnableToReadElfFile, @@ -418,7 +439,6 @@ pub const NativeTargetInfo = struct { error.InvalidElfEndian, error.InvalidElfFile, error.InvalidElfMagic, - error.UsrBinEnvNotAvailable, error.Unexpected, error.UnexpectedEndOfFile, error.NameTooLong, @@ -461,32 +481,15 @@ pub const NativeTargetInfo = struct { }; } - fn abiAndDynamicLinkerFromUsrBinEnv( + pub fn abiAndDynamicLinkerFromFile( + file: fs.File, cpu: Target.Cpu, os: Target.Os, ld_info_list: []const LdInfo, cross_target: CrossTarget, ) !NativeTargetInfo { - const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - error.NameTooLong => unreachable, - error.PathAlreadyExists => unreachable, - error.SharingViolation => unreachable, - error.InvalidUtf8 => unreachable, - error.BadPathName => unreachable, - error.PipeBusy => unreachable, - - error.IsDir => return error.UsrBinEnvNotAvailable, - error.NotDir => return error.UsrBinEnvNotAvailable, - error.AccessDenied => return error.UsrBinEnvNotAvailable, - error.NoDevice => return error.UsrBinEnvNotAvailable, - error.FileNotFound => return error.UsrBinEnvNotAvailable, - error.FileTooBig => return error.UsrBinEnvNotAvailable, - - else => |e| return e, - }; var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined; - _ = try preadFull(env_file, &hdr_buf, 0, hdr_buf.len); + _ = try preadFull(file, &hdr_buf, 0, hdr_buf.len); const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf); const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf); if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic; @@ -526,7 +529,7 @@ pub const NativeTargetInfo = struct { // Reserve some bytes so that we can deref the 64-bit struct fields // even when the ELF file is 32-bits. const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr); - const ph_read_byte_len = try preadFull(env_file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize); + const ph_read_byte_len = try preadFull(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize); var ph_buf_i: usize = 0; while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({ ph_i += 1; @@ -541,7 +544,7 @@ pub const NativeTargetInfo = struct { const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; - _ = try preadFull(env_file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz); + _ = try preadFull(file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz); // PT_INTERP includes a null byte in p_filesz. const len = p_filesz - 1; // dynamic_linker.max_byte is "max", not "len". @@ -573,7 +576,7 @@ pub const NativeTargetInfo = struct { // even when the ELF file is 32-bits. const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn); const dyn_read_byte_len = try preadFull( - env_file, + file, dyn_buf[0 .. dyn_buf.len - dyn_reserve], dyn_off, dyn_size, @@ -617,14 +620,14 @@ pub const NativeTargetInfo = struct { var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined; if (sh_buf.len < shentsize) return error.InvalidElfFile; - _ = try preadFull(env_file, &sh_buf, str_section_off, shentsize); + _ = try preadFull(file, &sh_buf, str_section_off, shentsize); const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf)); const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf)); const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset); const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size); var strtab_buf: [4096:0]u8 = undefined; const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len); - const shstrtab_read_len = try preadFull(env_file, &strtab_buf, shstrtab_off, shstrtab_len); + const shstrtab_read_len = try preadFull(file, &strtab_buf, shstrtab_off, shstrtab_len); const shstrtab = strtab_buf[0..shstrtab_read_len]; const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum); @@ -634,7 +637,7 @@ pub const NativeTargetInfo = struct { // even when the ELF file is 32-bits. const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr); const sh_read_byte_len = try preadFull( - env_file, + file, sh_buf[0 .. sh_buf.len - sh_reserve], shoff, shentsize, @@ -667,7 +670,7 @@ pub const NativeTargetInfo = struct { if (dynstr) |ds| { const strtab_len = std.math.min(ds.size, strtab_buf.len); - const strtab_read_len = try preadFull(env_file, &strtab_buf, ds.offset, shstrtab_len); + const strtab_read_len = try preadFull(file, &strtab_buf, ds.offset, shstrtab_len); const strtab = strtab_buf[0..strtab_read_len]; // TODO this pointer cast should not be necessary const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr)); @@ -763,7 +766,7 @@ pub const NativeTargetInfo = struct { }; } - const LdInfo = struct { + pub const LdInfo = struct { ld: DynamicLinker, abi: Target.Abi, };