mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-16 16:20:49 +00:00
Merge #422
422: Improved Emscripten debugging + optipng r=syrusakbary a=MarkMcCaskey Improved Emscripten debugging + optipng Co-authored-by: Mark McCaskey <mark@wasmer.io> Co-authored-by: Syrus <me@syrusakbary.com>
This commit is contained in:
commit
89b92e3305
@ -5,6 +5,7 @@ All PRs to the Wasmer repository must add to this file.
|
||||
Blocks of changes will separated by version increments.
|
||||
|
||||
## **[Unreleased]**
|
||||
- [#422](https://github.com/wasmerio/wasmer/pull/422) Improved Emscripten functions to run optipng and pngquant compiled to wasm
|
||||
- [#409](https://github.com/wasmerio/wasmer/pull/409) Improved Emscripten functions to run JavascriptCore compiled to wasm
|
||||
- [#399](https://github.com/wasmerio/wasmer/pull/399) Add example of using a plugin extended from WASI
|
||||
- [#397](https://github.com/wasmerio/wasmer/pull/397) Fix WASI fs abstraction to work on Windows
|
||||
|
@ -43,7 +43,8 @@ rustc_version = "0.2.3"
|
||||
|
||||
[features]
|
||||
default = ["fast-tests", "wasi"]
|
||||
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||
debug = ["wasmer-runtime-core/debug"]
|
||||
extra-debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||
# This feature will allow cargo test to run much faster
|
||||
fast-tests = []
|
||||
"backend:llvm" = ["wasmer-llvm-backend"]
|
||||
|
3
Makefile
3
Makefile
@ -84,5 +84,8 @@ production-release:
|
||||
debug-release:
|
||||
cargo build --release --features "debug"
|
||||
|
||||
extra-debug-release:
|
||||
cargo build --release --features "extra-debug"
|
||||
|
||||
publish-release:
|
||||
ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION} ./artifacts/
|
||||
|
9
examples/README.md
Normal file
9
examples/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
# WebAssembly Examples
|
||||
|
||||
In this directory you can find a set of different examples that can run on the Wasmer WebAssembly runtime:
|
||||
|
||||
* Cowsay (WASI ABI) [[source-code](https://github.com/wapm-packages/cowsay)] [[wapm-package](https://wapm.io/package/cowsay)]
|
||||
* Nginx (Emscripten ABI) [[source-code](https://github.com/wapm-packages/nginx)] [[wapm-package](https://wapm.io/package/nginx)]
|
||||
* Lua (Emscripten ABI) [[source-code](https://github.com/wapm-packages/lua)] [[wapm-package](https://wapm.io/package/lua)]
|
||||
* PHP (Emscripten ABI) [[source-code](https://github.com/wapm-packages/php)] [[wapm-package](https://wapm.io/package/php)]
|
||||
* SQLite (Emscripten ABI) [[source-code](https://github.com/wapm-packages/sqlite)] [[wapm-package](https://wapm.io/package/sqlite)]
|
@ -55,7 +55,7 @@ pub fn _dladdr(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
|
||||
0
|
||||
}
|
||||
pub fn _pthread_attr_init(_ctx: &mut Ctx, _a: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_attr_init");
|
||||
debug!("emscripten::_pthread_attr_init({})", _a);
|
||||
0
|
||||
}
|
||||
pub fn _pthread_attr_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
|
||||
@ -68,7 +68,10 @@ pub fn _pthread_attr_getstack(
|
||||
_stacksize: i32,
|
||||
_other: i32,
|
||||
) -> i32 {
|
||||
debug!("emscripten::_pthread_attr_getstack");
|
||||
debug!(
|
||||
"emscripten::_pthread_attr_getstack({}, {}, {})",
|
||||
_stackaddr, _stacksize, _other
|
||||
);
|
||||
// TODO: Translate from Emscripten
|
||||
// HEAP32[stackaddr >> 2] = STACK_BASE;
|
||||
// HEAP32[stacksize >> 2] = TOTAL_STACK;
|
||||
@ -87,7 +90,7 @@ pub fn _pthread_getspecific(_ctx: &mut Ctx, _a: i32) -> i32 {
|
||||
0
|
||||
}
|
||||
pub fn _pthread_getattr_np(_ctx: &mut Ctx, _thread: i32, _attr: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_getattr_np");
|
||||
debug!("emscripten::_pthread_getattr_np({}, {})", _thread, _attr);
|
||||
0
|
||||
}
|
||||
pub fn _pthread_setspecific(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
|
||||
@ -732,6 +735,10 @@ pub fn invoke_vj(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) {
|
||||
panic!("dyn_call_vj is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_vjji(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
|
||||
debug!("emscripten::invoke_vjji");
|
||||
invoke_no_return!(ctx, dyn_call_vjji, index, a1, a2, a3, a4, a5)
|
||||
}
|
||||
pub fn invoke_vij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) {
|
||||
debug!("emscripten::invoke_vij");
|
||||
if let Some(dyn_call_vij) = &get_emscripten_data(ctx).dyn_call_vij {
|
||||
|
42
lib/emscripten/src/env/mod.rs
vendored
42
lib/emscripten/src/env/mod.rs
vendored
@ -60,21 +60,51 @@ pub fn ___build_environment(ctx: &mut Ctx, environ: c_int) {
|
||||
const MAX_ENV_VALUES: u32 = 64;
|
||||
const TOTAL_ENV_SIZE: u32 = 1024;
|
||||
let environment = emscripten_memory_pointer!(ctx.memory(0), environ) as *mut c_int;
|
||||
unsafe {
|
||||
let (mut pool_offset, env_ptr, mut pool_ptr) = unsafe {
|
||||
let (pool_offset, _pool_slice): (u32, &mut [u8]) =
|
||||
allocate_on_stack(ctx, TOTAL_ENV_SIZE as u32);
|
||||
let (env_offset, _env_slice): (u32, &mut [u8]) =
|
||||
allocate_on_stack(ctx, (MAX_ENV_VALUES * 4) as u32);
|
||||
let env_ptr = emscripten_memory_pointer!(ctx.memory(0), env_offset) as *mut c_int;
|
||||
let mut _pool_ptr = emscripten_memory_pointer!(ctx.memory(0), pool_offset) as *mut c_int;
|
||||
let pool_ptr = emscripten_memory_pointer!(ctx.memory(0), pool_offset) as *mut u8;
|
||||
*env_ptr = pool_offset as i32;
|
||||
*environment = env_offset as i32;
|
||||
|
||||
// *env_ptr = 0;
|
||||
(pool_offset, env_ptr, pool_ptr)
|
||||
};
|
||||
// unsafe {
|
||||
// *env_ptr = 0;
|
||||
// };
|
||||
|
||||
// *env_ptr = 0;
|
||||
let default_vars = vec![
|
||||
["USER", "web_user"],
|
||||
["LOGNAME", "web_user"],
|
||||
["PATH", "/"],
|
||||
["PWD", "/"],
|
||||
["HOME", "/home/web_user"],
|
||||
["LANG", "C.UTF-8"],
|
||||
["_", "thisProgram"],
|
||||
];
|
||||
let mut strings = vec![];
|
||||
let mut total_size = 0;
|
||||
for [key, val] in &default_vars {
|
||||
let line = key.to_string() + "=" + val;
|
||||
total_size += line.len();
|
||||
strings.push(line);
|
||||
}
|
||||
if total_size as u32 > TOTAL_ENV_SIZE {
|
||||
panic!("Environment size exceeded TOTAL_ENV_SIZE!");
|
||||
}
|
||||
unsafe {
|
||||
for (i, s) in strings.iter().enumerate() {
|
||||
for (j, c) in s.chars().enumerate() {
|
||||
debug_assert!(c < u8::max_value() as char);
|
||||
*pool_ptr.add(j) = c as u8;
|
||||
}
|
||||
*env_ptr.add(i * 4) = pool_offset as i32;
|
||||
pool_offset += s.len() as u32 + 1;
|
||||
pool_ptr = pool_ptr.add(s.len() + 1);
|
||||
}
|
||||
*env_ptr.add(strings.len() * 4) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ___assert_fail(_ctx: &mut Ctx, _a: c_int, _b: c_int, _c: c_int, _d: c_int) {
|
||||
|
@ -7,7 +7,7 @@ use wasmer_runtime_core::vm::Ctx;
|
||||
/// setjmp
|
||||
pub fn __setjmp(ctx: &mut Ctx, _env_addr: u32) -> c_int {
|
||||
debug!("emscripten::__setjmp (setjmp)");
|
||||
abort_with_message(ctx, "missing function: _longjmp");
|
||||
abort_with_message(ctx, "missing function: _setjmp");
|
||||
unreachable!()
|
||||
// unsafe {
|
||||
// // Rather than using the env as the holder of the jump buffer pointer,
|
||||
|
@ -127,6 +127,7 @@ pub struct EmscriptenData<'a> {
|
||||
pub dyn_call_viijiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32)>>,
|
||||
pub dyn_call_viijj: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32)>>,
|
||||
pub dyn_call_vj: Option<Func<'a, (i32, i32, i32)>>,
|
||||
pub dyn_call_vjji: Option<Func<'a, (i32, i32, i32, i32, i32, i32)>>,
|
||||
pub dyn_call_vij: Option<Func<'a, (i32, i32, i32, i32)>>,
|
||||
pub dyn_call_viji: Option<Func<'a, (i32, i32, i32, i32, i32)>>,
|
||||
pub dyn_call_vijiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32)>>,
|
||||
@ -146,11 +147,7 @@ impl<'a> EmscriptenData<'a> {
|
||||
pub fn new(instance: &'a mut Instance) -> EmscriptenData<'a> {
|
||||
let malloc = instance.func("_malloc").unwrap();
|
||||
let free = instance.func("_free").unwrap();
|
||||
let memalign = if let Ok(func) = instance.func("_memalign") {
|
||||
Some(func)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let memalign = instance.func("_memalign").ok();
|
||||
let memset = instance.func("_memset").unwrap();
|
||||
let stack_alloc = instance.func("stackAlloc").unwrap();
|
||||
|
||||
@ -198,6 +195,7 @@ impl<'a> EmscriptenData<'a> {
|
||||
let dyn_call_viijiii = instance.func("dynCall_viijiii").ok();
|
||||
let dyn_call_viijj = instance.func("dynCall_viijj").ok();
|
||||
let dyn_call_vj = instance.func("dynCall_vj").ok();
|
||||
let dyn_call_vjji = instance.func("dynCall_vjji").ok();
|
||||
let dyn_call_vij = instance.func("dynCall_vij").ok();
|
||||
let dyn_call_viji = instance.func("dynCall_viji").ok();
|
||||
let dyn_call_vijiii = instance.func("dynCall_vijiii").ok();
|
||||
@ -261,6 +259,7 @@ impl<'a> EmscriptenData<'a> {
|
||||
dyn_call_viijiii,
|
||||
dyn_call_viijj,
|
||||
dyn_call_vj,
|
||||
dyn_call_vjji,
|
||||
dyn_call_vij,
|
||||
dyn_call_viji,
|
||||
dyn_call_vijiii,
|
||||
@ -282,6 +281,7 @@ pub fn run_emscripten_instance(
|
||||
instance: &mut Instance,
|
||||
path: &str,
|
||||
args: Vec<&str>,
|
||||
entrypoint: Option<String>,
|
||||
) -> CallResult<()> {
|
||||
let mut data = EmscriptenData::new(instance);
|
||||
let data_ptr = &mut data as *mut _ as *mut c_void;
|
||||
@ -299,45 +299,54 @@ pub fn run_emscripten_instance(
|
||||
|
||||
// println!("running emscripten instance");
|
||||
|
||||
let main_func = instance.dyn_func("_main")?;
|
||||
let num_params = main_func.signature().params().len();
|
||||
let _result = match num_params {
|
||||
2 => {
|
||||
let (argc, argv) = store_module_arguments(instance.context_mut(), path, args);
|
||||
instance.call("_main", &[Value::I32(argc as i32), Value::I32(argv as i32)])?;
|
||||
}
|
||||
0 => {
|
||||
instance.call("_main", &[])?;
|
||||
}
|
||||
_ => panic!(
|
||||
"The emscripten main function has received an incorrect number of params {}",
|
||||
num_params
|
||||
),
|
||||
};
|
||||
if let Some(ep) = entrypoint {
|
||||
debug!("Running entry point: {}", &ep);
|
||||
let ep_fn = instance.dyn_func(&ep)?;
|
||||
let arg = unsafe { allocate_cstr_on_stack(instance.context_mut(), args[0]).0 };
|
||||
//let (argc, argv) = store_module_arguments(instance.context_mut(), args);
|
||||
instance.call(&ep, &[Value::I32(arg as i32)])?;
|
||||
} else {
|
||||
let main_func = instance.dyn_func("_main")?;
|
||||
let num_params = main_func.signature().params().len();
|
||||
let _result = match num_params {
|
||||
2 => {
|
||||
let mut new_args = vec![path];
|
||||
new_args.extend(args);
|
||||
let (argc, argv) = store_module_arguments(instance.context_mut(), new_args);
|
||||
instance.call("_main", &[Value::I32(argc as i32), Value::I32(argv as i32)])?;
|
||||
}
|
||||
0 => {
|
||||
instance.call("_main", &[])?;
|
||||
}
|
||||
_ => panic!(
|
||||
"The emscripten main function has received an incorrect number of params {}",
|
||||
num_params
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
// TODO atexit for emscripten
|
||||
// println!("{:?}", data);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn store_module_arguments(ctx: &mut Ctx, path: &str, args: Vec<&str>) -> (u32, u32) {
|
||||
fn store_module_arguments(ctx: &mut Ctx, args: Vec<&str>) -> (u32, u32) {
|
||||
let argc = args.len() + 1;
|
||||
|
||||
let mut args_slice = vec![0; argc];
|
||||
args_slice[0] = unsafe { allocate_cstr_on_stack(ctx, path).0 };
|
||||
for (slot, arg) in args_slice[1..argc].iter_mut().zip(args.iter()) {
|
||||
for (slot, arg) in args_slice[0..argc].iter_mut().zip(args.iter()) {
|
||||
*slot = unsafe { allocate_cstr_on_stack(ctx, &arg).0 };
|
||||
}
|
||||
|
||||
let (argv_offset, argv_slice): (_, &mut [u32]) =
|
||||
unsafe { allocate_on_stack(ctx, ((argc + 1) * 4) as u32) };
|
||||
unsafe { allocate_on_stack(ctx, ((argc) * 4) as u32) };
|
||||
assert!(!argv_slice.is_empty());
|
||||
for (slot, arg) in argv_slice[0..argc].iter_mut().zip(args_slice.iter()) {
|
||||
*slot = *arg
|
||||
}
|
||||
argv_slice[argc] = 0;
|
||||
|
||||
(argc as u32, argv_offset)
|
||||
(argc as u32 - 1, argv_offset)
|
||||
}
|
||||
|
||||
pub fn emscripten_set_up_memory(memory: &Memory, globals: &EmscriptenGlobalsData) {
|
||||
@ -597,6 +606,7 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
|
||||
"___syscall272" => func!(crate::syscalls::___syscall272),
|
||||
"___syscall295" => func!(crate::syscalls::___syscall295),
|
||||
"___syscall300" => func!(crate::syscalls::___syscall300),
|
||||
"___syscall320" => func!(crate::syscalls::___syscall320),
|
||||
"___syscall324" => func!(crate::syscalls::___syscall324),
|
||||
"___syscall330" => func!(crate::syscalls::___syscall330),
|
||||
"___syscall334" => func!(crate::syscalls::___syscall334),
|
||||
@ -718,6 +728,7 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
|
||||
"invoke_v" => func!(crate::emscripten_target::invoke_v),
|
||||
"invoke_vi" => func!(crate::emscripten_target::invoke_vi),
|
||||
"invoke_vj" => func!(crate::emscripten_target::invoke_vj),
|
||||
"invoke_vjji" => func!(crate::emscripten_target::invoke_vjji),
|
||||
"invoke_vii" => func!(crate::emscripten_target::invoke_vii),
|
||||
"invoke_viii" => func!(crate::emscripten_target::invoke_viii),
|
||||
"invoke_viiii" => func!(crate::emscripten_target::invoke_viiii),
|
||||
|
@ -21,8 +21,11 @@ pub fn _emscripten_memcpy_big(ctx: &mut Ctx, dest: u32, src: u32, len: u32) -> u
|
||||
|
||||
/// emscripten: _emscripten_get_heap_size
|
||||
pub fn _emscripten_get_heap_size(ctx: &mut Ctx) -> u32 {
|
||||
debug!("emscripten::_emscripten_get_heap_size",);
|
||||
ctx.memory(0).size().bytes().0 as u32
|
||||
debug!("emscripten::_emscripten_get_heap_size");
|
||||
let result = ctx.memory(0).size().bytes().0 as u32;
|
||||
debug!("=> {}", result);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
// From emscripten implementation
|
||||
|
@ -82,7 +82,7 @@ pub fn _raise(_ctx: &mut Ctx, _one: i32) -> i32 {
|
||||
}
|
||||
|
||||
pub fn _sem_init(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
|
||||
debug!("emscripten::_sem_init");
|
||||
debug!("emscripten::_sem_init: {}, {}, {}", _one, _two, _three);
|
||||
0
|
||||
}
|
||||
|
||||
|
@ -31,12 +31,13 @@ use libc::{
|
||||
off_t,
|
||||
// open,
|
||||
read,
|
||||
rename,
|
||||
// sockaddr_in,
|
||||
// readv,
|
||||
rmdir,
|
||||
// writev,
|
||||
stat,
|
||||
write,
|
||||
// sockaddr_in,
|
||||
};
|
||||
use wasmer_runtime_core::vm::Ctx;
|
||||
|
||||
@ -118,9 +119,23 @@ pub fn ___syscall20(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
|
||||
unsafe { getpid() }
|
||||
}
|
||||
|
||||
pub fn ___syscall38(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
|
||||
debug!("emscripten::___syscall38");
|
||||
-1
|
||||
// rename
|
||||
pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
|
||||
debug!("emscripten::___syscall38 (rename)");
|
||||
let old_path_addr: u32 = varargs.get(ctx);
|
||||
let new_path_addr: u32 = varargs.get(ctx);
|
||||
let old_path = emscripten_memory_pointer!(ctx.memory(0), old_path_addr) as *const i8;
|
||||
let new_path = emscripten_memory_pointer!(ctx.memory(0), new_path_addr) as *const i8;
|
||||
let result = unsafe { rename(old_path, new_path) };
|
||||
unsafe {
|
||||
debug!(
|
||||
"=> old_path: {}, new_path: {}, result: {}",
|
||||
std::ffi::CStr::from_ptr(old_path).to_str().unwrap(),
|
||||
std::ffi::CStr::from_ptr(new_path).to_str().unwrap(),
|
||||
result
|
||||
);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
// rmdir
|
||||
@ -246,12 +261,22 @@ pub fn ___syscall192(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
if fd == -1 {
|
||||
let ptr = env::call_memalign(ctx, 16384, len);
|
||||
if ptr == 0 {
|
||||
return -1;
|
||||
// ENOMEM
|
||||
return -12;
|
||||
}
|
||||
let real_ptr = emscripten_memory_pointer!(ctx.memory(0), ptr) as *const u8;
|
||||
env::call_memset(ctx, ptr, 0, len);
|
||||
ptr as _
|
||||
for i in 0..(len as usize) {
|
||||
unsafe {
|
||||
assert_eq!(*real_ptr.add(i), 0);
|
||||
}
|
||||
}
|
||||
debug!("=> ptr: {}", ptr);
|
||||
return ptr as i32;
|
||||
} else {
|
||||
-1
|
||||
unimplemented!("temp during dev");
|
||||
// return ENODEV
|
||||
return -19;
|
||||
}
|
||||
}
|
||||
|
||||
@ -461,6 +486,12 @@ pub fn ___syscall300(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
|
||||
-1
|
||||
}
|
||||
|
||||
// utimensat
|
||||
pub fn ___syscall320(ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int {
|
||||
debug!("emscripten::___syscall320 (utimensat), {}", _which);
|
||||
0
|
||||
}
|
||||
|
||||
pub fn ___syscall334(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
|
||||
debug!("emscripten::___syscall334");
|
||||
-1
|
||||
|
@ -251,8 +251,9 @@ pub fn ___syscall33(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
|
||||
let path = emscripten_memory_pointer!(ctx.memory(0), path_ptr) as *const i8;
|
||||
let result = unsafe { access(path, amode) };
|
||||
debug!(
|
||||
"=> path: {}, result: {}",
|
||||
"=> path: {}, amode: {}, result: {}",
|
||||
unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() },
|
||||
amode,
|
||||
result
|
||||
);
|
||||
result
|
||||
@ -354,8 +355,13 @@ 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!("fd: {}, op: {}", fd, request);
|
||||
debug!("=> fd: {}, op: {}", fd, request);
|
||||
// Got the equivalents here: https://code.woboq.org/linux/linux/include/uapi/asm-generic/ioctls.h.html
|
||||
// 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, request as _, argp_ptr) };
|
||||
// debug!("=> {}", ret);
|
||||
// ret
|
||||
match request as _ {
|
||||
21537 => {
|
||||
// FIONBIO
|
||||
|
@ -53,6 +53,7 @@ macro_rules! assert_emscripten_output {
|
||||
&mut instance,
|
||||
$name,
|
||||
$args,
|
||||
None,
|
||||
).expect("run_emscripten_instance finishes");
|
||||
|
||||
let output = capturer.end().unwrap().0;
|
||||
|
@ -86,6 +86,10 @@ struct Run {
|
||||
#[structopt(long = "em-symbol-map", parse(from_os_str), group = "emscripten")]
|
||||
em_symbol_map: Option<PathBuf>,
|
||||
|
||||
/// Begin execution at the specified symbol
|
||||
#[structopt(long = "em-entrypoint", group = "emscripten")]
|
||||
em_entrypoint: Option<String>,
|
||||
|
||||
/// WASI pre-opened directory
|
||||
#[structopt(long = "dir", multiple = true, group = "wasi")]
|
||||
pre_opened_directories: Vec<String>,
|
||||
@ -320,6 +324,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
||||
options.path.to_str().unwrap()
|
||||
},
|
||||
options.args.iter().map(|arg| arg.as_str()).collect(),
|
||||
options.em_entrypoint.clone(),
|
||||
)
|
||||
.map_err(|e| format!("{:?}", e))?;
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user