diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-06-04 12:30:38 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-06-04 12:30:38 -0400 |
| commit | a608ebaa500af2f45ee3b826127b81822c92d028 (patch) | |
| tree | a42da35c21eb5665e2401282bde1bf8c1e98b0e1 /std | |
| parent | 8e109aec6b9e508e46f3d016065ad4ada0a2fd36 (diff) | |
| parent | 46cbed621b287d339a97e77e8e1bfd5090bd247c (diff) | |
| download | zig-a608ebaa500af2f45ee3b826127b81822c92d028.tar.gz zig-a608ebaa500af2f45ee3b826127b81822c92d028.zip | |
Merge pull request #2581 from LemonBoy/misc-stuff
Miscellaneous stdlib changes
Diffstat (limited to 'std')
| -rw-r--r-- | std/os.zig | 67 | ||||
| -rw-r--r-- | std/os/bits/freebsd.zig | 7 | ||||
| -rw-r--r-- | std/os/bits/netbsd.zig | 7 | ||||
| -rw-r--r-- | std/os/linux/test.zig | 39 | ||||
| -rw-r--r-- | std/os/test.zig | 50 |
5 files changed, 130 insertions, 40 deletions
diff --git a/std/os.zig b/std/os.zig index 07c9f880c7..cc44025031 100644 --- a/std/os.zig +++ b/std/os.zig @@ -19,6 +19,8 @@ const builtin = @import("builtin"); const assert = std.debug.assert; const math = std.math; const mem = std.mem; +const elf = std.elf; +const dl = @import("dynamic_library.zig"); const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES; comptime { @@ -1955,7 +1957,6 @@ pub fn mmap( fd: fd_t, offset: isize, ) MMapError![]align(mem.page_size) u8 { - assert(mem.isAligned(length, mem.page_size)); const err = if (builtin.link_libc) blk: { const rc = std.c.mmap(ptr, length, prot, flags, fd, offset); if (rc != MAP_FAILED) return @ptrCast([*]align(mem.page_size) u8, @alignCast(mem.page_size, rc))[0..length]; @@ -2368,6 +2369,70 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void { } } +pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, data: ?*T) isize { + // This is implemented only for systems using ELF executables + if (windows.is_the_target or builtin.os == .uefi or wasi.is_the_target or darwin.is_the_target) + @compileError("dl_iterate_phdr is not available for this target"); + + if (builtin.link_libc) { + return system.dl_iterate_phdr( + @ptrCast(std.c.dl_iterate_phdr_callback, callback), + @ptrCast(?*c_void, data), + ); + } + + const elf_base = std.process.getBaseAddress(); + const ehdr = @intToPtr(*elf.Ehdr, elf_base); + // Make sure the base address points to an ELF image + assert(mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF")); + const n_phdr = ehdr.e_phnum; + const phdrs = (@intToPtr([*]elf.Phdr, elf_base + ehdr.e_phoff))[0..n_phdr]; + + var it = dl.linkmap_iterator(phdrs) catch unreachable; + + // The executable has no dynamic link segment, create a single entry for + // the whole ELF image + if (it.end()) { + var info = dl_phdr_info{ + .dlpi_addr = elf_base, + .dlpi_name = c"/proc/self/exe", + .dlpi_phdr = phdrs.ptr, + .dlpi_phnum = ehdr.e_phnum, + }; + + return callback(&info, @sizeOf(dl_phdr_info), data); + } + + // Last return value from the callback function + var last_r: isize = 0; + while (it.next()) |entry| { + var dlpi_phdr: [*]elf.Phdr = undefined; + var dlpi_phnum: u16 = undefined; + + if (entry.l_addr != 0) { + const elf_header = @intToPtr(*elf.Ehdr, entry.l_addr); + dlpi_phdr = @intToPtr([*]elf.Phdr, entry.l_addr + elf_header.e_phoff); + dlpi_phnum = elf_header.e_phnum; + } else { + // This is the running ELF image + dlpi_phdr = @intToPtr([*]elf.Phdr, elf_base + ehdr.e_phoff); + dlpi_phnum = ehdr.e_phnum; + } + + var info = dl_phdr_info{ + .dlpi_addr = entry.l_addr, + .dlpi_name = entry.l_name, + .dlpi_phdr = dlpi_phdr, + .dlpi_phnum = dlpi_phnum, + }; + + last_r = callback(&info, @sizeOf(dl_phdr_info), data); + if (last_r != 0) break; + } + + return last_r; +} + pub const ClockGetTimeError = error{ UnsupportedClock, Unexpected, diff --git a/std/os/bits/freebsd.zig b/std/os/bits/freebsd.zig index 3fc019f9c1..c73887d648 100644 --- a/std/os/bits/freebsd.zig +++ b/std/os/bits/freebsd.zig @@ -20,6 +20,13 @@ pub const pthread_attr_t = extern struct { __align: c_long, }; +pub const dl_phdr_info = extern struct { + dlpi_addr: usize, + dlpi_name: ?[*]const u8, + dlpi_phdr: [*]std.elf.Phdr, + dlpi_phnum: u16, +}; + pub const msghdr = extern struct { /// optional address msg_name: ?*sockaddr, diff --git a/std/os/bits/netbsd.zig b/std/os/bits/netbsd.zig index e7a0f6ea52..d83ea82b06 100644 --- a/std/os/bits/netbsd.zig +++ b/std/os/bits/netbsd.zig @@ -20,6 +20,13 @@ pub const pthread_attr_t = extern struct { pta_private: *c_void, }; +pub const dl_phdr_info = extern struct { + dlpi_addr: usize, + dlpi_name: ?[*]const u8, + dlpi_phdr: [*]std.elf.Phdr, + dlpi_phnum: u16, +}; + pub const msghdr = extern struct { /// optional address msg_name: ?*sockaddr, diff --git a/std/os/linux/test.zig b/std/os/linux/test.zig index c78b071c74..637308638a 100644 --- a/std/os/linux/test.zig +++ b/std/os/linux/test.zig @@ -44,42 +44,3 @@ test "timer" { // TODO implicit cast from *[N]T to [*]T err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1); } - -export fn iter_fn(info: *linux.dl_phdr_info, size: usize, data: ?*usize) i32 { - var counter = data.?; - // Count how many libraries are loaded - counter.* += usize(1); - - // The image should contain at least a PT_LOAD segment - if (info.dlpi_phnum < 1) return -1; - - // Quick & dirty validation of the phdr pointers, make sure we're not - // pointing to some random gibberish - var i: usize = 0; - var found_load = false; - while (i < info.dlpi_phnum) : (i += 1) { - const phdr = info.dlpi_phdr[i]; - - if (phdr.p_type != elf.PT_LOAD) continue; - - // Find the ELF header - const elf_header = @intToPtr(*elf.Ehdr, phdr.p_vaddr - phdr.p_offset); - // Validate the magic - if (!mem.eql(u8, elf_header.e_ident[0..], "\x7fELF")) return -1; - // Consistency check - if (elf_header.e_phnum != info.dlpi_phnum) return -1; - - found_load = true; - break; - } - - if (!found_load) return -1; - - return 42; -} - -test "dl_iterate_phdr" { - var counter: usize = 0; - expect(linux.dl_iterate_phdr(usize, iter_fn, &counter) != 0); - expect(counter != 0); -} diff --git a/std/os/test.zig b/std/os/test.zig index dfcd25c4bb..a821c5dd9f 100644 --- a/std/os/test.zig +++ b/std/os/test.zig @@ -5,6 +5,7 @@ const expect = std.testing.expect; const io = std.io; const fs = std.fs; const mem = std.mem; +const elf = std.elf; const File = std.fs.File; const Thread = std.Thread; @@ -160,3 +161,52 @@ test "sigaltstack" { st.ss_size = 1; testing.expectError(error.SizeTooSmall, os.sigaltstack(&st, null)); } + +// If the type is not available use void to avoid erroring out when `iter_fn` is +// analyzed +const dl_phdr_info = if (@hasDecl(os, "dl_phdr_info")) os.dl_phdr_info else c_void; + +export fn iter_fn(info: *dl_phdr_info, size: usize, data: ?*usize) i32 { + if (builtin.os == .windows or builtin.os == .wasi or builtin.os == .macosx) + return 0; + + var counter = data.?; + // Count how many libraries are loaded + counter.* += usize(1); + + // The image should contain at least a PT_LOAD segment + if (info.dlpi_phnum < 1) return -1; + + // Quick & dirty validation of the phdr pointers, make sure we're not + // pointing to some random gibberish + var i: usize = 0; + var found_load = false; + while (i < info.dlpi_phnum) : (i += 1) { + const phdr = info.dlpi_phdr[i]; + + if (phdr.p_type != elf.PT_LOAD) continue; + + // Find the ELF header + const elf_header = @intToPtr(*elf.Ehdr, phdr.p_vaddr - phdr.p_offset); + // Validate the magic + if (!mem.eql(u8, elf_header.e_ident[0..4], "\x7fELF")) return -1; + // Consistency check + if (elf_header.e_phnum != info.dlpi_phnum) return -1; + + found_load = true; + break; + } + + if (!found_load) return -1; + + return 42; +} + +test "dl_iterate_phdr" { + if (builtin.os == .windows or builtin.os == .wasi or builtin.os == .macosx) + return error.SkipZigTest; + + var counter: usize = 0; + expect(os.dl_iterate_phdr(usize, iter_fn, &counter) != 0); + expect(counter != 0); +} |
