196 lines
6.0 KiB
Rust
Raw Normal View History

2019-01-10 21:37:59 -08:00
use super::env;
use super::env::get_emscripten_data;
2018-11-26 20:29:26 -08:00
use libc::stat;
2018-12-09 01:02:26 -06:00
use std::ffi::CStr;
use std::mem::size_of;
2018-11-26 22:15:49 +01:00
use std::os::raw::c_char;
use std::os::raw::c_int;
2018-11-26 20:28:13 -08:00
use std::slice;
use wasmer_runtime_core::memory::Memory;
use wasmer_runtime_core::{
module::Module,
structures::TypedIndex,
types::{ImportedMemoryIndex, ImportedTableIndex},
units::Pages,
vm::Ctx,
};
2019-01-24 15:30:13 -08:00
/// We check if a provided module is an Emscripten generated one
pub fn is_emscripten_module(module: &Module) -> bool {
for (_, import_name) in &module.0.info.imported_functions {
let namespace = module
.0
.info
.namespace_table
.get(import_name.namespace_index);
let field = module.0.info.name_table.get(import_name.name_index);
if field == "_emscripten_memcpy_big" && namespace == "env" {
2019-01-18 00:18:13 -06:00
return true;
}
}
false
}
pub fn get_emscripten_table_size(module: &Module) -> (u32, Option<u32>) {
let (_, table) = &module.0.info.imported_tables[ImportedTableIndex::new(0)];
(table.minimum, table.maximum)
}
pub fn get_emscripten_memory_size(module: &Module) -> (Pages, Option<Pages>) {
let (_, memory) = &module.0.info.imported_memories[ImportedMemoryIndex::new(0)];
(memory.minimum, memory.maximum)
}
pub unsafe fn write_to_buf(string: *const c_char, buf: u32, max: u32, ctx: &mut Ctx) -> u32 {
2019-01-24 13:04:12 -08:00
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_char;
2018-12-11 18:06:20 +01:00
2018-12-13 19:58:08 -06:00
for i in 0..max {
*buf_addr.add(i as _) = *string.add(i as _);
2018-12-11 18:06:20 +01:00
}
buf
}
2018-12-14 00:09:07 +01:00
/// This function expects nullbyte to be appended.
pub unsafe fn copy_cstr_into_wasm(ctx: &mut Ctx, cstr: *const c_char) -> u32 {
2018-12-07 04:08:17 +01:00
let s = CStr::from_ptr(cstr).to_str().unwrap();
let cstr_len = s.len();
let space_offset = env::call_malloc((cstr_len as u32) + 1, ctx);
let raw_memory = emscripten_memory_pointer!(ctx.memory(0), space_offset) as *mut c_char;
2018-12-07 04:08:17 +01:00
let slice = slice::from_raw_parts_mut(raw_memory, cstr_len);
for (byte, loc) in s.bytes().zip(slice.iter_mut()) {
*loc = byte as _;
2018-12-07 04:08:17 +01:00
}
2018-12-07 14:50:35 +01:00
// TODO: Appending null byte won't work, because there is CStr::from_ptr(cstr)
// at the top that crashes when there is no null byte
2018-12-07 04:08:17 +01:00
*raw_memory.add(cstr_len) = 0;
space_offset
}
pub unsafe fn allocate_on_stack<'a, T: Copy>(count: u32, ctx: &'a mut Ctx) -> (u32, &'a mut [T]) {
let offset = get_emscripten_data(ctx)
.stack_alloc
.call(count * (size_of::<T>() as u32))
.unwrap();
2019-01-24 13:04:12 -08:00
let addr = emscripten_memory_pointer!(ctx.memory(0), offset) as *mut T;
let slice = slice::from_raw_parts_mut(addr, count as usize);
(offset, slice)
2018-12-06 22:40:44 -05:00
}
pub unsafe fn allocate_cstr_on_stack<'a>(s: &str, ctx: &'a mut Ctx) -> (u32, &'a [u8]) {
let (offset, slice) = allocate_on_stack((s.len() + 1) as u32, ctx);
2018-12-06 22:40:44 -05:00
use std::iter;
for (byte, loc) in s.bytes().chain(iter::once(0)).zip(slice.iter_mut()) {
*loc = byte;
}
(offset, slice)
}
pub unsafe fn copy_terminated_array_of_cstrs(_ctx: &mut Ctx, cstrs: *mut *mut c_char) -> u32 {
2018-11-26 22:15:49 +01:00
let total_num = {
let mut ptr = cstrs;
let mut counter = 0;
while !(*ptr).is_null() {
counter += 1;
ptr = ptr.add(1);
}
counter
};
2018-11-26 20:29:26 -08:00
debug!(
"emscripten::copy_terminated_array_of_cstrs::total_num: {}",
total_num
);
2018-11-26 22:15:49 +01:00
0
}
#[repr(C)]
pub struct GuestStat {
2019-01-03 18:39:07 -08:00
st_dev: u32,
2018-12-31 09:31:23 -08:00
__st_dev_padding: u32,
__st_ino_truncated: u32,
st_mode: u32,
st_nlink: u32,
st_uid: u32,
st_gid: u32,
2018-12-31 09:31:23 -08:00
st_rdev: u32,
__st_rdev_padding: u32,
st_size: u32,
st_blksize: u32,
st_blocks: u32,
st_atime: u64,
st_mtime: u64,
st_ctime: u64,
2018-12-31 09:31:23 -08:00
st_ino: u64,
}
2019-01-18 00:33:46 -06:00
#[allow(clippy::cast_ptr_alignment)]
pub unsafe fn copy_stat_into_wasm(ctx: &mut Ctx, buf: u32, stat: &stat) {
2019-01-24 13:04:12 -08:00
let stat_ptr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut GuestStat;
(*stat_ptr).st_dev = stat.st_dev as _;
2018-12-31 09:31:23 -08:00
(*stat_ptr).__st_dev_padding = 0;
(*stat_ptr).__st_ino_truncated = stat.st_ino as _;
(*stat_ptr).st_mode = stat.st_mode as _;
(*stat_ptr).st_nlink = stat.st_nlink as _;
(*stat_ptr).st_uid = stat.st_uid as _;
(*stat_ptr).st_gid = stat.st_gid as _;
(*stat_ptr).st_rdev = stat.st_rdev as _;
2018-12-31 09:31:23 -08:00
(*stat_ptr).__st_rdev_padding = 0;
(*stat_ptr).st_size = stat.st_size as _;
2018-12-31 07:15:24 -08:00
(*stat_ptr).st_blksize = 4096;
#[cfg(not(target_os = "windows"))]
{
(*stat_ptr).st_blocks = stat.st_blocks as _;
}
2018-12-31 07:15:24 -08:00
#[cfg(target_os = "windows")]
{
(*stat_ptr).st_blocks = 0;
}
(*stat_ptr).st_atime = stat.st_atime as _;
(*stat_ptr).st_mtime = stat.st_mtime as _;
(*stat_ptr).st_ctime = stat.st_ctime as _;
2018-12-31 09:31:23 -08:00
(*stat_ptr).st_ino = stat.st_ino as _;
}
pub fn read_string_from_wasm(memory: &Memory, offset: u32) -> String {
memory.view::<u8>()[(offset as usize)..]
.iter()
.take_while(|cell| cell.get() != 0)
.map(|cell| cell.get() as char)
.collect()
}
#[cfg(test)]
mod tests {
2018-11-21 20:59:23 -08:00
use super::is_emscripten_module;
2019-01-18 01:25:05 +01:00
use std::sync::Arc;
2019-01-18 00:18:13 -06:00
use wabt::wat2wasm;
use wasmer_clif_backend::CraneliftCompiler;
2019-01-24 00:17:43 -06:00
use wasmer_runtime_core::compile_with;
#[test]
fn should_detect_emscripten_files() {
2019-01-24 00:05:07 -06:00
const WAST_BYTES: &[u8] = include_bytes!("tests/is_emscripten_true.wast");
let wasm_binary = wat2wasm(WAST_BYTES.to_vec()).expect("Can't convert to wasm");
2019-01-23 12:35:14 -08:00
let module = compile_with(&wasm_binary[..], &CraneliftCompiler::new())
.expect("WASM can't be compiled");
2019-01-18 01:25:05 +01:00
let module = Arc::new(module);
assert!(is_emscripten_module(&module));
}
#[test]
fn should_detect_non_emscripten_files() {
2019-01-24 00:05:07 -06:00
const WAST_BYTES: &[u8] = include_bytes!("tests/is_emscripten_false.wast");
let wasm_binary = wat2wasm(WAST_BYTES.to_vec()).expect("Can't convert to wasm");
2019-01-23 12:35:14 -08:00
let module = compile_with(&wasm_binary[..], &CraneliftCompiler::new())
.expect("WASM can't be compiled");
2019-01-18 01:25:05 +01:00
let module = Arc::new(module);
assert!(!is_emscripten_module(&module));
}
2018-11-21 20:59:23 -08:00
}