From 88589a9cbc08b14f0708463f4f9f1c77dff552fa Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Tue, 27 Nov 2018 19:10:43 -0500 Subject: [PATCH] Add sig* syscalls --- src/apis/emscripten/README.md | 2 +- src/apis/emscripten/mod.rs | 43 ++++++++++++++++++++++++++++----- src/apis/emscripten/process.rs | 26 ++++++++++++++++++++ src/apis/emscripten/syscalls.rs | 38 +++++++++++++++++++++++++++++ src/recovery.rs | 13 +++++++--- src/sighandler.rs | 7 +++--- 6 files changed, 115 insertions(+), 14 deletions(-) diff --git a/src/apis/emscripten/README.md b/src/apis/emscripten/README.md index dce02bc24..e5858b17f 100644 --- a/src/apis/emscripten/README.md +++ b/src/apis/emscripten/README.md @@ -127,7 +127,7 @@ ```rust ``` -- **dup** (\_\_\_syscall63)     [:top:](#host-apis) +- **dup2** (\_\_\_syscall63)     [:top:](#host-apis) ```rust ``` diff --git a/src/apis/emscripten/mod.rs b/src/apis/emscripten/mod.rs index d2f8e3606..93eb7d882 100644 --- a/src/apis/emscripten/mod.rs +++ b/src/apis/emscripten/mod.rs @@ -224,6 +224,11 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { "___syscall180", ImportValue::Func(syscalls::___syscall180 as _), ); + import_object.set( + "env", + "___syscall181", + ImportValue::Func(syscalls::___syscall181 as _), + ); import_object.set( "env", "___syscall39", @@ -264,6 +269,11 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { "___syscall192", ImportValue::Func(syscalls::___syscall192 as _), ); + import_object.set( + "env", + "___syscall63", + ImportValue::Func(syscalls::___syscall63 as _), + ); // Process import_object.set( @@ -281,6 +291,27 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { "abortStackOverflow", ImportValue::Func(process::abort_stack_overflow as _), ); + import_object.set( + "env", + "_sigemptyset", + ImportValue::Func(process::_sigemptyset as _), + ); + import_object.set( + "env", + "_sigaddset", + ImportValue::Func(process::_sigaddset as _), + ); + import_object.set( + "env", + "_sigprocmask", + ImportValue::Func(process::_sigprocmask as _), + ); + import_object.set( + "env", + "_sigaction", + ImportValue::Func(process::_sigaction as _), + ); + // Memory import_object.set( "env", @@ -384,10 +415,10 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { mock_external!(import_object, _sysconf); // mock_external!(import_object, _strftime); mock_external!(import_object, _sigsuspend); - mock_external!(import_object, _sigprocmask); - mock_external!(import_object, _sigemptyset); - mock_external!(import_object, _sigaddset); - mock_external!(import_object, _sigaction); + // mock_external!(import_object, _sigprocmask); + // mock_external!(import_object, _sigemptyset); + // mock_external!(import_object, _sigaddset); + // mock_external!(import_object, _sigaction); mock_external!(import_object, _setitimer); mock_external!(import_object, _setgroups); mock_external!(import_object, _setgrent); @@ -418,7 +449,7 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { mock_external!(import_object, ___syscall75); mock_external!(import_object, ___syscall66); // mock_external!(import_object, ___syscall64); - mock_external!(import_object, ___syscall63); + // mock_external!(import_object, ___syscall63); mock_external!(import_object, ___syscall60); // mock_external!(import_object, ___syscall54); // mock_external!(import_object, ___syscall39); @@ -439,7 +470,7 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { // mock_external!(import_object, ___syscall195); mock_external!(import_object, ___syscall194); mock_external!(import_object, ___syscall191); - mock_external!(import_object, ___syscall181); + // mock_external!(import_object, ___syscall181); // mock_external!(import_object, ___syscall180); mock_external!(import_object, ___syscall168); // mock_external!(import_object, ___syscall146); diff --git a/src/apis/emscripten/process.rs b/src/apis/emscripten/process.rs index 95a389ce8..5edd74203 100644 --- a/src/apis/emscripten/process.rs +++ b/src/apis/emscripten/process.rs @@ -33,3 +33,29 @@ pub extern "C" fn abort_stack_overflow() { // TODO: Message incomplete. Need to finish em runtime data first abort_with_message("Stack overflow! Attempted to allocate some bytes on the stack"); } + +pub extern "C" fn _sigemptyset(set: u32, instance: &mut Instance) -> i32 { + debug!("emscripten::_sigemptyset"); + let set_addr = instance.memory_offset_addr(0, set as _) as *mut u32; + unsafe { + *set_addr = 0; + } + 0 +} + +pub extern "C" fn _sigaction(_signum: u32, act: u32, oldact: u32) -> i32 { + debug!("emscripten::_sigaction"); + 0 +} + +pub extern "C" fn _sigaddset(set: u32, signum: u32, instance: &mut Instance) -> i32 { + let set_addr = instance.memory_offset_addr(0, set as _) as *mut u32; + unsafe { + *set_addr |= 1 << (signum - 1); + } + 0 +} + +pub extern "C" fn _sigprocmask() -> i32 { + 0 +} \ No newline at end of file diff --git a/src/apis/emscripten/syscalls.rs b/src/apis/emscripten/syscalls.rs index 0d5fcf434..cf0542866 100644 --- a/src/apis/emscripten/syscalls.rs +++ b/src/apis/emscripten/syscalls.rs @@ -29,6 +29,7 @@ use libc::{ open, pid_t, pread, + pwrite, read, readv, recvfrom, @@ -49,6 +50,7 @@ use libc::{ in_port_t, in_addr_t, c_char, + dup2, }; /// sys_exit @@ -470,6 +472,27 @@ pub extern "C" fn ___syscall180( unsafe { pread(fd, buf_ptr, count as _, offset) as _ } } +// sys_pwrite +pub extern "C" fn ___syscall181( + _which: c_int, + mut varargs: VarArgs, + instance: &mut Instance, +) -> c_int { + debug!("emscripten::___syscall181"); + let fd: i32 = varargs.get(instance); + let buf: u32 = varargs.get(instance); + let count: u32 = varargs.get(instance); + { + let zero: u32 = varargs.get(instance); + assert_eq!(zero, 0); + } + let offset: i64 = varargs.get(instance); + + let buf_ptr = instance.memory_offset_addr(0, buf as _) as _; + + unsafe { pwrite(fd, buf_ptr, count as _, offset) as _ } +} + // sys_stat64 pub extern "C" fn ___syscall195( _which: c_int, @@ -587,3 +610,18 @@ pub extern "C" fn ___syscall340( 0 } +// sys_dup2 +pub extern "C" fn ___syscall63( + _which: c_int, + mut varargs: VarArgs, + instance: &mut Instance, +) -> c_int { + debug!("emscripten::___syscall63"); + + let src: i32 = varargs.get(instance); + let dst: i32 = varargs.get(instance); + + unsafe { + dup2(src, dst) + } +} \ No newline at end of file diff --git a/src/recovery.rs b/src/recovery.rs index 7e515c92e..2619c2b42 100644 --- a/src/recovery.rs +++ b/src/recovery.rs @@ -4,7 +4,8 @@ //! are very special, the async signal unsafety of Rust's TLS implementation generally does not affect the correctness here //! unless you have memory unsafety elsewhere in your code. -use std::cell::UnsafeCell; +use std::cell::{Cell, UnsafeCell}; +use nix::libc::siginfo_t; extern "C" { pub fn setjmp(env: *mut ::nix::libc::c_void) -> ::nix::libc::c_int; @@ -15,6 +16,7 @@ const SETJMP_BUFFER_LEN: usize = 27; thread_local! { pub static SETJMP_BUFFER: UnsafeCell<[::nix::libc::c_int; SETJMP_BUFFER_LEN]> = UnsafeCell::new([0; SETJMP_BUFFER_LEN]); + pub static CAUGHT_ADDRESS: Cell = Cell::new(0); } // We need a macro since the arguments we will provide to the funciton @@ -28,7 +30,7 @@ thread_local! { macro_rules! call_protected { ($x:expr) => { unsafe { - use crate::recovery::{setjmp, SETJMP_BUFFER}; + use crate::recovery::{setjmp, SETJMP_BUFFER, CAUGHT_ADDRESS}; use crate::sighandler::install_sighandler; use crate::webassembly::ErrorKind; @@ -42,6 +44,8 @@ macro_rules! call_protected { let signum = setjmp(jmp_buf as *mut ::nix::libc::c_void); if signum != 0 { *jmp_buf = prev_jmp_buf; + let addr = CAUGHT_ADDRESS.with(|cell| cell.get()); + let signal = match Signal::from_c_int(signum) { Ok(SIGFPE) => "floating-point exception", Ok(SIGILL) => "illegal instruction", @@ -50,7 +54,7 @@ macro_rules! call_protected { Err(_) => "error while getting the Signal", _ => "unkown trapped signal", }; - Err(ErrorKind::RuntimeError(format!("trap - {}", signal))) + Err(ErrorKind::RuntimeError(format!("trap at {:#x} - {}", addr, signal))) } else { let ret = $x; // TODO: Switch stack? *jmp_buf = prev_jmp_buf; @@ -61,7 +65,7 @@ macro_rules! call_protected { } /// Unwinds to last protected_call. -pub unsafe fn do_unwind(signum: i32) -> ! { +pub unsafe fn do_unwind(signum: i32, siginfo: *mut siginfo_t) -> ! { // Since do_unwind is only expected to get called from WebAssembly code which doesn't hold any host resources (locks etc.) // itself, accessing TLS here is safe. In case any other code calls this, it often indicates a memory safety bug and you should // temporarily disable the signal handlers to debug it. @@ -70,6 +74,7 @@ pub unsafe fn do_unwind(signum: i32) -> ! { if *jmp_buf == [0; SETJMP_BUFFER_LEN] { ::std::process::abort(); } + CAUGHT_ADDRESS.with(|cell| cell.set((*siginfo).si_addr as _)); longjmp(jmp_buf as *mut ::nix::libc::c_void, signum) } diff --git a/src/sighandler.rs b/src/sighandler.rs index 5079688db..480f3e8b2 100644 --- a/src/sighandler.rs +++ b/src/sighandler.rs @@ -8,10 +8,11 @@ use super::recovery; use nix::sys::signal::{ sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGFPE, SIGILL, SIGSEGV, }; +use nix::libc::{siginfo_t, c_void}; pub unsafe fn install_sighandler() { let sa = SigAction::new( - SigHandler::Handler(signal_trap_handler), + SigHandler::SigAction(signal_trap_handler), SaFlags::SA_ONSTACK, SigSet::empty(), ); @@ -21,8 +22,8 @@ pub unsafe fn install_sighandler() { sigaction(SIGBUS, &sa).unwrap(); } -extern "C" fn signal_trap_handler(signum: ::nix::libc::c_int) { +extern "C" fn signal_trap_handler(signum: ::nix::libc::c_int, siginfo: *mut siginfo_t, _ucontext: *mut c_void) { unsafe { - recovery::do_unwind(signum); + recovery::do_unwind(signum, siginfo); } }