authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-04 12:30:38-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-06-04 12:30:38-04:00
loga608ebaa500af2f45ee3b826127b81822c92d028
treea42da35c21eb5665e2401282bde1bf8c1e98b0e1
parent8e109aec6b9e508e46f3d016065ad4ada0a2fd36
parent46cbed621b287d339a97e77e8e1bfd5090bd247c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #2581 from LemonBoy/misc-stuff

Miscellaneous stdlib changes

5 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");
19const assert = std.debug.assert;19const assert = std.debug.assert;
20const math = std.math;20const math = std.math;
21const mem = std.mem;21const mem = std.mem;
22const elf = std.elf;
23const dl = @import("dynamic_library.zig");
22const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES;24const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES;
2325
24comptime {26comptime {
...@@ -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}
23702371
2372pub 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
2371pub const ClockGetTimeError = error{2436pub 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};
2222
23pub 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
23pub const msghdr = extern struct {30pub const msghdr = extern struct {
24 /// optional address31 /// 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};
2222
23pub 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
23pub const msghdr = extern struct {30pub const msghdr = extern struct {
24 /// optional address31 /// 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 [*]T44 // 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
48export 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
81test "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;
5const io = std.io;5const io = std.io;
6const fs = std.fs;6const fs = std.fs;
7const mem = std.mem;7const mem = std.mem;
8const elf = std.elf;
8const File = std.fs.File;9const File = std.fs.File;
9const Thread = std.Thread;10const Thread = std.Thread;
1011
...@@ -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
167const dl_phdr_info = if (@hasDecl(os, "dl_phdr_info")) os.dl_phdr_info else c_void;
168
169export 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
205test "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}