From 09642c92db4f2eb03a200a00cbe0dfc682246509 Mon Sep 17 00:00:00 2001 From: Mackenzie Clark Date: Thu, 28 Mar 2019 11:55:01 -0700 Subject: [PATCH] revert changes to emscripten --- Cargo.lock | 9 - Cargo.toml | 2 +- Makefile | 2 - lib/emscripten/Cargo.toml | 12 +- lib/emscripten/src/env/unix/mod.rs | 31 +- lib/emscripten/src/env/windows/mod.rs | 5 - lib/emscripten/src/lib.rs | 33 +- lib/emscripten/src/syscalls/emscripten_vfs.rs | 151 ---- lib/emscripten/src/syscalls/mod.rs | 159 +++- .../src/syscalls/{unix/host_fs.rs => unix.rs} | 721 ++++++++++++------ lib/emscripten/src/syscalls/unix/mod.rs | 324 -------- lib/emscripten/src/syscalls/unix/select.rs | 95 --- lib/emscripten/src/syscalls/unix/vfs.rs | 677 ---------------- lib/emscripten/src/syscalls/windows.rs | 117 +-- lib/emscripten/src/utils.rs | 24 +- lib/emscripten/tests/emtests/_common.rs | 25 +- lib/emscripten/tests/emtests/mod.rs | 2 - 17 files changed, 653 insertions(+), 1736 deletions(-) delete mode 100644 lib/emscripten/src/syscalls/emscripten_vfs.rs rename lib/emscripten/src/syscalls/{unix/host_fs.rs => unix.rs} (51%) delete mode 100644 lib/emscripten/src/syscalls/unix/mod.rs delete mode 100644 lib/emscripten/src/syscalls/unix/select.rs delete mode 100644 lib/emscripten/src/syscalls/unix/vfs.rs diff --git a/Cargo.lock b/Cargo.lock index 86d38e4d8..732daab18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,11 +121,6 @@ dependencies = [ "which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bit_field" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "bitflags" version = "1.0.4" @@ -2251,9 +2246,7 @@ dependencies = [ name = "wasmer-emscripten" version = "0.2.1" dependencies = [ - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2263,7 +2256,6 @@ dependencies = [ "wasmer-clif-backend 0.2.0", "wasmer-dynasm-backend 0.1.0", "wasmer-llvm-backend 0.1.0", - "wasmer-runtime-abi 0.2.1", "wasmer-runtime-core 0.2.1", ] @@ -2526,7 +2518,6 @@ dependencies = [ "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bindgen 0.46.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7f7f0701772b17de73e4f5cbcb1dd6926f4706cba4c1ab62c5367f8bdc94e1" -"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum blake2b_simd 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce2571a6cd634670daa2977cc894c1cc2ba57c563c498e5a82c35446f34d056e" "checksum blob 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19803aa44ff8b43123bbe369efaddcb638ea7dc332e543972dd95ac7cb148b92" diff --git a/Cargo.toml b/Cargo.toml index 2a3b41171..776d61a5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,4 +45,4 @@ debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"] fast-tests = [] llvm = ["wasmer-llvm-backend"] dynasm = ["wasmer-dynasm-backend"] -vfs = ["wasmer-runtime-abi", "wasmer-emscripten/vfs"] +vfs = ["wasmer-runtime-abi"] diff --git a/Makefile b/Makefile index 3d95a57ce..19ce942d1 100644 --- a/Makefile +++ b/Makefile @@ -47,8 +47,6 @@ test-nightly: test-emscripten: cargo test --manifest-path lib/emscripten/Cargo.toml --features clif -- --test-threads=1 $(runargs) cargo test --manifest-path lib/emscripten/Cargo.toml --features llvm -- --test-threads=1 $(runargs) - cargo test --manifest-path lib/emscripten/Cargo.toml _vfs --features clif,vfs -- --test-threads=1 $(runargs) - cargo test --manifest-path lib/emscripten/Cargo.toml _vfs --features llvm,vfs -- --test-threads=1 $(runargs) test-emscripten-nightly: cargo test --manifest-path lib/emscripten/Cargo.toml --features dynasm -- --test-threads=1 $(runargs) diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index b2ebe9a31..2823b1c4f 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -9,20 +9,15 @@ edition = "2018" build = "build/mod.rs" [dependencies] -bit_field = "0.9.0" -byteorder = "1" -errno = "0.2.4" +wasmer-runtime-core = { path = "../runtime-core", version = "0.2.1" } lazy_static = "1.2.0" libc = "0.2.49" +byteorder = "1" time = "0.1.41" -wasmer-runtime-core = { path = "../runtime-core", version = "0.2.1" } wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" } wasmer-dynasm-backend = { path = "../dynasm-backend", version = "0.1.0", optional = true } wasmer-llvm-backend = { path = "../llvm-backend", version = "0.1.0", optional = true } -[target.'cfg(unix)'.dependencies] -wasmer-runtime-abi = { path = "../runtime-abi", optional = true } - [target.'cfg(windows)'.dependencies] rand = "0.6" @@ -35,5 +30,4 @@ glob = "0.2.11" [features] clif = [] llvm = ["wasmer-llvm-backend"] -dynasm = ["wasmer-dynasm-backend"] -vfs = ["wasmer-runtime-abi"] +dynasm = ["wasmer-dynasm-backend"] \ No newline at end of file diff --git a/lib/emscripten/src/env/unix/mod.rs b/lib/emscripten/src/env/unix/mod.rs index 999e5152b..7c846150f 100644 --- a/lib/emscripten/src/env/unix/mod.rs +++ b/lib/emscripten/src/env/unix/mod.rs @@ -1,11 +1,14 @@ /// NOTE: These syscalls only support wasm_32 for now because they take u32 offset -use libc::{c_int, getenv, getpwnam as libc_getpwnam, putenv, setenv, sysconf, unsetenv}; +use libc::{ + c_int, getenv, getgrnam as libc_getgrnam, getpwnam as libc_getpwnam, putenv, setenv, sysconf, + unsetenv, +}; use std::ffi::CStr; use std::mem; use std::os::raw::c_char; use crate::env::call_malloc; -use crate::utils::copy_cstr_into_wasm; +use crate::utils::{copy_cstr_into_wasm, copy_terminated_array_of_cstrs}; use wasmer_runtime_core::vm::Ctx; // #[no_mangle] @@ -118,7 +121,7 @@ pub fn _getgrnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int { }; unsafe { - let group = &*libc::getgrnam(name.as_ptr()); + let group = &*libc_getgrnam(name.as_ptr()); let group_struct_offset = call_malloc(ctx, mem::size_of::() as _); let group_struct_ptr = @@ -137,25 +140,3 @@ pub fn _sysconf(_ctx: &mut Ctx, name: c_int) -> i32 { // TODO: Implement like emscripten expects regarding memory/page size unsafe { sysconf(name) as i32 } // TODO review i64 } - -/// initgroups -pub fn _initgroups(_ctx: &mut Ctx, _user_offset: u32, _gid: u32) -> c_int { - 0 -} - -unsafe fn copy_terminated_array_of_cstrs(_ctx: &mut Ctx, cstrs: *mut *mut c_char) -> u32 { - let _total_num = { - let mut ptr = cstrs; - let mut counter = 0; - while !(*ptr).is_null() { - counter += 1; - ptr = ptr.add(1); - } - counter - }; - debug!( - "emscripten::copy_terminated_array_of_cstrs::total_num: {}", - _total_num - ); - 0 -} diff --git a/lib/emscripten/src/env/windows/mod.rs b/lib/emscripten/src/env/windows/mod.rs index 54e37f8bf..f738eccbb 100644 --- a/lib/emscripten/src/env/windows/mod.rs +++ b/lib/emscripten/src/env/windows/mod.rs @@ -131,8 +131,3 @@ pub fn _sysconf(_ctx: &mut Ctx, name: c_int) -> c_long { // stub because sysconf is not valid on windows 0 } - -/// initgroups -pub fn _initgroups(_ctx: &mut Ctx, _user_offset: u32, _gid: u32) -> c_int { - 0 -} diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index f0ca666b2..4d41cc40d 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -54,12 +54,6 @@ pub use self::utils::{ get_emscripten_table_size, is_emscripten_module, }; -#[cfg(all(feature = "vfs", not(target_os = "windows")))] -use crate::syscalls::EmscriptenVfs; - -#[cfg(all(feature = "vfs", not(target_os = "windows")))] -use wasmer_runtime_abi::vfs::vfs::Vfs; - // TODO: Magic number - how is this calculated? const TOTAL_STACK: u32 = 5_242_880; // TODO: make this variable @@ -128,9 +122,6 @@ pub struct EmscriptenData<'a> { pub dyn_call_vijiii: Option>, pub dyn_call_vijj: Option>, pub dyn_call_viidii: Option>, - - #[cfg(all(feature = "vfs", not(target_os = "windows")))] - pub vfs: Option, } impl<'a> EmscriptenData<'a> { @@ -235,38 +226,17 @@ impl<'a> EmscriptenData<'a> { dyn_call_vijiii, dyn_call_vijj, dyn_call_viidii, - #[cfg(all(feature = "vfs", not(target_os = "windows")))] - vfs: None, } } } pub fn run_emscripten_instance( - module: &Module, + _module: &Module, instance: &mut Instance, path: &str, args: Vec<&str>, ) -> CallResult<()> { let mut data = EmscriptenData::new(instance); - - // Construct a new virtual filesystem and inject it into the emscripten data - // This is behind a feature flag for now, but will be default in the future - #[cfg(any(not(feature = "vfs"), target_os = "windows"))] - let _ = module; - #[cfg(all(feature = "vfs", not(target_os = "windows")))] - { - data.vfs = match module.info().custom_sections.get("wasmer:fs") { - Some(bytes) => match Vfs::from_compressed_bytes(&bytes[..]) { - Ok(vfs) => { - let emscripten_vfs = EmscriptenVfs::new(vfs); - Some(emscripten_vfs) - } - Err(_) => None, - }, - None => None, - }; - } - let data_ptr = &mut data as *mut _ as *mut c_void; instance.context_mut().data = data_ptr; @@ -506,7 +476,6 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject "_getpagesize" => func!(crate::env::_getpagesize), "_sysconf" => func!(crate::env::_sysconf), "_getaddrinfo" => func!(crate::env::_getaddrinfo), - "_initgroups" => func!(crate::env::_initgroups), // Syscalls "___syscall1" => func!(crate::syscalls::___syscall1), diff --git a/lib/emscripten/src/syscalls/emscripten_vfs.rs b/lib/emscripten/src/syscalls/emscripten_vfs.rs deleted file mode 100644 index 927b07c34..000000000 --- a/lib/emscripten/src/syscalls/emscripten_vfs.rs +++ /dev/null @@ -1,151 +0,0 @@ -use std::cell::RefCell; -use std::collections::BTreeMap; -use std::io; -use std::path::Path; -use std::rc::Rc; -use wasmer_runtime_abi::vfs::device_file; -use wasmer_runtime_abi::vfs::file_like::{FileLike, Metadata}; -use wasmer_runtime_abi::vfs::vfs::Vfs; - -pub type Fd = i32; - -pub enum FileHandle { - Socket(Fd), - Vf(Rc>), -} - -pub struct EmscriptenVfs { - pub fd_map: BTreeMap, - pub vfs: Vfs, -} - -impl EmscriptenVfs { - pub fn new(mut vfs: Vfs) -> Self { - let mut fd_map = BTreeMap::new(); - - let stdin = Rc::new(RefCell::new(device_file::Stdin)); - vfs.create_device_file("/dev/stdin", stdin.clone()); - fd_map.insert(0, FileHandle::Vf(stdin)); - - let stdout = Rc::new(RefCell::new(device_file::Stdout)); - vfs.create_device_file("/dev/stdout", stdout.clone()); - fd_map.insert(1, FileHandle::Vf(stdout)); - - let stderr = Rc::new(RefCell::new(device_file::Stderr)); - vfs.create_device_file("/dev/stderr", stderr.clone()); - fd_map.insert(2, FileHandle::Vf(stderr)); - - EmscriptenVfs { fd_map, vfs } - } - - pub fn make_dir>(&mut self, path: P) -> () { - self.vfs.make_dir(path); - } - - pub fn path_metadata>(&mut self, path: P) -> Option { - if let Some(file) = self.vfs.open_file(path) { - RefCell::borrow(&file).metadata().ok() - } else { - None - } - } - - pub fn close_file_descriptor(&mut self, fd: i32) -> i32 { - match self.fd_map.remove(&fd) { - Some(FileHandle::Vf(_)) => 0, - Some(FileHandle::Socket(fd)) => unsafe { libc::close(fd) }, - _ => -1, - } - } - - pub fn next_lowest_fd_raw(&self) -> i32 { - let fd_map = &self.fd_map; - let mut next_lowest_fd = 0; - for (vfd, _) in fd_map.iter() { - let host_fd = *vfd; - if host_fd == next_lowest_fd { - next_lowest_fd += 1; - } else if host_fd < next_lowest_fd { - panic!("Should not be here."); - } else { - break; - } - } - next_lowest_fd - } - - pub fn get_host_socket_fd(&self, fd: i32) -> Option { - match self.fd_map.get(&fd) { - Some(FileHandle::Socket(fd)) => Some(*fd), - _ => None, - } - } - - pub fn open_file>(&mut self, path: P) -> i32 { - match self.vfs.open_file(path) { - Some(file) => { - let fd = self.next_lowest_fd_raw(); - let handle = FileHandle::Vf(file); - self.fd_map.insert(fd, handle); - fd - } - None => -1, - } - } - - pub fn write_file( - &mut self, - fd: i32, - buf_slice: &mut [u8], - count: usize, - ) -> Result { - match self.fd_map.get(&fd) { - Some(FileHandle::Vf(file)) => { - let mut mut_ref = RefCell::borrow_mut(file); - mut_ref - .write_file(buf_slice, 0) - .map_err(|e| EmscriptenVfsError::Io(e)) - } - Some(FileHandle::Socket(host_fd)) => unsafe { - let result = libc::write(*host_fd, buf_slice.as_ptr() as _, count as _); - if result == -1 { - Err(EmscriptenVfsError::Errno(errno::errno())) - } else { - Ok(result as usize) - } - }, - _ => Err(EmscriptenVfsError::FileSystemError), - } - } - - pub fn read_file(&self, fd: i32, buf_slice: &mut [u8]) -> usize { - match self.fd_map.get(&fd) { - Some(FileHandle::Vf(file)) => { - let count = { - let mut result = RefCell::borrow_mut(&file); - let result = result.read_file(buf_slice, 0); - result.unwrap() - }; - count as _ - } - Some(FileHandle::Socket(host_fd)) => unsafe { - let buf_addr = buf_slice.as_ptr() as _; - libc::write(*host_fd, buf_addr, buf_slice.len()) as usize - }, - _ => 0, - } - } - - pub fn new_socket_fd(&mut self, host_fd: Fd) -> Fd { - let fd = self.next_lowest_fd_raw(); - self.fd_map.insert(fd, FileHandle::Socket(host_fd)); - fd - } -} - -#[derive(Debug)] -pub enum EmscriptenVfsError { - Io(io::Error), - Errno(errno::Errno), - FileSystemError, -} diff --git a/lib/emscripten/src/syscalls/mod.rs b/lib/emscripten/src/syscalls/mod.rs index b01f7195c..36a1b0c7c 100644 --- a/lib/emscripten/src/syscalls/mod.rs +++ b/lib/emscripten/src/syscalls/mod.rs @@ -4,26 +4,44 @@ mod unix; #[cfg(windows)] mod windows; -#[cfg(all(feature = "vfs", not(target_os = "windows")))] -mod emscripten_vfs; - #[cfg(unix)] pub use self::unix::*; #[cfg(windows)] pub use self::windows::*; -#[cfg(all(feature = "vfs", not(target_os = "windows")))] -pub use self::emscripten_vfs::*; - +use super::utils::copy_stat_into_wasm; use super::varargs::VarArgs; use byteorder::{ByteOrder, LittleEndian}; /// NOTE: TODO: These syscalls only support wasm_32 for now because they assume offsets are u32 /// Syscall list: https://www.cs.utexas.edu/~bismith/test/syscalls/syscalls32.html -use libc::{c_int, c_void, chdir, exit, getpid, lseek, rmdir}; +use libc::{ + // ENOTTY, + c_int, + c_void, + chdir, + // fcntl, setsockopt, getppid + close, + dup2, + exit, + fstat, + getpid, + // iovec, + lseek, + off_t, + // open, + read, + // readv, + rmdir, + // writev, + stat, + write, + // sockaddr_in, +}; use wasmer_runtime_core::vm::Ctx; use super::env; +use std::cell::Cell; #[allow(unused_imports)] use std::io::Error; use std::mem; @@ -38,6 +56,39 @@ pub fn ___syscall1(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) { } } +/// read +pub fn ___syscall3(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { + // -> ssize_t + debug!("emscripten::___syscall3 (read) {}", _which); + let fd: i32 = varargs.get(ctx); + let buf: u32 = varargs.get(ctx); + let count: i32 = varargs.get(ctx); + debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count); + let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_void; + let ret = unsafe { read(fd, buf_addr, count as _) }; + debug!("=> ret: {}", ret); + ret as _ +} + +/// write +pub fn ___syscall4(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall4 (write) {}", _which); + let fd: i32 = varargs.get(ctx); + let buf: u32 = varargs.get(ctx); + let count: i32 = varargs.get(ctx); + debug!("=> fd: {}, buf: {}, count: {}", fd, buf, count); + let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *const c_void; + unsafe { write(fd, buf_addr, count as _) as i32 } +} + +/// close +pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall6 (close) {}", _which); + let fd: i32 = varargs.get(ctx); + debug!("fd: {}", fd); + unsafe { close(fd) } +} + // chdir pub fn ___syscall12(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall12 (chdir) {}", _which); @@ -56,6 +107,11 @@ pub fn ___syscall10(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { -1 } +pub fn ___syscall15(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { + debug!("emscripten::___syscall15"); + -1 +} + // getpid pub fn ___syscall20(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall20 (getpid)"); @@ -75,16 +131,51 @@ pub fn ___syscall40(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int unsafe { rmdir(pathname_addr) } } +// pipe +pub fn ___syscall42(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall42 (pipe)"); + // offset to a file descriptor, which contains a read end and write end, 2 integers + let fd_offset: u32 = varargs.get(ctx); + + let emscripten_memory = ctx.memory(0); + + // convert the file descriptor into a vec with two slots + let mut fd_vec: Vec = emscripten_memory.view()[((fd_offset / 4) as usize)..] + .iter() + .map(|pipe_end: &Cell| pipe_end.get()) + .take(2) + .collect(); + + // get it as a mutable pointer + let fd_ptr = fd_vec.as_mut_ptr(); + + // call pipe and store the pointers in this array + #[cfg(target_os = "windows")] + let result: c_int = unsafe { libc::pipe(fd_ptr, 2048, 0) }; + #[cfg(not(target_os = "windows"))] + let result: c_int = unsafe { libc::pipe(fd_ptr) }; + result +} + pub fn ___syscall60(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall60"); -1 } +// dup2 +pub fn ___syscall63(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall63 (dup2) {}", _which); + + let src: i32 = varargs.get(ctx); + let dst: i32 = varargs.get(ctx); + + unsafe { dup2(src, dst) } +} + // getppid pub fn ___syscall64(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall64 (getppid)"); - let result = unsafe { getpid() }; - result + unsafe { getpid() } } pub fn ___syscall66(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { @@ -173,7 +264,7 @@ pub fn ___syscall140(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { let offset_low: i32 = varargs.get(ctx); let result_ptr_value = varargs.get::(ctx); let whence: i32 = varargs.get(ctx); - let offset = offset_low as libc::off_t; + let offset = offset_low as off_t; let ret = unsafe { lseek(fd, offset, whence) as i32 }; #[allow(clippy::cast_ptr_alignment)] let result_ptr = emscripten_memory_pointer!(ctx.memory(0), result_ptr_value) as *mut i32; @@ -219,7 +310,43 @@ pub fn ___syscall145(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 as *mut c_void; let iov_len = (*guest_iov_addr).iov_len as _; // debug!("=> iov_addr: {:?}, {:?}", iov_base, iov_len); - let curr = libc::read(fd, iov_base, iov_len); + let curr = read(fd, iov_base, iov_len); + if curr < 0 { + return -1; + } + ret += curr; + } + // debug!(" => ret: {}", ret); + ret as _ + } +} + +// writev +#[allow(clippy::cast_ptr_alignment)] +pub fn ___syscall146(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { + // -> ssize_t + debug!("emscripten::___syscall146 (writev) {}", _which); + let fd: i32 = varargs.get(ctx); + let iov: i32 = varargs.get(ctx); + let iovcnt: i32 = varargs.get(ctx); + + #[repr(C)] + struct GuestIovec { + iov_base: i32, + iov_len: i32, + } + + debug!("=> fd: {}, iov: {}, iovcnt = {}", fd, iov, iovcnt); + let mut ret = 0; + unsafe { + for i in 0..iovcnt { + let guest_iov_addr = + emscripten_memory_pointer!(ctx.memory(0), (iov + i * 8)) as *mut GuestIovec; + let iov_base = emscripten_memory_pointer!(ctx.memory(0), (*guest_iov_addr).iov_base) + as *const c_void; + let iov_len = (*guest_iov_addr).iov_len as _; + // debug!("=> iov_addr: {:?}, {:?}", iov_base, iov_len); + let curr = write(fd, iov_base, iov_len); if curr < 0 { return -1; } @@ -254,8 +381,8 @@ pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; unsafe { - let mut _stat: libc::stat = std::mem::zeroed(); - let ret = libc::stat(pathname_addr, &mut _stat); + let mut _stat: stat = std::mem::zeroed(); + let ret = stat(pathname_addr, &mut _stat); debug!( "=> pathname: {}, buf: {}, path: {} = {}\nlast os error: {}", pathname, @@ -267,7 +394,7 @@ pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in if ret != 0 { return ret; } - crate::utils::copy_stat_into_wasm(ctx, buf, &_stat); + copy_stat_into_wasm(ctx, buf, &_stat); } 0 } @@ -280,12 +407,12 @@ pub fn ___syscall197(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in unsafe { let mut stat = std::mem::zeroed(); - let ret = libc::fstat(fd, &mut stat); + let ret = fstat(fd, &mut stat); debug!("ret: {}", ret); if ret != 0 { return ret; } - crate::utils::copy_stat_into_wasm(ctx, buf, &stat); + copy_stat_into_wasm(ctx, buf, &stat); } 0 diff --git a/lib/emscripten/src/syscalls/unix/host_fs.rs b/lib/emscripten/src/syscalls/unix.rs similarity index 51% rename from lib/emscripten/src/syscalls/unix/host_fs.rs rename to lib/emscripten/src/syscalls/unix.rs index ce1894449..c8fa04101 100644 --- a/lib/emscripten/src/syscalls/unix/host_fs.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -1,32 +1,102 @@ -use crate::utils::copy_stat_into_wasm; use crate::varargs::VarArgs; -use libc::{c_int, c_void, ioctl, sockaddr, socklen_t}; +/// NOTE: TODO: These syscalls only support wasm_32 for now because they assume offsets are u32 +/// Syscall list: https://www.cs.utexas.edu/~bismith/test/syscalls/syscalls32.html +use libc::{ + accept, + access, + bind, + c_char, + c_int, + c_void, + chown, + // fcntl, setsockopt, getppid + connect, + dup, + dup2, + fchmod, + fchown, + fcntl, + // ENOTTY, + fsync, + getgid, + getgroups, + getpeername, + getrusage, + getsockname, + getsockopt, + gid_t, + in_addr_t, + in_port_t, + ioctl, + lchown, + link, + // iovec, + listen, + mkdir, + mode_t, + msghdr, + nice, + off_t, + open, + pid_t, + pread, + pwrite, + // readv, + recvfrom, + recvmsg, + // ENOTTY, + rusage, + sa_family_t, + // writev, + select, + sendmsg, + sendto, + setpgid, + setsockopt, + size_t, + sockaddr, + socket, + socklen_t, + symlink, + uid_t, + uname, + utsname, + EINVAL, + // sockaddr_in, + FIOCLEX, + FIONBIO, + F_GETFD, + F_SETFD, + SOL_SOCKET, + SO_REUSEADDR, + TIOCGWINSZ, +}; use wasmer_runtime_core::vm::Ctx; -/// read -pub fn ___syscall3(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { - debug!("emscripten::___syscall3 (read) {}", _which); - let fd: i32 = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); - let count: i32 = varargs.get(ctx); - debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count); - let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_void; - let ret = unsafe { libc::read(fd, buf_addr, count as _) }; - debug!("=> ret: {}", ret); - ret as _ +#[allow(unused_imports)] +use std::io::Error; +use std::mem; + +// Linking to functions that are not provided by rust libc +#[cfg(target_os = "macos")] +#[link(name = "c")] +extern "C" { + pub fn wait4(pid: pid_t, status: *mut c_int, options: c_int, rusage: *mut rusage) -> pid_t; + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + pub fn fdatasync(fd: c_int) -> c_int; + pub fn lstat64(path: *const c_char, buf: *mut c_void) -> c_int; } -/// write -pub fn ___syscall4(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall4 (write) {}", _which); - let fd: i32 = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); - let count: i32 = varargs.get(ctx); - debug!("=> fd: {}, buf: {}, count: {}", fd, buf, count); - let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *const c_void; - let ret = unsafe { libc::write(fd, buf_addr, count as _) as i32 }; - ret -} +#[cfg(not(target_os = "macos"))] +use libc::{fallocate, fdatasync, ftruncate64, lstat64, madvise, wait4}; + +// Another conditional constant for name resolution: Macos et iOS use +// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket. +// Other platforms do otherwise. +#[cfg(target_os = "darwin")] +use libc::SO_NOSIGPIPE; +#[cfg(not(target_os = "darwin"))] +const SO_NOSIGPIPE: c_int = 0; /// open pub fn ___syscall5(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { @@ -36,61 +106,245 @@ pub fn ___syscall5(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int let mode: u32 = varargs.get(ctx); let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; let _path_str = unsafe { std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap() }; - let fd = unsafe { libc::open(pathname_addr, flags, mode) }; + let fd = unsafe { open(pathname_addr, flags, mode) }; debug!( - "=> pathname: {}, flags: {}, mode: {} = fd: {}\npath: {}", - pathname, flags, mode, fd, _path_str + "=> pathname: {}, flags: {}, mode: {} = fd: {}\npath: {}\nlast os error: {}", + pathname, + flags, + mode, + fd, + _path_str, + Error::last_os_error(), ); fd } -/// close -pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall6 (close) {}", _which); - let fd: i32 = varargs.get(ctx); - debug!("fd: {}", fd); - unsafe { libc::close(fd) } +/// link +pub fn ___syscall9(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall9 (link) {}", _which); + + let oldname: c_int = varargs.get(ctx); + let newname: c_int = varargs.get(ctx); + let oldname_ptr = emscripten_memory_pointer!(ctx.memory(0), oldname) as *const i8; + let newname_ptr = emscripten_memory_pointer!(ctx.memory(0), newname) as *const i8; + let result = unsafe { link(oldname_ptr, newname_ptr) }; + debug!( + "=> oldname: {}, newname: {}, result: {}", + unsafe { std::ffi::CStr::from_ptr(oldname_ptr).to_str().unwrap() }, + unsafe { std::ffi::CStr::from_ptr(newname_ptr).to_str().unwrap() }, + result, + ); + result } -/// chmod -pub fn ___syscall15(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { - debug!("emscripten::___syscall15"); - -1 +/// getrusage +pub fn ___syscall77(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall77 (getrusage) {}", _which); + + let resource: c_int = varargs.get(ctx); + let rusage_ptr: c_int = varargs.get(ctx); + #[allow(clippy::cast_ptr_alignment)] + let rusage = emscripten_memory_pointer!(ctx.memory(0), rusage_ptr) as *mut rusage; + assert_eq!(8, mem::align_of_val(&rusage)); + unsafe { getrusage(resource, rusage) } } -/// mkdir +/// symlink +pub fn ___syscall83(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall83 (symlink) {}", _which); + + let path1_ptr: c_int = varargs.get(ctx); + let path2_ptr: c_int = varargs.get(ctx); + let path1 = emscripten_memory_pointer!(ctx.memory(0), path1_ptr) as *mut i8; + let path2 = emscripten_memory_pointer!(ctx.memory(0), path2_ptr) as *mut i8; + let result = unsafe { symlink(path1, path2) }; + debug!( + "=> path1: {}, path2: {}, result: {}", + unsafe { std::ffi::CStr::from_ptr(path1).to_str().unwrap() }, + unsafe { std::ffi::CStr::from_ptr(path2).to_str().unwrap() }, + result, + ); + result +} + +/// ftruncate64 +pub fn ___syscall194(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall194 (ftruncate64) {}", _which); + let _fd: c_int = varargs.get(ctx); + let _length: i64 = varargs.get(ctx); + #[cfg(not(target_os = "macos"))] + unsafe { + ftruncate64(_fd, _length) + } + #[cfg(target_os = "macos")] + unimplemented!() +} + +/// lchown +pub fn ___syscall198(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall198 (lchown) {}", _which); + let path: c_int = varargs.get(ctx); + let uid: uid_t = varargs.get(ctx); + let gid: gid_t = varargs.get(ctx); + let path_ptr = emscripten_memory_pointer!(ctx.memory(0), path) as *const i8; + let result = unsafe { lchown(path_ptr, uid, gid) }; + debug!( + "=> path: {}, uid: {}, gid: {}, result: {}", + unsafe { std::ffi::CStr::from_ptr(path_ptr).to_str().unwrap() }, + uid, + gid, + result, + ); + result +} + +/// getgroups +pub fn ___syscall205(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall205 (getgroups) {}", _which); + let ngroups_max: c_int = varargs.get(ctx); + let groups: c_int = varargs.get(ctx); + + #[allow(clippy::cast_ptr_alignment)] + let gid_ptr = emscripten_memory_pointer!(ctx.memory(0), groups) as *mut gid_t; + assert_eq!(4, mem::align_of_val(&gid_ptr)); + let result = unsafe { getgroups(ngroups_max, gid_ptr) }; + debug!( + "=> ngroups_max: {}, gid_ptr: {:?}, result: {}", + ngroups_max, gid_ptr, result, + ); + result +} + +// chown +pub fn ___syscall212(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall212 (chown) {}", _which); + + let pathname: u32 = varargs.get(ctx); + let owner: u32 = varargs.get(ctx); + let group: u32 = varargs.get(ctx); + + let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; + + unsafe { chown(pathname_addr, owner, group) } +} + +/// madvise +pub fn ___syscall219(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall212 (chown) {}", _which); + + let addr_ptr: c_int = varargs.get(ctx); + let len: usize = varargs.get(ctx); + let advice: c_int = varargs.get(ctx); + + let addr = emscripten_memory_pointer!(ctx.memory(0), addr_ptr) as *mut c_void; + + unsafe { madvise(addr, len, advice) } +} + +/// access +pub fn ___syscall33(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall33 (access) {}", _which); + let path_ptr: c_int = varargs.get(ctx); + let amode: c_int = varargs.get(ctx); + let path = emscripten_memory_pointer!(ctx.memory(0), path_ptr) as *const i8; + let result = unsafe { access(path, amode) }; + debug!( + "=> path: {}, result: {}", + unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }, + result + ); + result +} + +/// nice +pub fn ___syscall34(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall34 (nice) {}", _which); + let inc_r: c_int = varargs.get(ctx); + unsafe { nice(inc_r) } +} + +// mkdir pub fn ___syscall39(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall39 (mkdir) {}", _which); let pathname: u32 = varargs.get(ctx); let mode: u32 = varargs.get(ctx); let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; - unsafe { libc::mkdir(pathname_addr, mode as _) } + unsafe { mkdir(pathname_addr, mode as _) } } -/// pipe -pub fn ___syscall42(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall42 (pipe)"); - // offset to a file descriptor, which contains a read end and write end, 2 integers - let fd_offset: u32 = varargs.get(ctx); +/// dup +pub fn ___syscall41(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall41 (dup) {}", _which); + let fd: c_int = varargs.get(ctx); + unsafe { dup(fd) } +} - let emscripten_memory = ctx.memory(0); +/// getgid +pub fn ___syscall200(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { + debug!("emscripten::___syscall200 (getgid)"); + unsafe { getgid() as i32 } +} - // convert the file descriptor into a vec with two slots - let mut fd_vec: Vec = emscripten_memory.view()[((fd_offset / 4) as usize)..] - .iter() - .map(|pipe_end: &std::cell::Cell| pipe_end.get()) - .take(2) - .collect(); +// getgid +pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { + debug!("emscripten::___syscall201 (getgid)"); + unsafe { + // Maybe fix: Emscripten returns 0 always + getgid() as i32 + } +} - // get it as a mutable pointer - let fd_ptr = fd_vec.as_mut_ptr(); +// getgid32 +pub fn ___syscall202(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { + // gid_t + debug!("emscripten::___syscall202 (getgid32)"); + unsafe { + // Maybe fix: Emscripten returns 0 always + getgid() as _ + } +} - // call pipe and store the pointers in this array - #[cfg(target_os = "windows")] - let result: c_int = unsafe { libc::pipe(fd_ptr, 2048, 0) }; - #[cfg(not(target_os = "windows"))] - let result: c_int = unsafe { libc::pipe(fd_ptr) }; - result +/// fchown +pub fn ___syscall207(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall207 (fchown) {}", _which); + let fd: c_int = varargs.get(ctx); + let owner: uid_t = varargs.get(ctx); + let group: gid_t = varargs.get(ctx); + unsafe { fchown(fd, owner, group) } +} + +/// dup3 +pub fn ___syscall330(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t { + // Implementation based on description at https://linux.die.net/man/2/dup3 + debug!("emscripten::___syscall330 (dup3)"); + let oldfd: c_int = varargs.get(ctx); + let newfd: c_int = varargs.get(ctx); + let flags: c_int = varargs.get(ctx); + + if oldfd == newfd { + return EINVAL; + } + + let res = unsafe { dup2(oldfd, newfd) }; + + // Set flags on newfd (https://www.gnu.org/software/libc/manual/html_node/Descriptor-Flags.html) + let mut old_flags = unsafe { fcntl(newfd, F_GETFD, 0) }; + + if old_flags > 0 { + old_flags |= flags; + } else if old_flags == 0 { + old_flags &= !flags; + } + + unsafe { + fcntl(newfd, F_SETFD, old_flags); + } + + debug!( + "=> oldfd: {}, newfd: {}, flags: {} = pid: {}", + oldfd, newfd, flags, res + ); + res } /// ioctl @@ -105,7 +359,7 @@ pub fn ___syscall54(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int // FIONBIO let argp: u32 = varargs.get(ctx); let argp_ptr = emscripten_memory_pointer!(ctx.memory(0), argp) as *mut c_void; - let ret = unsafe { ioctl(fd, libc::FIONBIO, argp_ptr) }; + let ret = unsafe { ioctl(fd, FIONBIO, argp_ptr) }; debug!("ret(FIONBIO): {}", ret); ret // 0 @@ -114,7 +368,7 @@ pub fn ___syscall54(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int // TIOCGWINSZ let argp: u32 = varargs.get(ctx); let argp_ptr = emscripten_memory_pointer!(ctx.memory(0), argp) as *mut c_void; - let ret = unsafe { ioctl(fd, libc::TIOCGWINSZ, argp_ptr) }; + let ret = unsafe { ioctl(fd, TIOCGWINSZ, argp_ptr) }; debug!("ret(TIOCGWINSZ): {} (harcoded to 0)", ret); // ret // TODO: We hardcode the value to have emscripten tests pass, as for some reason @@ -135,16 +389,6 @@ pub fn ___syscall54(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int } } -/// dup2 -pub fn ___syscall63(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall63 (dup2) {}", _which); - - let src: i32 = varargs.get(ctx); - let dst: i32 = varargs.get(ctx); - - unsafe { libc::dup2(src, dst) } -} - // socketcall #[allow(clippy::cast_ptr_alignment)] pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { @@ -154,55 +398,49 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in #[repr(C)] pub struct GuestSockaddrIn { - pub sin_family: libc::sa_family_t, - // u16 - pub sin_port: libc::in_port_t, - // u16 - pub sin_addr: GuestInAddr, - // u32 - pub sin_zero: [u8; 8], // u8 * 8 - // 2 + 2 + 4 + 8 = 16 + pub sin_family: sa_family_t, // u16 + pub sin_port: in_port_t, // u16 + pub sin_addr: GuestInAddr, // u32 + pub sin_zero: [u8; 8], // u8 * 8 + // 2 + 2 + 4 + 8 = 16 } #[repr(C)] pub struct GuestInAddr { - pub s_addr: libc::in_addr_t, // u32 + pub s_addr: in_addr_t, // u32 } // debug!("GuestSockaddrIn = {}", size_of::()); pub struct LinuxSockAddr { pub sa_family: u16, - pub sa_data: [libc::c_char; 14], + pub sa_data: [c_char; 14], } match call { 1 => { debug!("socket: socket"); - // Another conditional constant for name resolution: Macos et iOS use - // SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket. - // Other platforms do otherwise. - #[cfg(target_os = "darwin")] - use libc::SO_NOSIGPIPE; - #[cfg(not(target_os = "darwin"))] - const SO_NOSIGPIPE: c_int = 0; - // socket (domain: c_int, ty: c_int, protocol: c_int) -> c_int let domain: i32 = socket_varargs.get(ctx); let ty: i32 = socket_varargs.get(ctx); let protocol: i32 = socket_varargs.get(ctx); - let fd = unsafe { libc::socket(domain, ty, protocol) }; + let fd = unsafe { socket(domain, ty, protocol) }; // set_cloexec unsafe { - ioctl(fd, libc::FIOCLEX); + ioctl(fd, FIOCLEX); }; - let _err = errno::errno(); - - let _result = - unsafe { libc::setsockopt(fd, libc::SOL_SOCKET, SO_NOSIGPIPE, 0 as *const _, 4) }; - - let _err2 = errno::errno(); + type T = u32; + let payload = 1 as *const T as _; + unsafe { + setsockopt( + fd, + SOL_SOCKET, + SO_NOSIGPIPE, + payload, + mem::size_of::() as socklen_t, + ); + }; debug!( "=> domain: {} (AF_INET/2), type: {} (SOCK_STREAM/1), protocol: {} = fd: {}", @@ -222,10 +460,11 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in // Debug received address let _proper_address = address as *const GuestSockaddrIn; debug!( - "=> address.sin_family: {:?}, address.sin_port: {:?}, address.sin_addr.s_addr: {:?}", + "=> address.sin_family: {:?}, address.sin_port: {:?}, address.sin_addr.s_addr: {:?}", unsafe { (*_proper_address).sin_family }, unsafe { (*_proper_address).sin_port }, unsafe { (*_proper_address).sin_addr.s_addr } - ); - let status = unsafe { libc::bind(socket, address, address_len) }; + ); + + let status = unsafe { bind(socket, address, address_len) }; // debug!("=> status: {}", status); debug!( "=> socketfd: {}, address: {:?}, address_len: {} = status: {}", @@ -242,14 +481,14 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let address: u32 = socket_varargs.get(ctx); let address_len = socket_varargs.get(ctx); let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr; - unsafe { libc::connect(socket, address, address_len) } + unsafe { connect(socket, address, address_len) } } 4 => { debug!("socket: listen"); // listen (socket: c_int, backlog: c_int) -> c_int let socket = socket_varargs.get(ctx); let backlog: i32 = socket_varargs.get(ctx); - let status = unsafe { libc::listen(socket, backlog) }; + let status = unsafe { listen(socket, backlog) }; debug!( "=> socketfd: {}, backlog: {} = status: {}", socket, backlog, status @@ -272,20 +511,18 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in emscripten_memory_pointer!(ctx.memory(0), address_len) as *mut socklen_t; // let mut address_len_addr: socklen_t = 0; - let fd = unsafe { libc::accept(socket, address, address_len_addr) }; + let fd = unsafe { accept(socket, address, address_len_addr) }; unsafe { let address_linux = emscripten_memory_pointer!(ctx.memory(0), address_addr) as *mut LinuxSockAddr; (*address_linux).sa_family = (*address).sa_family as u16; (*address_linux).sa_data = (*address).sa_data; - let _proper_address = address as *const GuestSockaddrIn; - let _x = 10; }; // set_cloexec unsafe { - ioctl(fd, libc::FIOCLEX); + ioctl(fd, FIOCLEX); }; debug!("fd: {}", fd); @@ -301,7 +538,7 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr; let address_len_addr = emscripten_memory_pointer!(ctx.memory(0), address_len) as *mut socklen_t; - unsafe { libc::getsockname(socket, address, address_len_addr) } + unsafe { getsockname(socket, address, address_len_addr) } } 7 => { debug!("socket: getpeername"); @@ -312,7 +549,7 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr; let address_len_addr = emscripten_memory_pointer!(ctx.memory(0), address_len) as *mut socklen_t; - unsafe { libc::getpeername(socket, address, address_len_addr) } + unsafe { getpeername(socket, address, address_len_addr) } } 11 => { debug!("socket: sendto"); @@ -325,12 +562,12 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let address_len = socket_varargs.get(ctx); let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as _; let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr; - unsafe { libc::sendto(socket, buf_addr, flags, len, address, address_len) as i32 } + unsafe { sendto(socket, buf_addr, flags, len, address, address_len) as i32 } } 12 => { debug!("socket: recvfrom"); // recvfrom (socket: c_int, buf: *const c_void, len: size_t, flags: c_int, addr: *const sockaddr, addrlen: socklen_t) -> ssize_t - let socket: i32 = socket_varargs.get(ctx); + let socket = socket_varargs.get(ctx); let buf: u32 = socket_varargs.get(ctx); let flags = socket_varargs.get(ctx); let len: i32 = socket_varargs.get(ctx); @@ -340,14 +577,7 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr; let address_len_addr = emscripten_memory_pointer!(ctx.memory(0), address_len) as *mut socklen_t; - let recv_result = unsafe { - libc::recvfrom(socket, buf_addr, flags, len, address, address_len_addr) as i32 - }; - debug!( - "recvfrom: socket: {}, flags: {}, len: {}, result: {}", - socket, flags, len, recv_result - ); - recv_result + unsafe { recvfrom(socket, buf_addr, flags, len, address, address_len_addr) as i32 } } 14 => { debug!("socket: setsockopt"); @@ -359,15 +589,15 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let socket = socket_varargs.get(ctx); // SOL_SOCKET = 0xffff (BSD, Linux) - let level: i32 = libc::SOL_SOCKET; + let level: i32 = SOL_SOCKET; let _: u32 = socket_varargs.get(ctx); // SO_REUSEADDR = 0x4 (BSD, Linux) - let name: i32 = libc::SO_REUSEADDR; + let name: i32 = SO_REUSEADDR; let _: u32 = socket_varargs.get(ctx); let value: u32 = socket_varargs.get(ctx); let option_len = socket_varargs.get(ctx); let value_addr = emscripten_memory_pointer!(ctx.memory(0), value) as _; // Endian problem - let ret = unsafe { libc::setsockopt(socket, level, name, value_addr, option_len) }; + let ret = unsafe { setsockopt(socket, level, name, value_addr, option_len) }; debug!("=> socketfd: {}, level: {} (SOL_SOCKET/0xffff), name: {} (SO_REUSEADDR/4), value_addr: {:?}, option_len: {} = status: {}", socket, level, name, value_addr, option_len, ret); ret @@ -383,9 +613,7 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let value_addr = emscripten_memory_pointer!(ctx.memory(0), value) as _; let option_len_addr = emscripten_memory_pointer!(ctx.memory(0), option_len) as *mut socklen_t; - let result = - unsafe { libc::getsockopt(socket, level, name, value_addr, option_len_addr) }; - result + unsafe { getsockopt(socket, level, name, value_addr, option_len_addr) } } 16 => { debug!("socket: sendmsg"); @@ -393,8 +621,8 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let socket: i32 = socket_varargs.get(ctx); let msg: u32 = socket_varargs.get(ctx); let flags: i32 = socket_varargs.get(ctx); - let msg_addr = emscripten_memory_pointer!(ctx.memory(0), msg) as *const libc::msghdr; - unsafe { libc::sendmsg(socket, msg_addr, flags) as i32 } + let msg_addr = emscripten_memory_pointer!(ctx.memory(0), msg) as *const msghdr; + unsafe { sendmsg(socket, msg_addr, flags) as i32 } } 17 => { debug!("socket: recvmsg"); @@ -402,8 +630,8 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let socket: i32 = socket_varargs.get(ctx); let msg: u32 = socket_varargs.get(ctx); let flags: i32 = socket_varargs.get(ctx); - let msg_addr = emscripten_memory_pointer!(ctx.memory(0), msg) as *mut libc::msghdr; - unsafe { libc::recvmsg(socket, msg_addr, flags) as i32 } + let msg_addr = emscripten_memory_pointer!(ctx.memory(0), msg) as *mut msghdr; + unsafe { recvmsg(socket, msg_addr, flags) as i32 } } _ => { // others @@ -412,60 +640,7 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in } } -/// select = ___syscall142 -#[allow(clippy::cast_ptr_alignment)] -pub fn ___syscall142(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall142 (newselect) {}", _which); - - let nfds: i32 = varargs.get(ctx); - let readfds: u32 = varargs.get(ctx); - let writefds: u32 = varargs.get(ctx); - let _exceptfds: u32 = varargs.get(ctx); - let _timeout: i32 = varargs.get(ctx); - let readfds_ptr = emscripten_memory_pointer!(ctx.memory(0), readfds) as _; - let writefds_ptr = emscripten_memory_pointer!(ctx.memory(0), writefds) as _; - let result = unsafe { libc::select(nfds, readfds_ptr, writefds_ptr, 0 as _, 0 as _) }; - debug!("select returns {}", result); - result -} - -// writev -#[allow(clippy::cast_ptr_alignment)] -pub fn ___syscall146(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { - // -> ssize_t - debug!("emscripten::___syscall146 (writev) {}", _which); - let fd: i32 = varargs.get(ctx); - let iov: i32 = varargs.get(ctx); - let iovcnt: i32 = varargs.get(ctx); - - #[repr(C)] - struct GuestIovec { - iov_base: i32, - iov_len: i32, - } - - debug!("=> fd: {}, iov: {}, iovcnt = {}", fd, iov, iovcnt); - let mut ret = 0; - unsafe { - for i in 0..iovcnt { - let guest_iov_addr = - emscripten_memory_pointer!(ctx.memory(0), (iov + i * 8)) as *mut GuestIovec; - let iov_base = emscripten_memory_pointer!(ctx.memory(0), (*guest_iov_addr).iov_base) - as *const c_void; - let iov_len = (*guest_iov_addr).iov_len as _; - // debug!("=> iov_addr: {:?}, {:?}", iov_base, iov_len); - let curr = libc::write(fd, iov_base, iov_len); - if curr < 0 { - return -1; - } - ret += curr; - } - // debug!(" => ret: {}", ret); - ret as _ - } -} - -/// pread +// pread pub fn ___syscall180(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall180 (pread) {}", _which); let fd: i32 = varargs.get(ctx); @@ -476,12 +651,13 @@ pub fn ___syscall180(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in assert_eq!(zero, 0); } let offset: i64 = varargs.get(ctx); + let buf_ptr = emscripten_memory_pointer!(ctx.memory(0), buf) as _; - let pread_result = unsafe { libc::pread(fd, buf_ptr, count as _, offset) as _ }; - pread_result + + unsafe { pread(fd, buf_ptr, count as _, offset) as _ } } -/// pwrite +// pwrite pub fn ___syscall181(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall181 (pwrite) {}", _which); let fd: i32 = varargs.get(ctx); @@ -492,8 +668,9 @@ pub fn ___syscall181(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in assert_eq!(zero, 0); } let offset: i64 = varargs.get(ctx); + let buf_ptr = emscripten_memory_pointer!(ctx.memory(0), buf) as _; - let status = unsafe { libc::pwrite(fd, buf_ptr, count as _, offset) as _ }; + let status = unsafe { pwrite(fd, buf_ptr, count as _, offset) as _ }; debug!( "=> fd: {}, buf: {}, count: {}, offset: {} = status:{}", fd, buf, count, offset, status @@ -501,75 +678,119 @@ pub fn ___syscall181(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in status } -/// stat64 -pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall195 (stat64) {}", _which); - let pathname: u32 = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); - - let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; - - unsafe { - let mut _stat: libc::stat = std::mem::zeroed(); - let ret = libc::stat(pathname_addr, &mut _stat); - debug!("ret: {}", ret); - if ret != 0 { - return ret; - } - copy_stat_into_wasm(ctx, buf, &_stat); - } - 0 -} - -/// fstat64 -pub fn ___syscall197(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall197 (fstat64) {}", _which); +/// fchmod +pub fn ___syscall94(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall118 (fchmod) {}", _which); let fd: c_int = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); - - unsafe { - let mut stat = std::mem::zeroed(); - let ret = libc::fstat(fd, &mut stat); - debug!("ret: {}", ret); - if ret != 0 { - return ret; - } - copy_stat_into_wasm(ctx, buf, &stat); - } - - 0 + let mode: mode_t = varargs.get(ctx); + unsafe { fchmod(fd, mode) } } -/// dup3 -pub fn ___syscall330(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> libc::pid_t { - // Implementation based on description at https://linux.die.net/man/2/dup3 - debug!("emscripten::___syscall330 (dup3)"); - let oldfd: c_int = varargs.get(ctx); - let newfd: c_int = varargs.get(ctx); - let flags: c_int = varargs.get(ctx); - - if oldfd == newfd { - return libc::EINVAL; - } - - let res = unsafe { libc::dup2(oldfd, newfd) }; - - // Set flags on newfd (https://www.gnu.org/software/libc/manual/html_node/Descriptor-Flags.html) - let mut old_flags = unsafe { libc::fcntl(newfd, libc::F_GETFD, 0) }; - - if old_flags > 0 { - old_flags |= flags; - } else if old_flags == 0 { - old_flags &= !flags; - } - - unsafe { - libc::fcntl(newfd, libc::F_SETFD, old_flags); - } +/// wait4 +#[allow(clippy::cast_ptr_alignment)] +pub fn ___syscall114(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t { + debug!("emscripten::___syscall114 (wait4)"); + let pid: pid_t = varargs.get(ctx); + let status: u32 = varargs.get(ctx); + let options: c_int = varargs.get(ctx); + let rusage: u32 = varargs.get(ctx); + let status_addr = emscripten_memory_pointer!(ctx.memory(0), status) as *mut c_int; + let rusage_addr = emscripten_memory_pointer!(ctx.memory(0), rusage) as *mut rusage; + let res = unsafe { wait4(pid, status_addr, options, rusage_addr) }; debug!( - "=> oldfd: {}, newfd: {}, flags: {} = pid: {}", - oldfd, newfd, flags, res + "=> pid: {}, status: {:?}, options: {}, rusage: {:?} = pid: {}", + pid, status_addr, options, rusage_addr, res ); res } + +/// fsync +pub fn ___syscall118(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall118 (fsync) {}", _which); + let fd: c_int = varargs.get(ctx); + unsafe { fsync(fd) } +} + +// select +#[allow(clippy::cast_ptr_alignment)] +pub fn ___syscall142(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall142 (newselect) {}", _which); + + let nfds: i32 = varargs.get(ctx); + let readfds: u32 = varargs.get(ctx); + let writefds: u32 = varargs.get(ctx); + let exceptfds: u32 = varargs.get(ctx); + let _timeout: i32 = varargs.get(ctx); + + assert!(nfds <= 64, "`nfds` must be less than or equal to 64"); + assert!(exceptfds == 0, "`exceptfds` is not supporrted"); + + let readfds_ptr = emscripten_memory_pointer!(ctx.memory(0), readfds) as _; + let writefds_ptr = emscripten_memory_pointer!(ctx.memory(0), writefds) as _; + + unsafe { select(nfds, readfds_ptr, writefds_ptr, 0 as _, 0 as _) } +} + +/// fdatasync +pub fn ___syscall148(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall148 (fdatasync) {}", _which); + + let fd: i32 = varargs.get(ctx); + + unsafe { fdatasync(fd) } +} + +// setpgid +pub fn ___syscall57(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall57 (setpgid) {}", _which); + let pid: i32 = varargs.get(ctx); + let pgid: i32 = varargs.get(ctx); + unsafe { setpgid(pid, pgid) } +} + +/// uname +// NOTE: Wondering if we should return custom utsname, like Emscripten. +pub fn ___syscall122(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall122 (uname) {}", _which); + let buf: u32 = varargs.get(ctx); + debug!("=> buf: {}", buf); + let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut utsname; + unsafe { uname(buf_addr) } +} + +/// lstat64 +pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { + debug!("emscripten::___syscall196 (lstat64) {}", _which); + let path_ptr: c_int = varargs.get(ctx); + let buf_ptr: c_int = varargs.get(ctx); + let path = emscripten_memory_pointer!(ctx.memory(0), path_ptr) as *const c_char; + let buf = emscripten_memory_pointer!(ctx.memory(0), buf_ptr) as *mut c_void; + let result = unsafe { lstat64(path, buf as _) }; + debug!( + "=> path: {}, buf: {} = fd: {}\npath: {}\nlast os error: {}", + path_ptr, + buf_ptr, + result, + unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }, + Error::last_os_error(), + ); + result +} + +/// fallocate +pub fn ___syscall324(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall324 (fallocate) {}", _which); + let _fd: c_int = varargs.get(ctx); + let _mode: c_int = varargs.get(ctx); + let _offset: off_t = varargs.get(ctx); + let _len: off_t = varargs.get(ctx); + #[cfg(not(target_os = "macos"))] + unsafe { + fallocate(_fd, _mode, _offset, _len) + } + #[cfg(target_os = "macos")] + { + unimplemented!() + } +} diff --git a/lib/emscripten/src/syscalls/unix/mod.rs b/lib/emscripten/src/syscalls/unix/mod.rs deleted file mode 100644 index 84257c025..000000000 --- a/lib/emscripten/src/syscalls/unix/mod.rs +++ /dev/null @@ -1,324 +0,0 @@ -use crate::varargs::VarArgs; - -#[cfg(not(feature = "vfs"))] -pub mod host_fs; - -#[cfg(all(not(target_os = "windows"), feature = "vfs"))] -pub mod vfs; - -#[cfg(not(feature = "vfs"))] -pub use host_fs::*; - -#[cfg(feature = "vfs")] -pub mod select; - -#[cfg(feature = "vfs")] -pub use select::*; - -#[cfg(feature = "vfs")] -pub use vfs::*; - -/// NOTE: TODO: These syscalls only support wasm_32 for now because they assume offsets are u32 -/// Syscall list: https://www.cs.utexas.edu/~bismith/test/syscalls/syscalls32.html -use libc::{c_int, pid_t, rusage, setpgid, uname, utsname}; -use wasmer_runtime_core::vm::Ctx; - -// Linking to functions that are not provided by rust libc -#[cfg(target_os = "macos")] -#[link(name = "c")] -extern "C" { - pub fn wait4(pid: pid_t, status: *mut c_int, options: c_int, rusage: *mut rusage) -> pid_t; - pub fn madvise(addr: *mut libc::c_void, len: libc::size_t, advice: c_int) -> c_int; - pub fn fdatasync(fd: c_int) -> c_int; - pub fn lstat64(path: *const libc::c_char, buf: *mut libc::c_void) -> c_int; -} - -#[cfg(not(target_os = "macos"))] -use libc::{fallocate, fdatasync, ftruncate64, lstat64, madvise, wait4}; - -/// link -pub fn ___syscall9(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall9 (link) {}", _which); - - let oldname: c_int = varargs.get(ctx); - let newname: c_int = varargs.get(ctx); - let oldname_ptr = emscripten_memory_pointer!(ctx.memory(0), oldname) as *const i8; - let newname_ptr = emscripten_memory_pointer!(ctx.memory(0), newname) as *const i8; - let result = unsafe { libc::link(oldname_ptr, newname_ptr) }; - debug!( - "=> oldname: {}, newname: {}, result: {}", - unsafe { std::ffi::CStr::from_ptr(oldname_ptr).to_str().unwrap() }, - unsafe { std::ffi::CStr::from_ptr(newname_ptr).to_str().unwrap() }, - result, - ); - result -} - -/// access -pub fn ___syscall33(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall33 (access) {}", _which); - let path_ptr: c_int = varargs.get(ctx); - let amode: c_int = varargs.get(ctx); - let path = emscripten_memory_pointer!(ctx.memory(0), path_ptr) as *const i8; - let result = unsafe { libc::access(path, amode) }; - debug!( - "=> path: {}, result: {}", - unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }, - result - ); - result -} - -/// nice -pub fn ___syscall34(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall34 (nice) {}", _which); - let inc_r: c_int = varargs.get(ctx); - unsafe { libc::nice(inc_r) } -} - -/// getrusage -pub fn ___syscall77(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall77 (getrusage) {}", _which); - - let resource: c_int = varargs.get(ctx); - let rusage_ptr: c_int = varargs.get(ctx); - #[allow(clippy::cast_ptr_alignment)] - let rusage = emscripten_memory_pointer!(ctx.memory(0), rusage_ptr) as *mut rusage; - assert_eq!(8, std::mem::align_of_val(&rusage)); - unsafe { libc::getrusage(resource, rusage) } -} - -/// dup -pub fn ___syscall41(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall41 (dup) {}", _which); - let fd: c_int = varargs.get(ctx); - unsafe { libc::dup(fd) } -} - -/// setpgid -pub fn ___syscall57(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall57 (setpgid) {}", _which); - let pid: i32 = varargs.get(ctx); - let pgid: i32 = varargs.get(ctx); - unsafe { setpgid(pid, pgid) } -} - -/// symlink -pub fn ___syscall83(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall83 (symlink) {}", _which); - - let path1_ptr: c_int = varargs.get(ctx); - let path2_ptr: c_int = varargs.get(ctx); - let path1 = emscripten_memory_pointer!(ctx.memory(0), path1_ptr) as *mut i8; - let path2 = emscripten_memory_pointer!(ctx.memory(0), path2_ptr) as *mut i8; - let result = unsafe { libc::symlink(path1, path2) }; - debug!( - "=> path1: {}, path2: {}, result: {}", - unsafe { std::ffi::CStr::from_ptr(path1).to_str().unwrap() }, - unsafe { std::ffi::CStr::from_ptr(path2).to_str().unwrap() }, - result, - ); - result -} - -/// fchmod -pub fn ___syscall94(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall118 (fchmod) {}", _which); - let fd: c_int = varargs.get(ctx); - let mode: libc::mode_t = varargs.get(ctx); - unsafe { libc::fchmod(fd, mode) } -} - -/// wait4 -#[allow(clippy::cast_ptr_alignment)] -pub fn ___syscall114(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t { - debug!("emscripten::___syscall114 (wait4)"); - let pid: pid_t = varargs.get(ctx); - let status: u32 = varargs.get(ctx); - let options: c_int = varargs.get(ctx); - let rusage: u32 = varargs.get(ctx); - let status_addr = emscripten_memory_pointer!(ctx.memory(0), status) as *mut c_int; - let rusage_addr = emscripten_memory_pointer!(ctx.memory(0), rusage) as *mut rusage; - let res = unsafe { wait4(pid, status_addr, options, rusage_addr) }; - debug!( - "=> pid: {}, status: {:?}, options: {}, rusage: {:?} = pid: {}", - pid, status_addr, options, rusage_addr, res - ); - res -} - -/// fsync -pub fn ___syscall118(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall118 (fsync) {}", _which); - let fd: c_int = varargs.get(ctx); - unsafe { libc::fsync(fd) } -} - -/// uname -// NOTE: Wondering if we should return custom utsname, like Emscripten. -pub fn ___syscall122(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall122 (uname) {}", _which); - let buf: u32 = varargs.get(ctx); - debug!("=> buf: {}", buf); - let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut utsname; - let uname_result = unsafe { uname(buf_addr) }; - debug!( - "uname buf: {}", - crate::utils::read_string_from_wasm(ctx.memory(0), buf) - ); - uname_result -} - -/// fdatasync -pub fn ___syscall148(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall148 (fdatasync) {}", _which); - - let fd: i32 = varargs.get(ctx); - - unsafe { fdatasync(fd) } -} - -/// ftruncate64 -pub fn ___syscall194(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall194 (ftruncate64) {}", _which); - let _fd: c_int = varargs.get(ctx); - let _length: i64 = varargs.get(ctx); - #[cfg(not(target_os = "macos"))] - unsafe { - ftruncate64(_fd, _length) - } - #[cfg(target_os = "macos")] - unimplemented!() -} - -/// lstat64 -pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { - debug!("emscripten::___syscall196 (lstat64) {}", _which); - let path_ptr: c_int = varargs.get(ctx); - let buf_ptr: c_int = varargs.get(ctx); - let path = emscripten_memory_pointer!(ctx.memory(0), path_ptr) as *const libc::c_char; - let buf = emscripten_memory_pointer!(ctx.memory(0), buf_ptr) as *mut libc::c_void; - let result = unsafe { lstat64(path, buf as _) }; - debug!( - "=> path: {}, buf: {} = fd: {}\npath: {}\nlast os error: {}", - path_ptr, - buf_ptr, - result, - unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }, - std::io::Error::last_os_error(), - ); - result -} - -/// lchown -pub fn ___syscall198(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall198 (lchown) {}", _which); - let path: c_int = varargs.get(ctx); - let uid: libc::uid_t = varargs.get(ctx); - let gid: libc::gid_t = varargs.get(ctx); - let path_ptr = emscripten_memory_pointer!(ctx.memory(0), path) as *const i8; - let result = unsafe { libc::lchown(path_ptr, uid, gid) }; - debug!( - "=> path: {}, uid: {}, gid: {}, result: {}", - unsafe { std::ffi::CStr::from_ptr(path_ptr).to_str().unwrap() }, - uid, - gid, - result, - ); - result -} - -/// getgid -pub fn ___syscall200(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { - debug!("emscripten::___syscall200 (getgid)"); - unsafe { libc::getgid() as i32 } -} - -/// getgid -pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { - debug!("emscripten::___syscall201 (getgid)"); - let result = unsafe { - // Maybe fix: Emscripten returns 0 always - libc::getgid() as i32 - }; - result -} - -/// getgid32 -pub fn ___syscall202(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { - // gid_t - debug!("emscripten::___syscall202 (getgid32)"); - unsafe { - // Maybe fix: Emscripten returns 0 always - libc::getgid() as _ - } -} - -/// fchown -pub fn ___syscall207(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall207 (fchown) {}", _which); - let fd: c_int = varargs.get(ctx); - let owner: libc::uid_t = varargs.get(ctx); - let group: libc::gid_t = varargs.get(ctx); - unsafe { libc::fchown(fd, owner, group) } -} - -/// getgroups -pub fn ___syscall205(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall205 (getgroups) {}", _which); - let ngroups_max: c_int = varargs.get(ctx); - let groups: c_int = varargs.get(ctx); - - #[allow(clippy::cast_ptr_alignment)] - let gid_ptr = emscripten_memory_pointer!(ctx.memory(0), groups) as *mut libc::gid_t; - assert_eq!(4, std::mem::align_of_val(&gid_ptr)); - let result = unsafe { libc::getgroups(ngroups_max, gid_ptr) }; - debug!( - "=> ngroups_max: {}, gid_ptr: {:?}, result: {}", - ngroups_max, gid_ptr, result, - ); - result -} - -/// chown -pub fn ___syscall212(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall212 (chown) {}", _which); - - let pathname: u32 = varargs.get(ctx); - let owner: u32 = varargs.get(ctx); - let group: u32 = varargs.get(ctx); - - let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; - - unsafe { libc::chown(pathname_addr, owner, group) } -} - -/// madvise -pub fn ___syscall219(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall212 (madvise) {}", _which); - - let addr_ptr: c_int = varargs.get(ctx); - let len: usize = varargs.get(ctx); - let advice: c_int = varargs.get(ctx); - - let addr = emscripten_memory_pointer!(ctx.memory(0), addr_ptr) as *mut libc::c_void; - - unsafe { madvise(addr, len, advice) } -} - -/// fallocate -pub fn ___syscall324(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall324 (fallocate) {}", _which); - let _fd: c_int = varargs.get(ctx); - let _mode: c_int = varargs.get(ctx); - let _offset: libc::off_t = varargs.get(ctx); - let _len: libc::off_t = varargs.get(ctx); - #[cfg(not(target_os = "macos"))] - unsafe { - fallocate(_fd, _mode, _offset, _len) - } - #[cfg(target_os = "macos")] - { - unimplemented!() - } -} diff --git a/lib/emscripten/src/syscalls/unix/select.rs b/lib/emscripten/src/syscalls/unix/select.rs deleted file mode 100644 index 189b400cc..000000000 --- a/lib/emscripten/src/syscalls/unix/select.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::syscalls::emscripten_vfs::EmscriptenVfs; -use crate::varargs::VarArgs; -use crate::EmscriptenData; -use wasmer_runtime_core::memory::Memory; -use wasmer_runtime_core::vm::Ctx; - -#[inline] -pub fn emscripten_memory_ptr(memory: &Memory, offset: u32) -> *mut u8 { - use std::cell::Cell; - (&memory.view::()[(offset as usize)..]).as_ptr() as *mut Cell as *mut u8 -} - -fn translate_to_host_file_descriptors( - vfs: &EmscriptenVfs, - set_ptr: *mut libc::fd_set, - nfds: i32, -) -> Option<(i32, Vec)> { - let pairs = (0..nfds) - .map(|vfd| { - let host_fd = vfs.get_host_socket_fd(vfd).unwrap_or(-1); - (vfd, host_fd) - }) - .filter(|(_, host_fd)| *host_fd >= 0) - .filter(|(vfd, _)| unsafe { libc::FD_ISSET(*vfd, set_ptr) }) - .collect::>(); - let max = pairs - .iter() - .map(|(_, host_fd)| *host_fd) - .max() - .unwrap_or(-1) - + 1; - let mut internal_handles = vec![0; max as usize]; - unsafe { libc::FD_ZERO(set_ptr) }; - - for (vfd, host_fd) in pairs.iter() { - let index = *host_fd as usize; - if internal_handles.get(index).is_none() { - // index is out of range and we are in a bad state...push back up and let the application handle failure - return None; - } - internal_handles[*host_fd as usize] = *vfd; - unsafe { - libc::FD_SET(*host_fd, set_ptr); - }; - } - Some((max, internal_handles)) -} - -fn translate_to_virtual_file_descriptors(set_ptr: *mut libc::fd_set, internal_handles: Vec) { - let virtual_fds = internal_handles - .iter() - .enumerate() - .filter(|(host_fd, _)| unsafe { libc::FD_ISSET(*host_fd as i32, set_ptr) }) - .map(|(_, vfd)| *vfd) - .collect::>(); - unsafe { libc::FD_ZERO(set_ptr) }; - virtual_fds - .iter() - .for_each(|vfd| unsafe { libc::FD_SET(*vfd, set_ptr) }); -} - -/// select -#[allow(clippy::cast_ptr_alignment)] -pub fn ___syscall142(ctx: &mut Ctx, _: libc::c_int, mut varargs: VarArgs) -> libc::c_int { - debug!("emscripten::___syscall142 (select)"); - let nfds: i32 = varargs.get(ctx); - let readfds: u32 = varargs.get(ctx); - let writefds: u32 = varargs.get(ctx); - let _exceptfds: u32 = varargs.get(ctx); - let _timeout: i32 = varargs.get(ctx); - assert!(nfds <= 64, "`nfds` must be less than or equal to 64"); - let emscripten_memory = ctx.memory(0); - let read_set_ptr = emscripten_memory_ptr(emscripten_memory, readfds) as _; - let write_set_ptr = emscripten_memory_ptr(emscripten_memory, writefds) as _; - let vfs = unsafe { (*(ctx.data as *const EmscriptenData)).vfs.as_ref().unwrap() }; - - // read descriptors and write descriptors, if any didn't work, then fail - let (read_host_nfds, read_lookup, write_host_nfds, write_lookup) = match ( - translate_to_host_file_descriptors(vfs, read_set_ptr, nfds), - translate_to_host_file_descriptors(vfs, write_set_ptr, nfds), - ) { - (None, _) => return -1, - (_, None) => return -1, - (Some((read_host_nfds, read_lookup)), Some((write_host_nfds, write_lookup))) => { - (read_host_nfds, read_lookup, write_host_nfds, write_lookup) - } - }; - - let host_nfds = std::cmp::max(read_host_nfds, write_host_nfds); - // TODO: timeout and except fds set - let result = unsafe { libc::select(host_nfds, read_set_ptr, write_set_ptr, 0 as _, 0 as _) }; - translate_to_virtual_file_descriptors(read_set_ptr, read_lookup); - translate_to_virtual_file_descriptors(write_set_ptr, write_lookup); - result -} diff --git a/lib/emscripten/src/syscalls/unix/vfs.rs b/lib/emscripten/src/syscalls/unix/vfs.rs deleted file mode 100644 index 7ebd701e5..000000000 --- a/lib/emscripten/src/syscalls/unix/vfs.rs +++ /dev/null @@ -1,677 +0,0 @@ -use crate::syscalls::emscripten_vfs::FileHandle; -use crate::utils::{copy_stat_into_wasm, read_string_from_wasm}; -use crate::varargs::VarArgs; -use libc::stat; -use std::cell::RefCell; -use std::ffi::c_void; -use std::os::raw::c_int; -use std::slice; -use wasmer_runtime_core::memory::Memory; -use wasmer_runtime_core::vm::Ctx; - -#[inline] -pub fn emscripten_memory_ptr(memory: &Memory, offset: u32) -> *mut u8 { - use std::cell::Cell; - (&memory.view::()[(offset as usize)..]).as_ptr() as *mut Cell as *mut u8 -} - -/// read -pub fn ___syscall3(ctx: &mut Ctx, _: i32, mut varargs: VarArgs) -> i32 { - debug!("emscripten::___syscall3 (read - vfs)",); - let fd: i32 = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); - let count: i32 = varargs.get(ctx); - debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count); - let buf_addr = emscripten_memory_ptr(ctx.memory(0), buf) as *mut u8; - let buf_slice = unsafe { slice::from_raw_parts_mut(buf_addr, count as _) }; - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let ret = vfs.read_file(fd, buf_slice); - debug!("=> read syscall returns: {}", ret); - ret as _ -} - -/// write -pub fn ___syscall4(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall4 (write - vfs) {}", _which); - let fd: i32 = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); - let count: i32 = varargs.get(ctx); - let buf_addr = emscripten_memory_ptr(ctx.memory(0), buf); - let buf_slice = unsafe { slice::from_raw_parts_mut(buf_addr, count as _) }; - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - match vfs.write_file(fd, buf_slice, count as usize) { - Ok(count) => count as _, - Err(_) => -1, - } -} - -/// open -pub fn ___syscall5(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall5 (open vfs) {}", _which); - let pathname: u32 = varargs.get(ctx); - let pathname_addr = emscripten_memory_ptr(ctx.memory(0), pathname) as *const i8; - let path_str = unsafe { std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap() }; - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let fd = vfs.open_file(path_str); - fd -} - -/// close -pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall6 (close vfs) {}", _which); - let fd: i32 = varargs.get(ctx); - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let close_result = vfs.close_file_descriptor(fd); - close_result -} - -/// chmod -pub fn ___syscall15(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { - debug!("emscripten::___syscall15 (chmod)"); - debug!("chmod always returns 0."); - 0 -} - -/// mkdir -pub fn ___syscall39(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall39 (mkdir vfs) {}", _which); - let pathname: u32 = varargs.get(ctx); - let _mode: u32 = varargs.get(ctx); - let path = read_string_from_wasm(ctx.memory(0), pathname); - let root = std::path::PathBuf::from("/"); - let absolute_path = root.join(&path); - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - vfs.make_dir(&absolute_path); - 0 -} - -/// pipe -pub fn ___syscall42(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int { - unimplemented!("emscripten::___syscall42 (pipe)"); -} - -/// ioctl -pub fn ___syscall54(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall54 (ioctl) {}", _which); - let fd: i32 = varargs.get(ctx); - let request: u32 = varargs.get(ctx); - debug!("virtual fd: {}, op: {}", fd, request); - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_fd = match vfs.get_host_socket_fd(fd) { - Some(host_fd) => host_fd, - _ => return -1, - }; - - // Got the equivalents here: https://code.woboq.org/linux/linux/include/uapi/asm-generic/ioctls.h.html - match request as _ { - 21537 => { - // FIONBIO - let argp: u32 = varargs.get(ctx); - let argp_ptr = emscripten_memory_ptr(ctx.memory(0), argp) as *mut c_void; - let ret = unsafe { libc::ioctl(host_fd, libc::FIONBIO, argp_ptr) }; - debug!("ret(FIONBIO): {}", ret); - ret - // 0 - } - 21523 => { - // TIOCGWINSZ - let argp: u32 = varargs.get(ctx); - let argp_ptr = emscripten_memory_ptr(ctx.memory(0), argp) as *mut c_void; - let ret = unsafe { libc::ioctl(host_fd, libc::TIOCGWINSZ, argp_ptr) }; - debug!("ret(TIOCGWINSZ): {} (harcoded to 0)", ret); - // ret - // TODO: We hardcode the value to have emscripten tests pass, as for some reason - // when the capturer is active, ioctl returns -1 instead of 0 - if ret == -1 { - 0 - } else { - ret - } - } - _ => { - debug!( - "emscripten::___syscall54 -> non implemented case {}", - request - ); - 0 - } - } -} - -/// dup2 -pub fn ___syscall63(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall63 (dup2) {}", _which); - let src: i32 = varargs.get(ctx); - let dst: i32 = varargs.get(ctx); - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - // if the src is a valid file descriptor, then continue - if !vfs.fd_map.contains_key(&src) { - return -1; - } - // if src and dst are identical, do nothing - if src == dst { - return 0; - } - let _ = vfs.fd_map.remove(&dst); - let dst_file_handle = match vfs.fd_map.get(&src) { - Some(FileHandle::Vf(file)) => FileHandle::Vf(file.clone()), - Some(FileHandle::Socket(src_host_fd)) => { - // get a dst file descriptor, or just use the underlying dup syscall - match unsafe { libc::dup(*src_host_fd) } { - -1 => return -1, - dst_host_fd => FileHandle::Socket(dst_host_fd), - } - } - None => return -1, - }; - vfs.fd_map.insert(dst, dst_file_handle); - debug!("emscripten::___syscall63 (dup2) returns {}", dst); - dst -} - -// socketcall -#[allow(clippy::cast_ptr_alignment)] -pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall102 (socketcall) {}", _which); - let call: u32 = varargs.get(ctx); - let mut socket_varargs: VarArgs = varargs.get(ctx); - - #[repr(C)] - pub struct GuestSockaddrIn { - pub sin_family: libc::sa_family_t, // u16 - pub sin_port: libc::in_port_t, // u16 - pub sin_addr: GuestInAddr, // u32 - pub sin_zero: [u8; 8], // u8 * 8 - // 2 + 2 + 4 + 8 = 16 - } - - #[repr(C)] - pub struct GuestInAddr { - pub s_addr: libc::in_addr_t, // u32 - } - - pub struct LinuxSockAddr { - pub sa_family: u16, - pub sa_data: [libc::c_char; 14], - } - - match call { - 1 => { - debug!("socket: socket"); - // Another conditional constant for name resolution: Macos et iOS use - // SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket. - // Other platforms do otherwise. - #[cfg(target_os = "darwin")] - use libc::SO_NOSIGPIPE; - #[cfg(not(target_os = "darwin"))] - const SO_NOSIGPIPE: c_int = 0; - // socket (domain: c_int, ty: c_int, protocol: c_int) -> c_int - let domain: i32 = socket_varargs.get(ctx); - let ty: i32 = socket_varargs.get(ctx); - let protocol: i32 = socket_varargs.get(ctx); - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let _test_errno = errno::errno(); - // create the host socket - let host_fd = unsafe { libc::socket(domain, ty, protocol) }; - let vfd = vfs.new_socket_fd(host_fd); - // set_cloexec - let _ioctl_result = unsafe { libc::ioctl(host_fd, libc::FIOCLEX) }; - let _err = errno::errno(); - let _result = unsafe { - libc::setsockopt(host_fd, libc::SOL_SOCKET, SO_NOSIGPIPE, 0 as *const _, 4) - }; - let _err2 = errno::errno(); - debug!( - "=> domain: {} (AF_INET/2), type: {} (SOCK_STREAM/1), protocol: {} = fd: {}", - domain, ty, protocol, vfd - ); - vfd - } - 2 => { - debug!("socket: bind"); - // bind (socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int - // TODO: Emscripten has a different signature. - let socket: i32 = socket_varargs.get(ctx); - let address: u32 = socket_varargs.get(ctx); - let address_len = socket_varargs.get(ctx); - let address = emscripten_memory_ptr(ctx.memory(0), address) as *mut libc::sockaddr; - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_socket_fd = vfs.get_host_socket_fd(socket).unwrap(); - - // Debug received address - let _proper_address = address as *const GuestSockaddrIn; - let _other_proper_address = address as *const libc::sockaddr; - debug!( - "=> address.sin_family: {:?}, address.sin_port: {:?}, address.sin_addr.s_addr: {:?}", - unsafe { (*_proper_address).sin_family }, unsafe { (*_proper_address).sin_port }, unsafe { (*_proper_address).sin_addr.s_addr } - ); - let status = unsafe { libc::bind(host_socket_fd as _, address, address_len) }; - // debug!("=> status: {}", status); - debug!( - "=> socketfd: {}, address: {:?}, address_len: {} = status: {}", - socket, address, address_len, status - ); - status - // -1 - } - 3 => { - debug!("socket: connect"); - // connect (socket: c_int, address: *const sockaddr, len: socklen_t) -> c_int - // TODO: Emscripten has a different signature. - let socket: i32 = socket_varargs.get(ctx); - let address: u32 = socket_varargs.get(ctx); - let address_len = socket_varargs.get(ctx); - let address = emscripten_memory_ptr(ctx.memory(0), address) as *mut libc::sockaddr; - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_socket_fd = vfs.get_host_socket_fd(socket).unwrap(); - unsafe { libc::connect(host_socket_fd as _, address, address_len) } - } - 4 => { - debug!("socket: listen"); - // listen (socket: c_int, backlog: c_int) -> c_int - let socket: i32 = socket_varargs.get(ctx); - let backlog: i32 = socket_varargs.get(ctx); - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_socket_fd = vfs.get_host_socket_fd(socket).unwrap(); - let status = unsafe { libc::listen(host_socket_fd, backlog) }; - debug!( - "=> socketfd: {}, backlog: {} = status: {}", - socket, backlog, status - ); - status - } - 5 => { - debug!("socket: accept"); - let socket: i32 = socket_varargs.get(ctx); - let address_addr: u32 = socket_varargs.get(ctx); - let address_len: u32 = socket_varargs.get(ctx); - let address = emscripten_memory_ptr(ctx.memory(0), address_addr) as *mut libc::sockaddr; - let address_len_addr = - emscripten_memory_ptr(ctx.memory(0), address_len) as *mut libc::socklen_t; - - let host_socket_fd = { - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_socket_fd = vfs.get_host_socket_fd(socket).unwrap(); - host_socket_fd - }; - - debug!( - "=> socket: {}(host {}), address: {:?}, address_len: {}", - socket, host_socket_fd, address, address_len - ); - - let new_accept_host_fd = - unsafe { libc::accept(host_socket_fd, address, address_len_addr) }; - - if new_accept_host_fd < 0 { - panic!("accept file descriptor should not be negative."); - } - - unsafe { - let address_linux = - emscripten_memory_ptr(ctx.memory(0), address_addr) as *mut LinuxSockAddr; - (*address_linux).sa_family = (*address).sa_family as u16; - (*address_linux).sa_data = (*address).sa_data; - }; - - // set_cloexec - let _ioctl_result = unsafe { libc::ioctl(new_accept_host_fd, libc::FIOCLEX) }; - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let new_vfd = vfs.new_socket_fd(new_accept_host_fd); - - debug!("new accept fd: {}(host {})", new_vfd, new_accept_host_fd); - - new_vfd - } - 6 => { - debug!("socket: getsockname"); - // getsockname (socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int - let socket: i32 = socket_varargs.get(ctx); - let address: u32 = socket_varargs.get(ctx); - let address_len: u32 = socket_varargs.get(ctx); - let address = emscripten_memory_ptr(ctx.memory(0), address) as *mut libc::sockaddr; - let address_len_addr = - emscripten_memory_ptr(ctx.memory(0), address_len) as *mut libc::socklen_t; - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_socket_fd = vfs.get_host_socket_fd(socket).unwrap(); - - unsafe { libc::getsockname(host_socket_fd as _, address, address_len_addr) } - } - 7 => { - debug!("socket: getpeername"); - // getpeername (socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int - let socket: i32 = socket_varargs.get(ctx); - let address: u32 = socket_varargs.get(ctx); - let address_len: u32 = socket_varargs.get(ctx); - let address = emscripten_memory_ptr(ctx.memory(0), address) as *mut libc::sockaddr; - let address_len_addr = - emscripten_memory_ptr(ctx.memory(0), address_len) as *mut libc::socklen_t; - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_socket_fd = vfs.get_host_socket_fd(socket).unwrap(); - - unsafe { libc::getpeername(host_socket_fd as _, address, address_len_addr) } - } - 11 => { - debug!("socket: sendto"); - // sendto (socket: c_int, buf: *const c_void, len: size_t, flags: c_int, addr: *const sockaddr, addrlen: socklen_t) -> ssize_t - let socket: i32 = socket_varargs.get(ctx); - let buf: u32 = socket_varargs.get(ctx); - let flags = socket_varargs.get(ctx); - let len: i32 = socket_varargs.get(ctx); - let address: u32 = socket_varargs.get(ctx); - let address_len = socket_varargs.get(ctx); - let buf_addr = emscripten_memory_ptr(ctx.memory(0), buf) as _; - let address = emscripten_memory_ptr(ctx.memory(0), address) as *mut libc::sockaddr; - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_socket_fd = vfs.get_host_socket_fd(socket).unwrap(); - - unsafe { - libc::sendto( - host_socket_fd as _, - buf_addr, - flags, - len, - address, - address_len, - ) as i32 - } - } - 12 => { - debug!("socket: recvfrom"); - // recvfrom (socket: c_int, buf: *const c_void, len: size_t, flags: c_int, addr: *const sockaddr, addrlen: socklen_t) -> ssize_t - let socket: i32 = socket_varargs.get(ctx); - let buf: u32 = socket_varargs.get(ctx); - let flags = socket_varargs.get(ctx); - let len: i32 = socket_varargs.get(ctx); - let address: u32 = socket_varargs.get(ctx); - let address_len: u32 = socket_varargs.get(ctx); - let buf_addr = emscripten_memory_ptr(ctx.memory(0), buf) as _; - let address = emscripten_memory_ptr(ctx.memory(0), address) as *mut libc::sockaddr; - let address_len_addr = - emscripten_memory_ptr(ctx.memory(0), address_len) as *mut libc::socklen_t; - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_socket_fd = vfs.get_host_socket_fd(socket).unwrap(); - - let recv_result = unsafe { - libc::recvfrom( - host_socket_fd, - buf_addr, - flags, - len, - address, - address_len_addr, - ) as i32 - }; - debug!( - "recvfrom: socket: {}, flags: {}, len: {}, result: {}", - socket, flags, len, recv_result - ); - recv_result - } - 14 => { - debug!("socket: setsockopt"); - // NOTE: Emscripten seems to be passing the wrong values to this syscall - // level: Em passes 1 as SOL_SOCKET; SOL_SOCKET is 0xffff in BSD - // name: Em passes SO_ACCEPTCONN, but Nginx complains about REUSEADDR - // https://github.com/openbsd/src/blob/master/sys/sys/socket.h#L156 - // setsockopt (socket: c_int, level: c_int, name: c_int, value: *const c_void, option_len: socklen_t) -> c_int - - let socket = socket_varargs.get(ctx); - // SOL_SOCKET = 0xffff (BSD, Linux) - let level: i32 = libc::SOL_SOCKET; - let _: u32 = socket_varargs.get(ctx); - // SO_REUSEADDR = 0x4 (BSD, Linux) - let name: i32 = libc::SO_REUSEADDR; - let _: u32 = socket_varargs.get(ctx); - let value: u32 = socket_varargs.get(ctx); - let option_len = socket_varargs.get(ctx); - let value_addr = emscripten_memory_ptr(ctx.memory(0), value) as _; // Endian problem - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_socket_fd = vfs.get_host_socket_fd(socket).unwrap(); - - let ret = unsafe { - libc::setsockopt(host_socket_fd as _, level, name, value_addr, option_len) - }; - - debug!("=> socketfd: {}, level: {} (SOL_SOCKET/0xffff), name: {} (SO_REUSEADDR/4), value_addr: {:?}, option_len: {} = status: {}", socket, level, name, value_addr, option_len, ret); - ret - } - 15 => { - debug!("socket: getsockopt"); - // getsockopt (sockfd: c_int, level: c_int, optname: c_int, optval: *mut c_void, optlen: *mut socklen_t) -> c_int - use libc::socklen_t; - let socket = socket_varargs.get(ctx); - let level: i32 = socket_varargs.get(ctx); - let correct_level = if level == 1 { libc::SOL_SOCKET } else { level }; - let name: i32 = socket_varargs.get(ctx); - let correct_name = if name == 3 { libc::SO_TYPE } else { name }; - - let value: u32 = socket_varargs.get(ctx); - let option_len: u32 = socket_varargs.get(ctx); - let value_addr = emscripten_memory_ptr(ctx.memory(0), value) as _; - let option_len_addr = - emscripten_memory_ptr(ctx.memory(0), option_len) as *mut socklen_t; - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_socket_fd = match vfs.get_host_socket_fd(socket) { - Some(host_fd) => host_fd, - None => { - return -1; - } - }; - let result = unsafe { - libc::getsockopt( - host_socket_fd, - correct_level, - correct_name, - value_addr, - option_len_addr, - ) - }; - result - } - 16 => { - debug!("socket: sendmsg"); - // sendmsg (fd: c_int, msg: *const msghdr, flags: c_int) -> ssize_t - let socket: i32 = socket_varargs.get(ctx); - let msg: u32 = socket_varargs.get(ctx); - let flags: i32 = socket_varargs.get(ctx); - let msg_addr = emscripten_memory_ptr(ctx.memory(0), msg) as *const libc::msghdr; - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_socket_fd = vfs.get_host_socket_fd(socket).unwrap(); - - unsafe { libc::sendmsg(host_socket_fd as _, msg_addr, flags) as i32 } - } - 17 => { - debug!("socket: recvmsg"); - // recvmsg (fd: c_int, msg: *mut msghdr, flags: c_int) -> ssize_t - let socket: i32 = socket_varargs.get(ctx); - let msg: u32 = socket_varargs.get(ctx); - let flags: i32 = socket_varargs.get(ctx); - let msg_addr = emscripten_memory_ptr(ctx.memory(0), msg) as *mut libc::msghdr; - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let host_socket_fd = vfs.get_host_socket_fd(socket).unwrap(); - - unsafe { libc::recvmsg(host_socket_fd as _, msg_addr, flags) as i32 } - } - _ => { - // others - -1 - } - } -} - -/// writev -#[allow(clippy::cast_ptr_alignment)] -pub fn ___syscall146(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { - // -> ssize_t - debug!("emscripten::___syscall146 (writev) {}", _which); - let fd: i32 = varargs.get(ctx); - let iov_array_offset: i32 = varargs.get(ctx); - let iovcnt: i32 = varargs.get(ctx); - - #[repr(C)] - struct GuestIovec { - iov_base: i32, - iov_len: i32, - } - - let mut err = false; - let iov_array_offset = iov_array_offset as u32; - let count = (0..iovcnt as u32).fold(0, |acc, iov_array_index| { - let iov_offset = iov_array_offset + iov_array_index * 8; // get the offset to the iov - let (iov_buf_slice, iov_buf_ptr, count) = { - let emscripten_memory = ctx.memory(0); - let guest_iov_ptr = - emscripten_memory_ptr(emscripten_memory, iov_offset) as *mut GuestIovec; - let iov_base_offset = unsafe { (*guest_iov_ptr).iov_base as u32 }; - let iov_buf_ptr = - emscripten_memory_ptr(emscripten_memory, iov_base_offset) as *const c_void; - let iov_len = unsafe { (*guest_iov_ptr).iov_len as usize }; - let iov_buf_slice = unsafe { slice::from_raw_parts(iov_buf_ptr as *const u8, iov_len) }; - (iov_buf_slice, iov_buf_ptr, iov_len) - }; - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let count: usize = match vfs.fd_map.get(&fd) { - Some(FileHandle::Vf(file)) => { - match RefCell::borrow_mut(file).write_file(iov_buf_slice, 0) { - Ok(count) => count, - _ => { - err = true; - 0 - } - } - } - Some(FileHandle::Socket(host_fd)) => unsafe { - let count = libc::write(*host_fd, iov_buf_ptr, count); - count as usize - }, - None => { - err = true; - 0 - } - }; - acc + count - }); - - if err { - return -1; - } - - debug!( - "=> fd: {}, iov: {}, iovcnt = {}, returning {}", - fd, iov_array_offset, iovcnt, count - ); - count as _ -} - -/// pread -pub fn ___syscall180(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall180 (pread) {}", _which); - let fd: i32 = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); - let count: i32 = varargs.get(ctx); - let offset: i32/*i64*/ = varargs.get(ctx); - let buf_addr = emscripten_memory_ptr(ctx.memory(0), buf) as *mut u8; - let buf_slice = unsafe { slice::from_raw_parts_mut(buf_addr, count as _) }; - let mut buf_slice_with_offset: &mut [u8] = &mut buf_slice[(offset as usize)..]; - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_ref().unwrap(); //.as_mut().unwrap(); - let ret = vfs.read_file(fd, &mut buf_slice_with_offset); - debug!("read: '{}'", read_string_from_wasm(ctx.memory(0), buf)); - ret as _ -} - -/// pwrite -pub fn ___syscall181(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall181 (pwrite) {}", _which); - let fd: i32 = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); - let count: u32 = varargs.get(ctx); - let _offset: i32 = varargs.get(ctx); - let buf_addr = emscripten_memory_ptr(ctx.memory(0), buf); - let buf_slice = unsafe { slice::from_raw_parts_mut(buf_addr, count as _) }; - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - match vfs.write_file(fd, buf_slice, count as _) { - Ok(count) => count as _, - Err(e) => { - eprintln!("{:?}", e); - -1 - } - } -} - -// stat64 -pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall195 (stat64) {}", _which); - let pathname: u32 = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); - let path_string = read_string_from_wasm(ctx.memory(0), pathname); - debug!("path extract for `stat` syscall: {}", &path_string); - let path = std::path::PathBuf::from(path_string); - - let emscripten_data = crate::env::get_emscripten_data(ctx); - let ret = match &mut emscripten_data.vfs { - Some(vfs) => { - let metadata = vfs.path_metadata(&path).unwrap(); - let len = metadata.len; - unsafe { - let mut stat: stat = std::mem::zeroed(); - stat.st_size = len as _; - debug!("stat size: {}", len); - copy_stat_into_wasm(ctx, buf, &stat as _); - } - 0 - } - None => -1, - }; - debug!("stat return: {}", ret); - ret -} - -/// fstat64 -pub fn ___syscall197(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall197 (fstat64) {}", _which); - let fd: c_int = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - let ret = match vfs.fd_map.get(&fd) { - Some(FileHandle::Vf(file)) => { - let metadata = file.borrow_mut().metadata().unwrap(); - // let metadata = vfs.vfs.get_file_metadata(internal_handle).unwrap(); - let len = metadata.len; - let mode = if metadata.is_file { - libc::S_IFREG - } else { - libc::S_IFDIR - }; - unsafe { - let mut stat: stat = std::mem::zeroed(); - stat.st_mode = mode as _; - stat.st_size = len as _; - debug!("fstat size: {}", len); - copy_stat_into_wasm(ctx, buf, &stat as _); - } - 0 - } - Some(FileHandle::Socket(_host_fd)) => panic!(), - None => -1, - }; - debug!("fstat return: {}", ret); - ret -} - -/// dup3 -pub fn ___syscall330(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> libc::pid_t { - unimplemented!(); -} diff --git a/lib/emscripten/src/syscalls/windows.rs b/lib/emscripten/src/syscalls/windows.rs index 8ba3a71a7..a7ac8c11c 100644 --- a/lib/emscripten/src/syscalls/windows.rs +++ b/lib/emscripten/src/syscalls/windows.rs @@ -13,31 +13,6 @@ use wasmer_runtime_core::vm::Ctx; #[allow(non_camel_case_types)] type pid_t = c_int; -/// read -pub fn ___syscall3(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { - debug!("emscripten::___syscall3 (read) {}", _which); - let fd: i32 = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); - let count: i32 = varargs.get(ctx); - debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count); - let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut libc::c_void; - let ret = unsafe { libc::read(fd, buf_addr, count as _) }; - debug!("=> ret: {}", ret); - ret as _ -} - -/// write -pub fn ___syscall4(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall4 (write) {}", _which); - let fd: i32 = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); - let count: i32 = varargs.get(ctx); - debug!("=> fd: {}, buf: {}, count: {}", fd, buf, count); - let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *const libc::c_void; - let ret = unsafe { libc::write(fd, buf_addr, count as _) as i32 }; - ret -} - /// open pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall5 (open) {}", which); @@ -83,72 +58,12 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { } } -/// close -pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall6 (close) {}", _which); - let fd: i32 = varargs.get(ctx); - debug!("fd: {}", fd); - unsafe { libc::close(fd) } -} - /// link -pub fn ___syscall9(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { +pub fn ___syscall9(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall9 (link) {}", _which); unimplemented!() } -/// chmod -pub fn ___syscall15(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { - debug!("emscripten::___syscall15"); - -1 -} - -/// dup2 -pub fn ___syscall63(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall63 (dup2) {}", _which); - - let src: i32 = varargs.get(ctx); - let dst: i32 = varargs.get(ctx); - - unsafe { libc::dup2(src, dst) } -} - -// writev -#[allow(clippy::cast_ptr_alignment)] -pub fn ___syscall146(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { - // -> ssize_t - debug!("emscripten::___syscall146 (writev) {}", _which); - let fd: i32 = varargs.get(ctx); - let iov: i32 = varargs.get(ctx); - let iovcnt: i32 = varargs.get(ctx); - - #[repr(C)] - struct GuestIovec { - iov_base: i32, - iov_len: i32, - } - - debug!("=> fd: {}, iov: {}, iovcnt = {}", fd, iov, iovcnt); - let mut ret = 0; - unsafe { - for i in 0..iovcnt { - let guest_iov_addr = - emscripten_memory_pointer!(ctx.memory(0), (iov + i * 8)) as *mut GuestIovec; - let iov_base = emscripten_memory_pointer!(ctx.memory(0), (*guest_iov_addr).iov_base) - as *const libc::c_void; - let iov_len = (*guest_iov_addr).iov_len as _; - // debug!("=> iov_addr: {:?}, {:?}", iov_base, iov_len); - let curr = libc::write(fd, iov_base, iov_len); - if curr < 0 { - return -1; - } - ret += curr; - } - // debug!(" => ret: {}", ret); - ret as _ - } -} - /// ftruncate64 pub fn ___syscall194(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall194 - stub"); @@ -164,13 +79,13 @@ pub fn ___syscall212(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i } /// access -pub fn ___syscall33(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { +pub fn ___syscall33(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall33 (access) {}", _which); unimplemented!() } /// nice -pub fn ___syscall34(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { +pub fn ___syscall34(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall34 (nice) {}", _which); unimplemented!() } @@ -246,32 +161,6 @@ pub fn ___syscall330(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> pi -1 } -/// pipe -pub fn ___syscall42(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { - debug!("emscripten::___syscall42 (pipe)"); - // offset to a file descriptor, which contains a read end and write end, 2 integers - let fd_offset: u32 = varargs.get(ctx); - - let emscripten_memory = ctx.memory(0); - - // convert the file descriptor into a vec with two slots - let mut fd_vec: Vec = emscripten_memory.view()[((fd_offset / 4) as usize)..] - .iter() - .map(|pipe_end: &std::cell::Cell| pipe_end.get()) - .take(2) - .collect(); - - // get it as a mutable pointer - let fd_ptr = fd_vec.as_mut_ptr(); - - // call pipe and store the pointers in this array - #[cfg(target_os = "windows")] - let result: c_int = unsafe { libc::pipe(fd_ptr, 2048, 0) }; - #[cfg(not(target_os = "windows"))] - let result: c_int = unsafe { libc::pipe(fd_ptr) }; - result -} - /// ioctl pub fn ___syscall54(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall54 (ioctl) {}", which); diff --git a/lib/emscripten/src/utils.rs b/lib/emscripten/src/utils.rs index d6255308f..5dcfd4e11 100644 --- a/lib/emscripten/src/utils.rs +++ b/lib/emscripten/src/utils.rs @@ -90,6 +90,24 @@ pub unsafe fn allocate_cstr_on_stack<'a>(ctx: &'a mut Ctx, s: &str) -> (u32, &'a (offset, slice) } +#[cfg(not(target_os = "windows"))] +pub unsafe fn copy_terminated_array_of_cstrs(_ctx: &mut Ctx, cstrs: *mut *mut c_char) -> u32 { + let _total_num = { + let mut ptr = cstrs; + let mut counter = 0; + while !(*ptr).is_null() { + counter += 1; + ptr = ptr.add(1); + } + counter + }; + debug!( + "emscripten::copy_terminated_array_of_cstrs::total_num: {}", + _total_num + ); + 0 +} + #[repr(C)] pub struct GuestStat { st_dev: u32, @@ -175,7 +193,11 @@ mod tests { } #[cfg(not(any(feature = "llvm", feature = "clif", feature = "dynasm")))] - compile_error!("compiler not specified, activate a compiler via features"); + fn get_compiler() -> impl Compiler { + panic!("compiler not specified, activate a compiler via features"); + use wasmer_clif_backend::CraneliftCompiler; + CraneliftCompiler::new() + } #[test] fn should_detect_emscripten_files() { diff --git a/lib/emscripten/tests/emtests/_common.rs b/lib/emscripten/tests/emtests/_common.rs index a0cb48493..1289fe741 100644 --- a/lib/emscripten/tests/emtests/_common.rs +++ b/lib/emscripten/tests/emtests/_common.rs @@ -68,31 +68,10 @@ macro_rules! assert_emscripten_output { } pub fn assert_emscripten_output(wasm_bytes: &[u8], raw_expected_str: &str) { + use wasmer_clif_backend::CraneliftCompiler; use wasmer_emscripten::{generate_emscripten_env, stdio::StdioCapturer, EmscriptenGlobals}; - use wasmer_runtime_core::backend::Compiler; - #[cfg(feature = "clif")] - fn get_compiler() -> impl Compiler { - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() - } - - #[cfg(feature = "llvm")] - fn get_compiler() -> impl Compiler { - use wasmer_llvm_backend::LLVMCompiler; - LLVMCompiler::new() - } - - #[cfg(not(any(feature = "llvm", feature = "clif")))] - fn get_compiler() -> impl Compiler { - panic!("compiler not specified, activate a compiler via features"); - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() - } - - let compiler = get_compiler(); - - let module = wasmer_runtime_core::compile_with(&wasm_bytes[..], &compiler) + let module = wasmer_runtime_core::compile_with(&wasm_bytes[..], &CraneliftCompiler::new()) .expect("WASM can't be compiled"); let mut emscripten_globals = EmscriptenGlobals::new(&module); diff --git a/lib/emscripten/tests/emtests/mod.rs b/lib/emscripten/tests/emtests/mod.rs index 0de23e60d..89a66bf2b 100644 --- a/lib/emscripten/tests/emtests/mod.rs +++ b/lib/emscripten/tests/emtests/mod.rs @@ -176,8 +176,6 @@ mod test_unary_literal; mod test_utf; mod test_varargs; mod test_varargs_multi; -#[cfg(all(feature = "vfs", not(target_os = "windows")))] -mod test_vfs; mod test_vprintf; mod test_vsnprintf; mod test_wprintf;