| author | |
| committer | |
| log | a608ebaa500af2f45ee3b826127b81822c92d028 |
| tree | a42da35c21eb5665e2401282bde1bf8c1e98b0e1 |
| parent | 8e109aec6b9e508e46f3d016065ad4ada0a2fd36 |
| parent | 46cbed621b287d339a97e77e8e1bfd5090bd247c |
| signature |
Miscellaneous stdlib changes5 files changed, 130 insertions(+), 40 deletions(-)
std/os.zig+66-1| ... | @@ -19,6 +19,8 @@ const builtin = @import("builtin"); | ... | @@ -19,6 +19,8 @@ const builtin = @import("builtin"); |
| 19 | const assert = std.debug.assert; | 19 | const assert = std.debug.assert; |
| 20 | const math = std.math; | 20 | const math = std.math; |
| 21 | const mem = std.mem; | 21 | const mem = std.mem; |
| 22 | const elf = std.elf; | ||
| 23 | const dl = @import("dynamic_library.zig"); | ||
| 22 | const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES; | 24 | const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES; |
| 23 | 25 | ||
| 24 | comptime { | 26 | comptime { |
| ... | @@ -1955,7 +1957,6 @@ pub fn mmap( | ... | @@ -1955,7 +1957,6 @@ pub fn mmap( |
| 1955 | fd: fd_t, | 1957 | fd: fd_t, |
| 1956 | offset: isize, | 1958 | offset: isize, |
| 1957 | ) MMapError![]align(mem.page_size) u8 { | 1959 | ) MMapError![]align(mem.page_size) u8 { |
| 1958 | assert(mem.isAligned(length, mem.page_size)); | ||
| 1959 | const err = if (builtin.link_libc) blk: { | 1960 | const err = if (builtin.link_libc) blk: { |
| 1960 | const rc = std.c.mmap(ptr, length, prot, flags, fd, offset); | 1961 | const rc = std.c.mmap(ptr, length, prot, flags, fd, offset); |
| 1961 | if (rc != MAP_FAILED) return @ptrCast([*]align(mem.page_size) u8, @alignCast(mem.page_size, rc))[0..length]; | 1962 | 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 { | ... | @@ -2368,6 +2369,70 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void { |
| 2368 | } | 2369 | } |
| 2369 | } | 2370 | } |
| 2370 | 2371 | ||
| 2372 | pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, data: ?*T) isize { | ||
| 2373 | // This is implemented only for systems using ELF executables | ||
| 2374 | if (windows.is_the_target or builtin.os == .uefi or wasi.is_the_target or darwin.is_the_target) | ||
| 2375 | @compileError("dl_iterate_phdr is not available for this target"); | ||
| 2376 | |||
| 2377 | if (builtin.link_libc) { | ||
| 2378 | return system.dl_iterate_phdr( | ||
| 2379 | @ptrCast(std.c.dl_iterate_phdr_callback, callback), | ||
| 2380 | @ptrCast(?*c_void, data), | ||
| 2381 | ); | ||
| 2382 | } | ||
| 2383 | |||
| 2384 | const elf_base = std.process.getBaseAddress(); | ||
| 2385 | const ehdr = @intToPtr(*elf.Ehdr, elf_base); | ||
| 2386 | // Make sure the base address points to an ELF image | ||
| 2387 | assert(mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF")); | ||
| 2388 | const n_phdr = ehdr.e_phnum; | ||
| 2389 | const phdrs = (@intToPtr([*]elf.Phdr, elf_base + ehdr.e_phoff))[0..n_phdr]; | ||
| 2390 | |||
| 2391 | var it = dl.linkmap_iterator(phdrs) catch unreachable; | ||
| 2392 | |||
| 2393 | // The executable has no dynamic link segment, create a single entry for | ||
| 2394 | // the whole ELF image | ||
| 2395 | if (it.end()) { | ||
| 2396 | var info = dl_phdr_info{ | ||
| 2397 | .dlpi_addr = elf_base, | ||
| 2398 | .dlpi_name = c"/proc/self/exe", | ||
| 2399 | .dlpi_phdr = phdrs.ptr, | ||
| 2400 | .dlpi_phnum = ehdr.e_phnum, | ||
| 2401 | }; | ||
| 2402 | |||
| 2403 | return callback(&info, @sizeOf(dl_phdr_info), data); | ||
| 2404 | } | ||
| 2405 | |||
| 2406 | // Last return value from the callback function | ||
| 2407 | var last_r: isize = 0; | ||
| 2408 | while (it.next()) |entry| { | ||
| 2409 | var dlpi_phdr: [*]elf.Phdr = undefined; | ||
| 2410 | var dlpi_phnum: u16 = undefined; | ||
| 2411 | |||
| 2412 | if (entry.l_addr != 0) { | ||
| 2413 | const elf_header = @intToPtr(*elf.Ehdr, entry.l_addr); | ||
| 2414 | dlpi_phdr = @intToPtr([*]elf.Phdr, entry.l_addr + elf_header.e_phoff); | ||
| 2415 | dlpi_phnum = elf_header.e_phnum; | ||
| 2416 | } else { | ||
| 2417 | // This is the running ELF image | ||
| 2418 | dlpi_phdr = @intToPtr([*]elf.Phdr, elf_base + ehdr.e_phoff); | ||
| 2419 | dlpi_phnum = ehdr.e_phnum; | ||
| 2420 | } | ||
| 2421 | |||
| 2422 | var info = dl_phdr_info{ | ||
| 2423 | .dlpi_addr = entry.l_addr, | ||
| 2424 | .dlpi_name = entry.l_name, | ||
| 2425 | .dlpi_phdr = dlpi_phdr, | ||
| 2426 | .dlpi_phnum = dlpi_phnum, | ||
| 2427 | }; | ||
| 2428 | |||
| 2429 | last_r = callback(&info, @sizeOf(dl_phdr_info), data); | ||
| 2430 | if (last_r != 0) break; | ||
| 2431 | } | ||
| 2432 | |||
| 2433 | return last_r; | ||
| 2434 | } | ||
| 2435 | |||
| 2371 | pub const ClockGetTimeError = error{ | 2436 | pub const ClockGetTimeError = error{ |
| 2372 | UnsupportedClock, | 2437 | UnsupportedClock, |
| 2373 | Unexpected, | 2438 | Unexpected, |
std/os/bits/freebsd.zig+7| ... | @@ -20,6 +20,13 @@ pub const pthread_attr_t = extern struct { | ... | @@ -20,6 +20,13 @@ pub const pthread_attr_t = extern struct { |
| 20 | __align: c_long, | 20 | __align: c_long, |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | pub const dl_phdr_info = extern struct { | ||
| 24 | dlpi_addr: usize, | ||
| 25 | dlpi_name: ?[*]const u8, | ||
| 26 | dlpi_phdr: [*]std.elf.Phdr, | ||
| 27 | dlpi_phnum: u16, | ||
| 28 | }; | ||
| 29 | |||
| 23 | pub const msghdr = extern struct { | 30 | pub const msghdr = extern struct { |
| 24 | /// optional address | 31 | /// optional address |
| 25 | msg_name: ?*sockaddr, | 32 | msg_name: ?*sockaddr, |
std/os/bits/netbsd.zig+7| ... | @@ -20,6 +20,13 @@ pub const pthread_attr_t = extern struct { | ... | @@ -20,6 +20,13 @@ pub const pthread_attr_t = extern struct { |
| 20 | pta_private: *c_void, | 20 | pta_private: *c_void, |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | pub const dl_phdr_info = extern struct { | ||
| 24 | dlpi_addr: usize, | ||
| 25 | dlpi_name: ?[*]const u8, | ||
| 26 | dlpi_phdr: [*]std.elf.Phdr, | ||
| 27 | dlpi_phnum: u16, | ||
| 28 | }; | ||
| 29 | |||
| 23 | pub const msghdr = extern struct { | 30 | pub const msghdr = extern struct { |
| 24 | /// optional address | 31 | /// optional address |
| 25 | msg_name: ?*sockaddr, | 32 | msg_name: ?*sockaddr, |
std/os/linux/test.zig-39| ... | @@ -44,42 +44,3 @@ test "timer" { | ... | @@ -44,42 +44,3 @@ test "timer" { |
| 44 | // TODO implicit cast from *[N]T to [*]T | 44 | // TODO implicit cast from *[N]T to [*]T |
| 45 | err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1); | 45 | err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1); |
| 46 | } | 46 | } |
| 47 | |||
| 48 | export fn iter_fn(info: *linux.dl_phdr_info, size: usize, data: ?*usize) i32 { | ||
| 49 | var counter = data.?; | ||
| 50 | // Count how many libraries are loaded | ||
| 51 | counter.* += usize(1); | ||
| 52 | |||
| 53 | // The image should contain at least a PT_LOAD segment | ||
| 54 | if (info.dlpi_phnum < 1) return -1; | ||
| 55 | |||
| 56 | // Quick & dirty validation of the phdr pointers, make sure we're not | ||
| 57 | // pointing to some random gibberish | ||
| 58 | var i: usize = 0; | ||
| 59 | var found_load = false; | ||
| 60 | while (i < info.dlpi_phnum) : (i += 1) { | ||
| 61 | const phdr = info.dlpi_phdr[i]; | ||
| 62 | |||
| 63 | if (phdr.p_type != elf.PT_LOAD) continue; | ||
| 64 | |||
| 65 | // Find the ELF header | ||
| 66 | const elf_header = @intToPtr(*elf.Ehdr, phdr.p_vaddr - phdr.p_offset); | ||
| 67 | // Validate the magic | ||
| 68 | if (!mem.eql(u8, elf_header.e_ident[0..], "\x7fELF")) return -1; | ||
| 69 | // Consistency check | ||
| 70 | if (elf_header.e_phnum != info.dlpi_phnum) return -1; | ||
| 71 | |||
| 72 | found_load = true; | ||
| 73 | break; | ||
| 74 | } | ||
| 75 | |||
| 76 | if (!found_load) return -1; | ||
| 77 | |||
| 78 | return 42; | ||
| 79 | } | ||
| 80 | |||
| 81 | test "dl_iterate_phdr" { | ||
| 82 | var counter: usize = 0; | ||
| 83 | expect(linux.dl_iterate_phdr(usize, iter_fn, &counter) != 0); | ||
| 84 | expect(counter != 0); | ||
| 85 | } |
std/os/test.zig+50| ... | @@ -5,6 +5,7 @@ const expect = std.testing.expect; | ... | @@ -5,6 +5,7 @@ const expect = std.testing.expect; |
| 5 | const io = std.io; | 5 | const io = std.io; |
| 6 | const fs = std.fs; | 6 | const fs = std.fs; |
| 7 | const mem = std.mem; | 7 | const mem = std.mem; |
| 8 | const elf = std.elf; | ||
| 8 | const File = std.fs.File; | 9 | const File = std.fs.File; |
| 9 | const Thread = std.Thread; | 10 | const Thread = std.Thread; |
| 10 | 11 | ||
| ... | @@ -160,3 +161,52 @@ test "sigaltstack" { | ... | @@ -160,3 +161,52 @@ test "sigaltstack" { |
| 160 | st.ss_size = 1; | 161 | st.ss_size = 1; |
| 161 | testing.expectError(error.SizeTooSmall, os.sigaltstack(&st, null)); | 162 | testing.expectError(error.SizeTooSmall, os.sigaltstack(&st, null)); |
| 162 | } | 163 | } |
| 164 | |||
| 165 | // If the type is not available use void to avoid erroring out when `iter_fn` is | ||
| 166 | // analyzed | ||
| 167 | const dl_phdr_info = if (@hasDecl(os, "dl_phdr_info")) os.dl_phdr_info else c_void; | ||
| 168 | |||
| 169 | export fn iter_fn(info: *dl_phdr_info, size: usize, data: ?*usize) i32 { | ||
| 170 | if (builtin.os == .windows or builtin.os == .wasi or builtin.os == .macosx) | ||
| 171 | return 0; | ||
| 172 | |||
| 173 | var counter = data.?; | ||
| 174 | // Count how many libraries are loaded | ||
| 175 | counter.* += usize(1); | ||
| 176 | |||
| 177 | // The image should contain at least a PT_LOAD segment | ||
| 178 | if (info.dlpi_phnum < 1) return -1; | ||
| 179 | |||
| 180 | // Quick & dirty validation of the phdr pointers, make sure we're not | ||
| 181 | // pointing to some random gibberish | ||
| 182 | var i: usize = 0; | ||
| 183 | var found_load = false; | ||
| 184 | while (i < info.dlpi_phnum) : (i += 1) { | ||
| 185 | const phdr = info.dlpi_phdr[i]; | ||
| 186 | |||
| 187 | if (phdr.p_type != elf.PT_LOAD) continue; | ||
| 188 | |||
| 189 | // Find the ELF header | ||
| 190 | const elf_header = @intToPtr(*elf.Ehdr, phdr.p_vaddr - phdr.p_offset); | ||
| 191 | // Validate the magic | ||
| 192 | if (!mem.eql(u8, elf_header.e_ident[0..4], "\x7fELF")) return -1; | ||
| 193 | // Consistency check | ||
| 194 | if (elf_header.e_phnum != info.dlpi_phnum) return -1; | ||
| 195 | |||
| 196 | found_load = true; | ||
| 197 | break; | ||
| 198 | } | ||
| 199 | |||
| 200 | if (!found_load) return -1; | ||
| 201 | |||
| 202 | return 42; | ||
| 203 | } | ||
| 204 | |||
| 205 | test "dl_iterate_phdr" { | ||
| 206 | if (builtin.os == .windows or builtin.os == .wasi or builtin.os == .macosx) | ||
| 207 | return error.SkipZigTest; | ||
| 208 | |||
| 209 | var counter: usize = 0; | ||
| 210 | expect(os.dl_iterate_phdr(usize, iter_fn, &counter) != 0); | ||
| 211 | expect(counter != 0); | ||
| 212 | } |