Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add mapdir for emscripten; implement getdents, etc. #470

Merged
merged 7 commits into from
May 29, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions lib/emscripten/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ edition = "2018"
build = "build/mod.rs"

[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
byteorder = "1"
hashbrown = "0.1"
lazy_static = "1.2.0"
libc = "0.2.49"
byteorder = "1"
time = "0.1.41"
wasmer-clif-backend = { path = "../clif-backend", version = "0.4.2" }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.2", optional = true }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.4.2", optional = true }
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.2", optional = true }

[target.'cfg(windows)'.dependencies]
rand = "0.6"
Expand Down
12 changes: 10 additions & 2 deletions lib/emscripten/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
#[macro_use]
extern crate wasmer_runtime_core;

use hashbrown::HashMap;
use lazy_static::lazy_static;
use std::cell::UnsafeCell;
use std::path::PathBuf;
use std::{f64, ffi::c_void};
use wasmer_runtime_core::{
error::CallResult,
Expand Down Expand Up @@ -141,10 +143,14 @@ pub struct EmscriptenData<'a> {
pub stack_save: Option<Func<'a, (), i32>>,
pub stack_restore: Option<Func<'a, (i32)>>,
pub set_threw: Option<Func<'a, (i32, i32)>>,
pub mapped_dirs: HashMap<String, PathBuf>,
}

