authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-27 19:49:00-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-28 14:51:56-05:00
log3683ba87ac5e5dfb6ea65c21c9fb714ed0582124
tree4f46634e9c253a42bd33c763991d2957afd8a4d7
parentfd006c1c74a43827a6f1c32e289ba57cafa874be
signaturelock-open Commit is signed but in an unrecognized format.

complete the native target detection based on /usr/bin/env


4 files changed, 244 insertions(+), 77 deletions(-)

lib/std/c.zig+1
...@@ -108,6 +108,7 @@ pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8...@@ -108,6 +108,7 @@ pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8
108pub extern "c" fn dup(fd: fd_t) c_int;108pub extern "c" fn dup(fd: fd_t) c_int;
109pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int;109pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int;
110pub extern "c" fn readlink(noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;110pub extern "c" fn readlink(noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;
111pub extern "c" fn readlinkat(dirfd: fd_t, noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;
111pub extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;112pub extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
112pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;113pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
113pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;114pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
lib/std/dynamic_library.zig+2-2
...@@ -82,12 +82,12 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {...@@ -82,12 +82,12 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {
82 for (dyn_table) |*dyn| {82 for (dyn_table) |*dyn| {
83 switch (dyn.d_tag) {83 switch (dyn.d_tag) {
84 elf.DT_DEBUG => {84 elf.DT_DEBUG => {
85 const r_debug = @intToPtr(*RDebug, dyn.d_un.d_ptr);85 const r_debug = @intToPtr(*RDebug, dyn.d_val);
86 if (r_debug.r_version != 1) return error.InvalidExe;86 if (r_debug.r_version != 1) return error.InvalidExe;
87 break :init r_debug.r_map;87 break :init r_debug.r_map;
88 },88 },
89 elf.DT_PLTGOT => {89 elf.DT_PLTGOT => {
90 const got_table = @intToPtr([*]usize, dyn.d_un.d_ptr);90 const got_table = @intToPtr([*]usize, dyn.d_val);
91 // The address to the link_map structure is stored in the91 // The address to the link_map structure is stored in the
92 // second slot92 // second slot
93 break :init @intToPtr(?*LinkMap, got_table[1]);93 break :init @intToPtr(?*LinkMap, got_table[1]);
lib/std/elf.zig+2-8
...@@ -708,17 +708,11 @@ pub const Elf64_Rela = extern struct {...@@ -708,17 +708,11 @@ pub const Elf64_Rela = extern struct {
708};708};
709pub const Elf32_Dyn = extern struct {709pub const Elf32_Dyn = extern struct {
710 d_tag: Elf32_Sword,710 d_tag: Elf32_Sword,
711 d_un: extern union {711 d_val: Elf32_Addr,
712 d_val: Elf32_Word,
713 d_ptr: Elf32_Addr,
714 },
715};712};
716pub const Elf64_Dyn = extern struct {713pub const Elf64_Dyn = extern struct {
717 d_tag: Elf64_Sxword,714 d_tag: Elf64_Sxword,
718 d_un: extern union {715 d_val: Elf64_Addr,
719 d_val: Elf64_Xword,
720 d_ptr: Elf64_Addr,
721 },
722};716};
723pub const Elf32_Verdef = extern struct {717pub const Elf32_Verdef = extern struct {
724 vd_version: Elf32_Half,718 vd_version: Elf32_Half,
lib/std/zig/system.zig+239-67
...@@ -238,16 +238,6 @@ pub const NativeTargetInfo = struct {...@@ -238,16 +238,6 @@ pub const NativeTargetInfo = struct {
238 // A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined238 // A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined
239 // and supported by Zig. But that means that we must detect the system ABI here rather than239 // and supported by Zig. But that means that we must detect the system ABI here rather than
240 // relying on `Target.current`.240 // relying on `Target.current`.
241 const LdInfo = struct {
242 ld_path_buffer: [255]u8,
243 ld_path_max: u8,
244 abi: Target.Abi,
245
246 pub fn ldPath(self: *const @This()) []const u8 {
247 const m: usize = self.ld_path_max;
248 return self.ld_path_buffer[0 .. m + 1];
249 }
250 };
251 const all_abis = comptime blk: {241 const all_abis = comptime blk: {
252 assert(@enumToInt(Target.Abi.none) == 0);242 assert(@enumToInt(Target.Abi.none) == 0);
253 const fields = std.meta.fields(Target.Abi)[1..];243 const fields = std.meta.fields(Target.Abi)[1..];
...@@ -333,7 +323,7 @@ pub const NativeTargetInfo = struct {...@@ -333,7 +323,7 @@ pub const NativeTargetInfo = struct {
333 // trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env.323 // trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env.
334 // Since that path is hard-coded into the shebang line of many portable scripts, it's a324 // Since that path is hard-coded into the shebang line of many portable scripts, it's a
335 // reasonably reliable path to check for.325 // reasonably reliable path to check for.
336 return abiAndDynamicLinkerFromUsrBinEnv(cpu, os) catch |err| switch (err) {326 return abiAndDynamicLinkerFromUsrBinEnv(cpu, os, ld_info_list) catch |err| switch (err) {
337 error.FileSystem,327 error.FileSystem,
338 error.SystemResources,328 error.SystemResources,
339 error.SymLinkLoop,329 error.SymLinkLoop,
...@@ -343,8 +333,6 @@ pub const NativeTargetInfo = struct {...@@ -343,8 +333,6 @@ pub const NativeTargetInfo = struct {
343 => |e| return e,333 => |e| return e,
344334
345 error.UnableToReadElfFile,335 error.UnableToReadElfFile,
346 error.ElfNotADynamicExecutable,
347 error.InvalidElfProgramHeaders,
348 error.InvalidElfClass,336 error.InvalidElfClass,
349 error.InvalidElfVersion,337 error.InvalidElfVersion,
350 error.InvalidElfEndian,338 error.InvalidElfEndian,
...@@ -373,6 +361,10 @@ pub const NativeTargetInfo = struct {...@@ -373,6 +361,10 @@ pub const NativeTargetInfo = struct {
373 error.NotDir => return error.GnuLibCVersionUnavailable,361 error.NotDir => return error.GnuLibCVersionUnavailable,
374 error.Unexpected => return error.GnuLibCVersionUnavailable,362 error.Unexpected => return error.GnuLibCVersionUnavailable,
375 };363 };
364 return glibcVerFromLinkName(link_name);
365 }
366
367 fn glibcVerFromLinkName(link_name: []const u8) !std.builtin.Version {
376 // example: "libc-2.3.4.so"368 // example: "libc-2.3.4.so"
377 // example: "libc-2.27.so"369 // example: "libc-2.27.so"
378 const prefix = "libc-";370 const prefix = "libc-";
...@@ -389,7 +381,11 @@ pub const NativeTargetInfo = struct {...@@ -389,7 +381,11 @@ pub const NativeTargetInfo = struct {
389 };381 };
390 }382 }
391383
392 fn abiAndDynamicLinkerFromUsrBinEnv(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo {384 fn abiAndDynamicLinkerFromUsrBinEnv(
385 cpu: Target.Cpu,
386 os: Target.Os,
387 ld_info_list: []const LdInfo,
388 ) !NativeTargetInfo {
393 const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) {389 const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) {
394 error.NoSpaceLeft => unreachable,390 error.NoSpaceLeft => unreachable,
395 error.NameTooLong => unreachable,391 error.NameTooLong => unreachable,
...@@ -409,8 +405,7 @@ pub const NativeTargetInfo = struct {...@@ -409,8 +405,7 @@ pub const NativeTargetInfo = struct {
409 else => |e| return e,405 else => |e| return e,
410 };406 };
411 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined;407 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined;
412 const hdr_bytes_len = try wrapRead(env_file.pread(&hdr_buf, 0));408 _ = try preadFull(env_file, &hdr_buf, 0, hdr_buf.len);
413 if (hdr_bytes_len < @sizeOf(elf.Elf32_Ehdr)) return error.InvalidElfFile;
414 const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);409 const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
415 const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);410 const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
416 if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;411 if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
...@@ -430,7 +425,6 @@ pub const NativeTargetInfo = struct {...@@ -430,7 +425,6 @@ pub const NativeTargetInfo = struct {
430 var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff);425 var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff);
431 const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize);426 const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize);
432 const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum);427 const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum);
433 const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx);
434428
435 var result: NativeTargetInfo = .{429 var result: NativeTargetInfo = .{
436 .target = .{430 .target = .{
...@@ -439,67 +433,234 @@ pub const NativeTargetInfo = struct {...@@ -439,67 +433,234 @@ pub const NativeTargetInfo = struct {
439 .abi = Target.Abi.default(cpu.arch, os),433 .abi = Target.Abi.default(cpu.arch, os),
440 },434 },
441 };435 };
436 var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC
442437
443 const ph_total_size = std.math.mul(u32, phentsize, phnum) catch |err| switch (err) {
444 error.Overflow => return error.InvalidElfProgramHeaders,
445 };
446 var ph_buf: [16 * @sizeOf(elf.Elf64_Phdr)]u8 align(@alignOf(elf.Elf64_Phdr)) = undefined;438 var ph_buf: [16 * @sizeOf(elf.Elf64_Phdr)]u8 align(@alignOf(elf.Elf64_Phdr)) = undefined;
439 if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile;
440
447 var ph_i: u16 = 0;441 var ph_i: u16 = 0;
448 while (ph_i < phnum) {442 while (ph_i < phnum) {
449 // Reserve some bytes so that we can deref the 64-bit struct fields even when the ELF file is 32-bits.443 // Reserve some bytes so that we can deref the 64-bit struct fields
450 const reserve = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr);444 // even when the ELF file is 32-bits.
451 const read_byte_len = try wrapRead(env_file.pread(ph_buf[0 .. ph_buf.len - reserve], phoff));445 const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr);
452 if (read_byte_len < phentsize) return error.ElfNotADynamicExecutable;446 const ph_read_byte_len = try preadFull(env_file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize);
453 var buf_i: usize = 0;447 var ph_buf_i: usize = 0;
454 while (buf_i < read_byte_len and ph_i < phnum) : ({448 while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({
455 ph_i += 1;449 ph_i += 1;
456 phoff += phentsize;450 phoff += phentsize;
457 buf_i += phentsize;451 ph_buf_i += phentsize;
458 }) {452 }) {
459 const ph32 = @ptrCast(*elf.Elf32_Phdr, @alignCast(@alignOf(elf.Elf32_Phdr), &ph_buf[buf_i]));453 const ph32 = @ptrCast(*elf.Elf32_Phdr, @alignCast(@alignOf(elf.Elf32_Phdr), &ph_buf[ph_buf_i]));
460 const ph64 = @ptrCast(*elf.Elf64_Phdr, @alignCast(@alignOf(elf.Elf64_Phdr), &ph_buf[buf_i]));454 const ph64 = @ptrCast(*elf.Elf64_Phdr, @alignCast(@alignOf(elf.Elf64_Phdr), &ph_buf[ph_buf_i]));
461 const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type);455 const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type);
462 switch (p_type) {456 switch (p_type) {
463 elf.PT_INTERP => {457 elf.PT_INTERP => {
464 const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);458 const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
465 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);459 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
466 var interp_buf: [255]u8 = undefined;460 if (p_filesz > result.dynamic_linker_buffer.len) return error.NameTooLong;
467 if (p_filesz > interp_buf.len) return error.NameTooLong;461 _ = try preadFull(env_file, result.dynamic_linker_buffer[0..p_filesz], p_offset, p_filesz);
468 var read_offset: usize = 0;
469 while (true) {
470 const len = try wrapRead(env_file.pread(
471 interp_buf[read_offset .. p_filesz - read_offset],
472 p_offset + read_offset,
473 ));
474 if (len == 0) return error.UnexpectedEndOfFile;
475 read_offset += len;
476 if (read_offset == p_filesz) break;
477 }
478 // PT_INTERP includes a null byte in p_filesz.462 // PT_INTERP includes a null byte in p_filesz.
479 result.setDynamicLinker(interp_buf[0 .. p_filesz - 1]);463 const len = p_filesz - 1;
464 // dynamic_linker_max is "max", not "len".
465 // We know it will fit in u8 because we check against dynamic_linker_buffer.len above.
466 result.dynamic_linker_max = @intCast(u8, len - 1);
467
468 // Use it to determine ABI.
469 const full_ld_path = result.dynamic_linker_buffer[0..len];
470 for (ld_info_list) |ld_info| {
471 const standard_ld_basename = fs.path.basename(ld_info.ldPath());
472 if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
473 result.target.abi = ld_info.abi;
474 break;
475 }
476 }
480 },477 },
481 elf.PT_DYNAMIC => {478 // We only need this for detecting glibc version.
482 std.debug.warn("found PT_DYNAMIC\n", .{});479 elf.PT_DYNAMIC => if (Target.current.os.tag == .linux and result.target.isGnuLibC()) {
480 var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
481 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
482 const dyn_size: u64 = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn);
483 const dyn_num = p_filesz / dyn_size;
484 var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined;
485 var dyn_i: usize = 0;
486 dyn: while (dyn_i < dyn_num) {
487 // Reserve some bytes so that we can deref the 64-bit struct fields
488 // even when the ELF file is 32-bits.
489 const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
490 const dyn_read_byte_len = try preadFull(
491 env_file,
492 dyn_buf[0 .. dyn_buf.len - dyn_reserve],
493 dyn_off,
494 dyn_size,
495 );
496 var dyn_buf_i: usize = 0;
497 while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({
498 dyn_i += 1;
499 dyn_off += dyn_size;
500 dyn_buf_i += dyn_size;
501 }) {
502 const dyn32 = @ptrCast(
503 *elf.Elf32_Dyn,
504 @alignCast(@alignOf(elf.Elf32_Dyn), &dyn_buf[dyn_buf_i]),
505 );
506 const dyn64 = @ptrCast(
507 *elf.Elf64_Dyn,
508 @alignCast(@alignOf(elf.Elf64_Dyn), &dyn_buf[dyn_buf_i]),
509 );
510 const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag);
511 const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val);
512 if (tag == elf.DT_RUNPATH) {
513 rpath_offset = val;
514 break :dyn;
515 }
516 }
517 }
483 },518 },
484 else => continue,519 else => continue,
485 }520 }
486 }521 }
487 }522 }
488523
524 if (Target.current.os.tag == .linux and result.target.isGnuLibC()) {
525 if (rpath_offset) |rpoff| {
526 const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx);
527
528 var shoff = elfInt(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff);
529 const shentsize = elfInt(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize);
530 const str_section_off = shoff + @as(u64, shentsize) * @as(u64, shstrndx);
531
532 var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined;
533 if (sh_buf.len < shentsize) return error.InvalidElfFile;
534
535 _ = try preadFull(env_file, &sh_buf, str_section_off, shentsize);
536 const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf));
537 const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf));
538 const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset);
539 const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size);
540 var strtab_buf: [4096:0]u8 = undefined;
541 const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len);
542 const shstrtab_read_len = try preadFull(env_file, &strtab_buf, shstrtab_off, shstrtab_len);
543 const shstrtab = strtab_buf[0..shstrtab_read_len];
544
545 const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum);
546 var sh_i: u16 = 0;
547 const dynstr: ?struct { offset: u64, size: u64 } = find_dyn_str: while (sh_i < shnum) {
548 // Reserve some bytes so that we can deref the 64-bit struct fields
549 // even when the ELF file is 32-bits.
550 const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr);
551 const sh_read_byte_len = try preadFull(
552 env_file,
553 sh_buf[0 .. sh_buf.len - sh_reserve],
554 shoff,
555 shentsize,
556 );
557 var sh_buf_i: usize = 0;
558 while (sh_buf_i < sh_read_byte_len and sh_i < shnum) : ({
559 sh_i += 1;
560 shoff += shentsize;
561 sh_buf_i += shentsize;
562 }) {
563 const sh32 = @ptrCast(
564 *elf.Elf32_Shdr,
565 @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf[sh_buf_i]),
566 );
567 const sh64 = @ptrCast(
568 *elf.Elf64_Shdr,
569 @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf[sh_buf_i]),
570 );
571 const sh_name_off = elfInt(is_64, need_bswap, sh32.sh_name, sh64.sh_name);
572 // TODO this pointer cast should not be necessary
573 const sh_name = mem.toSliceConst(u8, @ptrCast([*:0]u8, shstrtab[sh_name_off..].ptr));
574 if (mem.eql(u8, sh_name, ".dynstr")) {
575 break :find_dyn_str .{
576 .offset = elfInt(is_64, need_bswap, sh32.sh_offset, sh64.sh_offset),
577 .size = elfInt(is_64, need_bswap, sh32.sh_size, sh64.sh_size),
578 };
579 }
580 }
581 } else null;
582
583 if (dynstr) |ds| {
584 const strtab_len = std.math.min(ds.size, strtab_buf.len);
585 const strtab_read_len = try preadFull(env_file, &strtab_buf, ds.offset, shstrtab_len);
586 const strtab = strtab_buf[0..strtab_read_len];
587 // TODO this pointer cast should not be necessary
588 const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr));
589 var it = mem.tokenize(rpath_list, ":");
590 while (it.next()) |rpath| {
591 var dir = fs.cwd().openDirList(rpath) catch |err| switch (err) {
592 error.NameTooLong => unreachable,
593 error.InvalidUtf8 => unreachable,
594 error.BadPathName => unreachable,
595 error.DeviceBusy => unreachable,
596
597 error.FileNotFound,
598 error.NotDir,
599 error.AccessDenied,
600 error.NoDevice,
601 => continue,
602
603 error.ProcessFdQuotaExceeded,
604 error.SystemFdQuotaExceeded,
605 error.SystemResources,
606 error.SymLinkLoop,
607 error.Unexpected,
608 => |e| return e,
609 };
610 defer dir.close();
611
612 var link_buf: [std.os.PATH_MAX]u8 = undefined;
613 const link_name = std.os.readlinkatC(
614 dir.fd,
615 glibc_so_basename,
616 &link_buf,
617 ) catch |err| switch (err) {
618 error.NameTooLong => unreachable,
619
620 error.AccessDenied,
621 error.FileNotFound,
622 error.NotDir,
623 => continue,
624
625 error.SystemResources,
626 error.FileSystem,
627 error.SymLinkLoop,
628 error.Unexpected,
629 => |e| return e,
630 };
631 result.target.os.version_range.linux.glibc = glibcVerFromLinkName(
632 link_name,
633 ) catch |err| switch (err) {
634 error.UnrecognizedGnuLibCFileName,
635 error.InvalidGnuLibCVersion,
636 => continue,
637 };
638 break;
639 }
640 }
641 }
642 }
643
489 return result;644 return result;
490 }645 }
491646
492 fn wrapRead(res: std.os.ReadError!usize) !usize {647 fn preadFull(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize {
493 return res catch |err| switch (err) {648 var i: u64 = 0;
494 error.OperationAborted => unreachable, // Windows-only649 while (i < min_read_len) {
495 error.WouldBlock => unreachable, // Did not request blocking mode650 const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
496 error.SystemResources => return error.SystemResources,651 error.OperationAborted => unreachable, // Windows-only
497 error.IsDir => return error.UnableToReadElfFile,652 error.WouldBlock => unreachable, // Did not request blocking mode
498 error.BrokenPipe => return error.UnableToReadElfFile,653 error.SystemResources => return error.SystemResources,
499 error.ConnectionResetByPeer => return error.UnableToReadElfFile,654 error.IsDir => return error.UnableToReadElfFile,
500 error.Unexpected => return error.Unexpected,655 error.BrokenPipe => return error.UnableToReadElfFile,
501 error.InputOutput => return error.FileSystem,656 error.ConnectionResetByPeer => return error.UnableToReadElfFile,
502 };657 error.Unexpected => return error.Unexpected,
658 error.InputOutput => return error.FileSystem,
659 };
660 if (len == 0) return error.UnexpectedEndOfFile;
661 i += len;
662 }
663 return i;
503 }664 }
504665
505 fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo {666 fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo {
...@@ -513,20 +674,31 @@ pub const NativeTargetInfo = struct {...@@ -513,20 +674,31 @@ pub const NativeTargetInfo = struct {
513 result.dynamic_linker_max = result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer);674 result.dynamic_linker_max = result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer);
514 return result;675 return result;
515 }676 }
516};
517677
518fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) {678 const LdInfo = struct {
519 if (is_64) {679 ld_path_buffer: [255]u8,
520 if (need_bswap) {680 ld_path_max: u8,
521 return @byteSwap(@TypeOf(int_64), int_64);681 abi: Target.Abi,
522 } else {682
523 return int_64;683 pub fn ldPath(self: *const LdInfo) []const u8 {
684 const m: usize = self.ld_path_max;
685 return self.ld_path_buffer[0 .. m + 1];
524 }686 }
525 } else {687 };
526 if (need_bswap) {688
527 return @byteSwap(@TypeOf(int_32), int_32);689 fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) {
690 if (is_64) {
691 if (need_bswap) {
692 return @byteSwap(@TypeOf(int_64), int_64);
693 } else {
694 return int_64;
695 }
528 } else {696 } else {
529 return int_32;697 if (need_bswap) {
698 return @byteSwap(@TypeOf(int_32), int_32);
699 } else {
700 return int_32;
701 }
530 }702 }
531 }703 }
532}704};