diff --git a/src/apis/emscripten/env.rs b/src/apis/emscripten/env.rs index 9ae2d9de5..623de1191 100644 --- a/src/apis/emscripten/env.rs +++ b/src/apis/emscripten/env.rs @@ -1,8 +1,9 @@ use super::super::host; /// NOTE: These syscalls only support wasm_32 for now because they take u32 offset -use libc::{c_int}; +use libc::{c_int, getpwnam as libc_getpwnam, passwd, getgrnam as libc_getgrnam, group}; use std::ffi::CStr; use std::os::raw::c_char; +use std::{slice, mem}; use crate::webassembly::Instance; @@ -20,3 +21,94 @@ pub extern "C" fn _getenv(name_ptr: c_int, instance: &mut Instance) -> c_int { Err(_) => 0, } } + +unsafe fn copy_cstr_into_wasm(instance: &mut Instance, cstr: *const c_char) -> u32 { + let s = CStr::from_ptr(cstr).to_str().unwrap(); + let space_offset = (instance.emscripten_data.malloc)(s.len() as _, instance); + let raw_memory = instance.memory_offset_addr(0, space_offset as _) as *mut u8; + let mut slice = slice::from_raw_parts_mut(raw_memory, s.len()); + + for (byte, loc) in s.bytes().zip(slice.iter_mut()) { + *loc = byte; + } + + space_offset +} + +unsafe fn copy_terminated_array_of_cstrs(instance: &mut Instance, 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 + }; + println!("total_num: {}", total_num); + 0 +} + +pub extern "C" fn _getpwnam(name_ptr: c_int, instance: &mut Instance) -> c_int { + #[repr(C)] + struct GuestPasswd { + pw_name: u32, + pw_passwd: u32, + pw_uid: u32, + pw_gid: u32, + pw_gecos: u32, + pw_dir: u32, + pw_shell: u32, + } + + debug!("emscripten::_getpwnam {}", name_ptr); + let name = unsafe { + let memory_name_ptr = instance.memory_offset_addr(0, name_ptr as usize) as *const c_char; + CStr::from_ptr(memory_name_ptr) + }; + + unsafe { + let passwd = &*libc_getpwnam(name.as_ptr()); + let passwd_struct_offset = (instance.emscripten_data.malloc)(mem::size_of::() as _, instance); + + let passwd_struct_ptr = instance.memory_offset_addr(0, passwd_struct_offset as _) as *mut GuestPasswd; + (*passwd_struct_ptr).pw_name = copy_cstr_into_wasm(instance, passwd.pw_name); + (*passwd_struct_ptr).pw_passwd = copy_cstr_into_wasm(instance, passwd.pw_passwd); + (*passwd_struct_ptr).pw_gecos = copy_cstr_into_wasm(instance, passwd.pw_gecos); + (*passwd_struct_ptr).pw_dir = copy_cstr_into_wasm(instance, passwd.pw_dir); + (*passwd_struct_ptr).pw_shell = copy_cstr_into_wasm(instance, passwd.pw_shell); + (*passwd_struct_ptr).pw_uid = passwd.pw_uid; + (*passwd_struct_ptr).pw_gid = passwd.pw_gid; + + passwd_struct_offset as c_int + } +} + +pub extern "C" fn _getgrnam(name_ptr: c_int, instance: &mut Instance) -> c_int { + #[repr(C)] + struct GuestGroup { + gr_name: u32, + gr_passwd: u32, + gr_gid: u32, + gr_mem: u32, + } + + debug!("emscripten::_getgrnam {}", name_ptr); + let name = unsafe { + let memory_name_ptr = instance.memory_offset_addr(0, name_ptr as usize) as *const c_char; + CStr::from_ptr(memory_name_ptr) + }; + + unsafe { + let group = &*libc_getgrnam(name.as_ptr()); + let group_struct_offset = (instance.emscripten_data.malloc)(mem::size_of::() as _, instance); + + let group_struct_ptr = instance.memory_offset_addr(0, group_struct_offset as _) as *mut GuestGroup; + (*group_struct_ptr).gr_name = copy_cstr_into_wasm(instance, group.gr_name); + (*group_struct_ptr).gr_passwd = copy_cstr_into_wasm(instance, group.gr_passwd); + (*group_struct_ptr).gr_gid = group.gr_gid; + (*group_struct_ptr).gr_mem = copy_terminated_array_of_cstrs(instance, group.gr_mem); + + group_struct_offset as c_int + } +} \ No newline at end of file diff --git a/src/apis/emscripten/mod.rs b/src/apis/emscripten/mod.rs index 51120a7f5..3b5a5f218 100644 --- a/src/apis/emscripten/mod.rs +++ b/src/apis/emscripten/mod.rs @@ -258,6 +258,19 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { "nullFunc_viiii", ImportValue::Func(nullfunc::nullfunc_viiii as *const u8), ); + + // named syscalls + import_object.set( + "env", + "_getpwnam", + ImportValue::Func(env::_getpwnam as _), + ); + // import_object.set( + // "env", + // "_getgrnam", + // ImportValue::Func(env::_getgrnam as _), + // ); + import_object } diff --git a/src/webassembly/instance.rs b/src/webassembly/instance.rs index aec3ca8a3..1c9667cc3 100644 --- a/src/webassembly/instance.rs +++ b/src/webassembly/instance.rs @@ -18,7 +18,7 @@ use std::iter::FromIterator; use std::iter::Iterator; use std::mem::size_of; use std::ptr::write_unaligned; -use std::slice; +use std::{fmt, slice, mem}; use std::sync::Arc; use super::super::common::slice::{BoundedSlice, UncheckedSlice}; @@ -68,6 +68,20 @@ fn get_function_addr( func_pointer } +pub struct EmscriptenData { + pub malloc: extern fn(i32, &mut Instance) -> u32, + pub free: extern fn(i32, &mut Instance), +} + +impl fmt::Debug for EmscriptenData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("EmscriptenData") + .field("malloc", &(self.malloc as usize)) + .field("free", &(self.free as usize)) + .finish() + } +} + /// An Instance of a WebAssembly module /// NOTE: There is an assumption that data_pointers is always the /// first field @@ -98,6 +112,7 @@ pub struct Instance { pub start_func: Option, // Region start memory location // code_base: *const (), + pub emscripten_data: EmscriptenData, } /// Contains pointers to data (heaps, globals, tables) needed @@ -494,6 +509,27 @@ impl Instance { tables: tables_pointer[..].into(), }; + let emscripten_data = unsafe { + let malloc_index = if let Some(Export::Function(index)) = module.info.exports.get("_malloc") { + index + } else { + panic!("Unable to find _malloc export") + }; + let malloc_addr = get_function_addr(&malloc_index, &import_functions, &functions); + + let free_index = if let Some(Export::Function(index)) = module.info.exports.get("_free") { + index + } else { + panic!("Unable to find _free export") + }; + let free_addr = get_function_addr(&free_index, &import_functions, &functions); + + EmscriptenData { + malloc: mem::transmute(malloc_addr), + free: mem::transmute(free_addr), + } + }; + Ok(Instance { data_pointers, tables: Arc::new(tables.into_iter().collect()), // tables.into_iter().map(|table| RwLock::new(table)).collect()), @@ -502,7 +538,7 @@ impl Instance { functions, import_functions, start_func, - // emscripten_data, + emscripten_data, }) }