impl<'a> EmscriptenData<'a> {
pub fn new(instance: &'a mut Instance) -> EmscriptenData<'a> {
pub fn new(
instance: &'a mut Instance,
mapped_dirs: HashMap<String, PathBuf>,
) -> EmscriptenData<'a> {
let malloc = instance.func("_malloc").unwrap();
let free = instance.func("_free").unwrap();
let memalign = instance.func("_memalign").ok();
Expand Down Expand Up @@ -272,6 +278,7 @@ impl<'a> EmscriptenData<'a> {
stack_save,
stack_restore,
set_threw,
mapped_dirs,
}
}
}
Expand All @@ -282,8 +289,9 @@ pub fn run_emscripten_instance(
path: &str,
args: Vec<&str>,
entrypoint: Option<String>,
mapped_dirs: Vec<(String, PathBuf)>,
) -> CallResult<()> {
let mut data = EmscriptenData::new(instance);
let mut data = EmscriptenData::new(instance, mapped_dirs.into_iter().collect());
let data_ptr = &mut data as *mut _ as *mut c_void;
instance.context_mut().data = data_ptr;

Expand Down
50 changes: 31 additions & 19 deletions lib/emscripten/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ pub use self::unix::*;
#[cfg(windows)]
pub use self::windows::*;

use super::utils::copy_stat_into_wasm;
use crate::utils::{copy_stat_into_wasm, get_cstr_path, get_current_directory};

use super::varargs::VarArgs;
use byteorder::{ByteOrder, LittleEndian};
/// NOTE: TODO: These syscalls only support wasm_32 for now because they assume offsets are u32
Expand Down Expand Up @@ -95,12 +96,16 @@ pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
pub fn ___syscall12(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall12 (chdir) {}", _which);
let path_ptr = varargs.get_str(ctx);
unsafe {
let _path = std::ffi::CStr::from_ptr(path_ptr);
let ret = chdir(path_ptr);
debug!("=> path: {:?}, ret: {}", _path, ret);
let real_path = get_cstr_path(ctx, path_ptr)
.map(|cstr| cstr.as_c_str() as *const _ as *const i8)
.unwrap_or(path_ptr);
let ret = unsafe { chdir(real_path) };
debug!(
"=> path: {:?}, ret: {}",
unsafe { std::ffi::CStr::from_ptr(real_path) },
ret
}
);
ret
}

pub fn ___syscall10(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
Expand All @@ -124,11 +129,17 @@ pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall38 (rename)");
let old_path = varargs.get_str(ctx);
let new_path = varargs.get_str(ctx);
let result = unsafe { rename(old_path, new_path) };
let real_old_path = get_cstr_path(ctx, old_path)
.map(|cstr| cstr.as_c_str() as *const _ as *const i8)
.unwrap_or(old_path);
let real_new_path = get_cstr_path(ctx, new_path)
.map(|cstr| cstr.as_c_str() as *const _ as *const i8)
.unwrap_or(new_path);
let result = unsafe { rename(real_old_path, real_new_path) };
debug!(
"=> old_path: {}, new_path: {}, result: {}",
unsafe { std::ffi::CStr::from_ptr(old_path).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(new_path).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(real_old_path).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(real_new_path).to_str().unwrap() },
result
);
result
Expand All @@ -138,7 +149,10 @@ pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
pub fn ___syscall40(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall40 (rmdir)");
let pathname_addr = varargs.get_str(ctx);
unsafe { rmdir(pathname_addr) }
let real_path = get_cstr_path(ctx, pathname_addr)
.map(|cstr| cstr.as_c_str() as *const _ as *const i8)
.unwrap_or(pathname_addr);
unsafe { rmdir(real_path) }
}

// pipe
Expand Down Expand Up @@ -244,10 +258,9 @@ pub fn ___syscall110(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
// getcwd
pub fn ___syscall183(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall183");
use std::env;
let buf_offset: c_int = varargs.get(ctx);
let _size: c_int = varargs.get(ctx);
let path = env::current_dir();
let path = get_current_directory(ctx);
let path_string = path.unwrap().display().to_string();
let len = path_string.len();
unsafe {
Expand Down Expand Up @@ -420,9 +433,13 @@ pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
let pathname_addr = varargs.get_str(ctx);
let buf: u32 = varargs.get(ctx);

let real_path = get_cstr_path(ctx, pathname_addr)
.map(|cstr| cstr.as_c_str() as *const _ as *const i8)
.unwrap_or(pathname_addr);

unsafe {
let mut _stat: stat = std::mem::zeroed();
let ret = stat(pathname_addr, &mut _stat);
let ret = stat(real_path, &mut _stat);
debug!(
"=> pathname: {}, buf: {} = {}, last os error: {}",
std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap(),
Expand Down Expand Up @@ -457,11 +474,6 @@ pub fn ___syscall197(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
0
}

pub fn ___syscall220(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall220");
-1
}

// fcntl64
pub fn ___syscall221(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall221 (fcntl64) {}", _which);
Expand All @@ -474,7 +486,7 @@ pub fn ___syscall221(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
// |FNONBLOCK - 0x04
debug!("=> fd: {}, cmd: {}", _fd, cmd);
match cmd {
2 => 0,
1 | 2 => 0,
13 | 14 => 0, // pretend file locking worked
_ => -1,
}
Expand Down
59 changes: 54 additions & 5 deletions lib/emscripten/src/syscalls/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ use libc::{
pid_t,
pread,
pwrite,
readdir,
// readv,
recvfrom,
recvmsg,
Expand Down Expand Up @@ -107,8 +108,11 @@ pub fn ___syscall5(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
let pathname_addr = varargs.get_str(ctx);
let flags: i32 = varargs.get(ctx);
let mode: u32 = varargs.get(ctx);
let _path_str = unsafe { std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap() };
let fd = unsafe { open(pathname_addr, flags, mode) };
let real_path = utils::get_cstr_path(ctx, pathname_addr)
.map(|cstr| cstr.as_c_str() as *const _ as *const i8)
.unwrap_or(pathname_addr);
let _path_str = unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() };
let fd = unsafe { open(real_path, flags, mode) };
debug!(
"=> path: {}, flags: {}, mode: {} = fd: {}, last os error: {}",
_path_str,
Expand Down Expand Up @@ -154,11 +158,17 @@ pub fn ___syscall83(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int

let path1 = varargs.get_str(ctx);
let path2 = varargs.get_str(ctx);
let result = unsafe { symlink(path1, path2) };
let real_path1 = utils::get_cstr_path(ctx, path1)
.map(|cstr| cstr.as_c_str() as *const _ as *const i8)
.unwrap_or(path1);
let real_path2 = utils::get_cstr_path(ctx, path2)
.map(|cstr| cstr.as_c_str() as *const _ as *const i8)
.unwrap_or(path2);
let result = unsafe { symlink(real_path1, real_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() },
unsafe { std::ffi::CStr::from_ptr(real_path1).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(real_path2).to_str().unwrap() },
result,
);
result
Expand Down Expand Up @@ -784,6 +794,45 @@ pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
0
}

// getdents
// dirent structure is
// i64, i64, u16 (280), i8, [i8; 256]
pub fn ___syscall220(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall220");
let fd: i32 = varargs.get(ctx);
let dirp_addr: i32 = varargs.get(ctx);
let count: u32 = varargs.get(ctx);

let dirp = emscripten_memory_pointer!(ctx.memory(0), dirp_addr) as *mut u8;
// need to persist stream across calls?
let dir: *mut libc::DIR = unsafe { libc::fdopendir(fd) };

let mut pos = 0;
let offset = 280;
while pos + offset <= count as usize {
let dirent = unsafe { readdir(dir) };
if dirent.is_null() {
break;
}
#[allow(clippy::cast_ptr_alignment)]
unsafe {
*(dirp.add(pos) as *mut u64) = (*dirent).d_ino;
*(dirp.add(pos + 8) as *mut u64) = pos as u64 + offset as u64;
*(dirp.add(pos + 16) as *mut u16) = offset as u16;
*(dirp.add(pos + 18) as *mut u8) = (*dirent).d_type;
let upper_bound = std::cmp::min((*dirent).d_reclen, 254) as usize;
let mut i = 0;
while i < upper_bound {
*(dirp.add(pos + 19 + i) as *mut i8) = (*dirent).d_name[i];
i += 1;
}
*(dirp.add(pos + 19 + i) as *mut i8) = 0 as i8;
}
pos += offset;
}
pos as i32
}

/// fallocate
pub fn ___syscall324(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall324 (fallocate) {}", _which);
Expand Down
6 changes: 6 additions & 0 deletions lib/emscripten/src/syscalls/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,12 @@ pub fn ___syscall196(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
-1
}

// getdents
pub fn ___syscall220(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall220");
-1
}

/// fchown
pub fn ___syscall207(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall207 (fchown) {}", _which);
Expand Down
32 changes: 32 additions & 0 deletions lib/emscripten/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use libc::stat;
use std::ffi::CStr;
use std::mem::size_of;
use std::os::raw::c_char;
use std::path::PathBuf;
use std::slice;
use wasmer_runtime_core::memory::Memory;
use wasmer_runtime_core::{
Expand Down Expand Up @@ -204,6 +205,37 @@ pub fn read_string_from_wasm(memory: &Memory, offset: u32) -> String {
String::from_utf8_lossy(&v).to_owned().to_string()
}

/// This function trys to find an entry in mapdir
/// translating paths into their correct value
pub fn get_cstr_path(ctx: &mut Ctx, path: *const i8) -> Option<std::ffi::CString> {
let path_str = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }.to_string();
if let Some(val) = get_emscripten_data(ctx).mapped_dirs.get(&path_str) {
std::ffi::CString::new(val.to_string_lossy().as_bytes()).ok()
} else {
None
}
}

/// gets the current directory
/// handles mapdir logic
pub fn get_current_directory(ctx: &mut Ctx) -> Option<PathBuf> {
if let Some(val) = get_emscripten_data(ctx).mapped_dirs.get(".") {
return Some(val.clone());
}
std::env::current_dir()
.map(|cwd| {
if let Some(val) = get_emscripten_data(ctx)
.mapped_dirs
.get(&cwd.to_string_lossy().to_string())
{
val.clone()
} else {
cwd
}
})
.ok()
}

#[cfg(test)]
mod tests {
use super::is_emscripten_module;
Expand Down
1 change: 1 addition & 0 deletions src/bin/wasmer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
},
options.args.iter().map(|arg| arg.as_str()).collect(),
options.em_entrypoint.clone(),
mapped_dirs,
)
.map_err(|e| format!("{:?}", e))?;
} else {
Expand Down