diff --git a/lib/emscripten/src/emscripten_target.rs b/lib/emscripten/src/emscripten_target.rs
index 7e0b81af2..a533b094b 100644
--- a/lib/emscripten/src/emscripten_target.rs
+++ b/lib/emscripten/src/emscripten_target.rs
@@ -1,9 +1,13 @@
 #![allow(non_snake_case)]
 
-use crate::env::get_emscripten_data;
+use crate::env::{call_malloc_with_cast, get_emscripten_data};
+use libc::c_char;
 #[cfg(target_os = "linux")]
 use libc::getdtablesize;
-use wasmer_runtime_core::vm::Ctx;
+use wasmer_runtime_core::{
+    memory::ptr::{Array, WasmPtr},
+    vm::Ctx,
+};
 
 pub fn asm_const_i(_ctx: &mut Ctx, _val: i32) -> i32 {
     debug!("emscripten::asm_const_i: {}", _val);
@@ -15,12 +19,12 @@ pub fn exit_with_live_runtime(_ctx: &mut Ctx) {
 }
 
 pub fn setTempRet0(ctx: &mut Ctx, val: i32) {
-    debug!("emscripten::setTempRet0: {}", val);
+    trace!("emscripten::setTempRet0: {}", val);
     get_emscripten_data(ctx).temp_ret_0 = val;
 }
 
 pub fn getTempRet0(ctx: &mut Ctx) -> i32 {
-    debug!("emscripten::getTempRet0");
+    trace!("emscripten::getTempRet0");
     get_emscripten_data(ctx).temp_ret_0
 }
 
@@ -69,7 +73,7 @@ pub fn _dladdr(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
     0
 }
 pub fn _pthread_attr_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_attr_destroy");
+    trace!("emscripten::_pthread_attr_destroy");
     0
 }
 pub fn _pthread_attr_getstack(
@@ -88,136 +92,136 @@ pub fn _pthread_attr_getstack(
     0
 }
 pub fn _pthread_attr_init(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_attr_init({})", _a);
+    trace!("emscripten::_pthread_attr_init({})", _a);
     0
 }
 pub fn _pthread_attr_setstacksize(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
-    debug!("emscripten::_pthread_attr_setstacksize");
+    trace!("emscripten::_pthread_attr_setstacksize");
     0
 }
 pub fn _pthread_cleanup_pop(_ctx: &mut Ctx, _a: i32) -> () {
-    debug!("emscripten::_pthread_cleanup_pop");
+    trace!("emscripten::_pthread_cleanup_pop");
 }
 pub fn _pthread_cleanup_push(_ctx: &mut Ctx, _a: i32, _b: i32) -> () {
-    debug!("emscripten::_pthread_cleanup_push");
+    trace!("emscripten::_pthread_cleanup_push");
 }
 pub fn _pthread_cond_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_cond_destroy");
+    trace!("emscripten::_pthread_cond_destroy");
     0
 }
 pub fn _pthread_cond_init(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
-    debug!("emscripten::_pthread_cond_init");
+    trace!("emscripten::_pthread_cond_init");
     0
 }
 pub fn _pthread_cond_signal(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_cond_signal");
+    trace!("emscripten::_pthread_cond_signal");
     0
 }
 pub fn _pthread_cond_timedwait(_ctx: &mut Ctx, _a: i32, _b: i32, _c: i32) -> i32 {
-    debug!("emscripten::_pthread_cond_timedwait");
+    trace!("emscripten::_pthread_cond_timedwait");
     0
 }
 pub fn _pthread_cond_wait(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
-    debug!("emscripten::_pthread_cond_wait");
+    trace!("emscripten::_pthread_cond_wait");
     0
 }
 pub fn _pthread_condattr_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_condattr_destroy");
+    trace!("emscripten::_pthread_condattr_destroy");
     0
 }
 pub fn _pthread_condattr_init(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_condattr_init");
+    trace!("emscripten::_pthread_condattr_init");
     0
 }
 pub fn _pthread_condattr_setclock(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
-    debug!("emscripten::_pthread_condattr_setclock");
+    trace!("emscripten::_pthread_condattr_setclock");
     0
 }
 pub fn _pthread_create(_ctx: &mut Ctx, _a: i32, _b: i32, _c: i32, _d: i32) -> i32 {
-    debug!("emscripten::_pthread_create");
+    trace!("emscripten::_pthread_create");
     0
 }
 pub fn _pthread_detach(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_detach");
+    trace!("emscripten::_pthread_detach");
     0
 }
 pub fn _pthread_equal(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
-    debug!("emscripten::_pthread_equal");
+    trace!("emscripten::_pthread_equal");
     0
 }
 pub fn _pthread_exit(_ctx: &mut Ctx, _a: i32) -> () {
-    debug!("emscripten::_pthread_exit");
+    trace!("emscripten::_pthread_exit");
 }
 pub fn _pthread_getattr_np(_ctx: &mut Ctx, _thread: i32, _attr: i32) -> i32 {
-    debug!("emscripten::_pthread_getattr_np({}, {})", _thread, _attr);
+    trace!("emscripten::_pthread_getattr_np({}, {})", _thread, _attr);
     0
 }
 pub fn _pthread_getspecific(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_getspecific");
+    trace!("emscripten::_pthread_getspecific");
     0
 }
 pub fn _pthread_join(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
-    debug!("emscripten::_pthread_join");
+    trace!("emscripten::_pthread_join");
     0
 }
 pub fn _pthread_key_create(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
-    debug!("emscripten::_pthread_key_create");
+    trace!("emscripten::_pthread_key_create");
     0
 }
 pub fn _pthread_mutex_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_mutex_destroy");
+    trace!("emscripten::_pthread_mutex_destroy");
     0
 }
 pub fn _pthread_mutex_init(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
-    debug!("emscripten::_pthread_mutex_init");
+    trace!("emscripten::_pthread_mutex_init");
     0
 }
 pub fn _pthread_mutexattr_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_mutexattr_destroy");
+    trace!("emscripten::_pthread_mutexattr_destroy");
     0
 }
 pub fn _pthread_mutexattr_init(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_mutexattr_init");
+    trace!("emscripten::_pthread_mutexattr_init");
     0
 }
 pub fn _pthread_mutexattr_settype(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
-    debug!("emscripten::_pthread_mutexattr_settype");
+    trace!("emscripten::_pthread_mutexattr_settype");
     0
 }
 pub fn _pthread_once(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
-    debug!("emscripten::_pthread_once");
+    trace!("emscripten::_pthread_once");
     0
 }
 pub fn _pthread_rwlock_destroy(_ctx: &mut Ctx, _rwlock: i32) -> i32 {
-    debug!("emscripten::_pthread_rwlock_destroy({})", _rwlock);
+    trace!("emscripten::_pthread_rwlock_destroy({})", _rwlock);
     0
 }
 pub fn _pthread_rwlock_init(_ctx: &mut Ctx, _rwlock: i32, _attr: i32) -> i32 {
-    debug!("emscripten::_pthread_rwlock_init({}, {})", _rwlock, _attr);
+    trace!("emscripten::_pthread_rwlock_init({}, {})", _rwlock, _attr);
     0
 }
 pub fn _pthread_rwlock_rdlock(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_rwlock_rdlock");
+    trace!("emscripten::_pthread_rwlock_rdlock");
     0
 }
 pub fn _pthread_rwlock_unlock(_ctx: &mut Ctx, _a: i32) -> i32 {
-    debug!("emscripten::_pthread_rwlock_unlock");
+    trace!("emscripten::_pthread_rwlock_unlock");
     0
 }
 pub fn _pthread_rwlock_wrlock(_ctx: &mut Ctx, _rwlock: i32) -> i32 {
-    debug!("emscripten::_pthread_rwlock_wrlock({})", _rwlock);
+    trace!("emscripten::_pthread_rwlock_wrlock({})", _rwlock);
     0
 }
 pub fn _pthread_setcancelstate(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
-    debug!("emscripten::_pthread_setcancelstate");
+    trace!("emscripten::_pthread_setcancelstate");
     0
 }
 pub fn _pthread_setspecific(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
-    debug!("emscripten::_pthread_setspecific");
+    trace!("emscripten::_pthread_setspecific");
     0
 }
 pub fn _pthread_sigmask(_ctx: &mut Ctx, _a: i32, _b: i32, _c: i32) -> i32 {
-    debug!("emscripten::_pthread_sigmask");
+    trace!("emscripten::_pthread_sigmask");
     0
 }
 pub fn ___gxx_personality_v0(
@@ -233,9 +237,24 @@ pub fn ___gxx_personality_v0(
     0
 }
 
-pub fn _gai_strerror(_ctx: &mut Ctx, _ecode: i32) -> i32 {
-    debug!("emscripten::_gai_strerror({})", _ecode);
-    0
+// this may be a memory leak, probably not though because emscripten does the same thing
+pub fn _gai_strerror(ctx: &mut Ctx, ecode: i32) -> i32 {
+    debug!("emscripten::_gai_strerror({})", ecode);
+
+    let cstr = unsafe { std::ffi::CStr::from_ptr(libc::gai_strerror(ecode)) };
+    let bytes = cstr.to_bytes_with_nul();
+    let string_on_guest: WasmPtr<c_char, Array> = call_malloc_with_cast(ctx, bytes.len() as _);
+
+    let writer = unsafe {
+        string_on_guest
+            .deref_mut(ctx.memory(0), 0, bytes.len() as _)
+            .unwrap()
+    };
+    for (i, byte) in bytes.iter().enumerate() {
+        writer[i].set(*byte as i8);
+    }
+
+    string_on_guest.offset() as _
 }
 
 #[cfg(target_os = "linux")]
diff --git a/lib/emscripten/src/env/mod.rs b/lib/emscripten/src/env/mod.rs
index 98bc39dc8..093ec7973 100644
--- a/lib/emscripten/src/env/mod.rs
+++ b/lib/emscripten/src/env/mod.rs
@@ -13,18 +13,228 @@ pub use self::windows::*;
 use libc::c_char;
 
 use crate::{allocate_on_stack, EmscriptenData};
-use std::os::raw::c_int;
-use wasmer_runtime_core::vm::Ctx;
 
-pub fn _getaddrinfo(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32, _four: i32) -> i32 {
+use std::cell::Cell;
+use std::os::raw::c_int;
+use wasmer_runtime_core::{
+    memory::ptr::{Array, WasmPtr},
+    types::ValueType,
+    vm::Ctx,
+};
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct EmAddrInfo {
+    // int
+    ai_flags: i32,
+    // int
+    ai_family: i32,
+    // int
+    ai_socktype: i32,
+    // int
+    ai_protocol: i32,
+    // socklen_t
+    ai_addrlen: u32,
+    // struct sockaddr*
+    ai_addr: WasmPtr<EmSockAddr>,
+    // char*
+    ai_canonname: WasmPtr<c_char, Array>,
+    // struct addrinfo*
+    ai_next: WasmPtr<EmAddrInfo>,
+}
+
+unsafe impl ValueType for EmAddrInfo {}
+
+// NOTE: from looking at emscripten JS, this should be a union
+// TODO: review this, highly likely to have bugs
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct EmSockAddr {
+    sa_family: i16,
+    sa_data: [c_char; 14],
+}
+
+unsafe impl ValueType for EmSockAddr {}
+
+pub fn _getaddrinfo(
+    ctx: &mut Ctx,
+    node_ptr: WasmPtr<c_char>,
+    service_str_ptr: WasmPtr<c_char>,
+    hints_ptr: WasmPtr<EmAddrInfo>,
+    res_val_ptr: WasmPtr<WasmPtr<EmAddrInfo>>,
+) -> i32 {
+    use libc::{addrinfo, freeaddrinfo};
     debug!("emscripten::_getaddrinfo");
-    -1
+    let memory = ctx.memory(0);
+    debug!(" => node = {}", unsafe {
+        node_ptr
+            .deref(memory)
+            .map(|np| {
+                std::ffi::CStr::from_ptr(np as *const Cell<c_char> as *const c_char)
+                    .to_string_lossy()
+            })
+            .unwrap_or(std::borrow::Cow::Borrowed("null"))
+    });
+    debug!(" => server_str = {}", unsafe {
+        service_str_ptr
+            .deref(memory)
+            .map(|np| {
+                std::ffi::CStr::from_ptr(np as *const Cell<c_char> as *const c_char)
+                    .to_string_lossy()
+            })
+            .unwrap_or(std::borrow::Cow::Borrowed("null"))
+    });
+
+    let hints = hints_ptr.deref(memory).map(|hints_memory| {
+        let hints_guest = dbg!(hints_memory.get());
+        unsafe {
+            let mut hints_native: addrinfo = std::mem::uninitialized();
+            hints_native.ai_flags = hints_guest.ai_flags;
+            hints_native.ai_family = hints_guest.ai_family;
+            hints_native.ai_socktype = hints_guest.ai_socktype;
+            hints_native.ai_protocol = hints_guest.ai_protocol;
+            hints_native.ai_addrlen = 0;
+            hints_native.ai_addr = std::ptr::null_mut();
+            hints_native.ai_canonname = std::ptr::null_mut();
+            hints_native.ai_next = std::ptr::null_mut();
+
+            hints_native
+        }
+    });
+
+    let mut out_ptr: *mut addrinfo = std::ptr::null_mut();
+
+    // allocate equivalent memory for res_val_ptr
+    let result = unsafe {
+        libc::getaddrinfo(
+            (node_ptr
+                .deref(memory)
+                .map(|m| m as *const Cell<c_char> as *const c_char))
+            .unwrap_or(std::ptr::null()),
+            (service_str_ptr
+                .deref(memory)
+                .map(|m| m as *const Cell<c_char> as *const c_char))
+            .unwrap_or(std::ptr::null()),
+            hints
+                .as_ref()
+                .map(|h| h as *const addrinfo)
+                .unwrap_or(std::ptr::null()),
+            &mut out_ptr as *mut *mut addrinfo,
+        )
+    };
+    if dbg!(result) != 0 {
+        return result;
+    }
+
+    // walk linked list and copy over, freeing them from the kernel
+    let head_of_list = unsafe {
+        let mut current_host_node = out_ptr;
+        let mut head_of_list = None;
+        let mut previous_guest_node: Option<WasmPtr<EmAddrInfo>> = None;
+
+        while !current_host_node.is_null() {
+            let current_guest_node_ptr: WasmPtr<EmAddrInfo> =
+                call_malloc_with_cast(ctx, std::mem::size_of::<EmAddrInfo>() as _);
+            if head_of_list.is_none() {
+                dbg!("Setting head of list");
+                head_of_list = Some(current_guest_node_ptr);
+            }
+
+            // connect list
+            if let Some(prev_guest) = previous_guest_node {
+                let mut pg = prev_guest.deref_mut(ctx.memory(0)).unwrap().get_mut();
+                pg.ai_next = current_guest_node_ptr;
+                dbg!("list connected");
+            }
+
+            // update values
+
+            let host_addrlen = (*current_host_node).ai_addrlen;
+            // allocate addr and copy data
+            let guest_sockaddr_ptr = {
+                let host_sockaddr_ptr = (*current_host_node).ai_addr;
+                let guest_sockaddr_ptr: WasmPtr<EmSockAddr> =
+                    call_malloc_with_cast(ctx, host_addrlen as _);
+                let guest_sockaddr = guest_sockaddr_ptr
+                    .deref_mut(ctx.memory(0))
+                    .unwrap()
+                    .get_mut();
+
+                guest_sockaddr.sa_family = (*host_sockaddr_ptr).sa_family as i16;
+                guest_sockaddr.sa_data = (*host_sockaddr_ptr).sa_data.clone();
+                guest_sockaddr_ptr
+            };
+
+            dbg!("Socketaddr allocated");
+
+            // allocate canon name on guest and copy data over
+            let guest_canonname_ptr = {
+                let str_ptr = (*current_host_node).ai_canonname;
+                if !str_ptr.is_null() {
+                    let canonname_cstr = dbg!(std::ffi::CStr::from_ptr(str_ptr));
+                    let canonname_bytes = canonname_cstr.to_bytes_with_nul();
+                    let str_size = dbg!(canonname_bytes.len());
+                    let guest_canonname: WasmPtr<c_char, Array> =
+                        call_malloc_with_cast(ctx, str_size as _);
+
+                    let guest_canonname_writer = guest_canonname
+                        .deref(ctx.memory(0), 0, str_size as _)
+                        .unwrap();
+                    for (i, b) in canonname_bytes.into_iter().enumerate() {
+                        guest_canonname_writer[i].set(*b as i8)
+                    }
+
+                    guest_canonname
+                } else {
+                    WasmPtr::new(0)
+                }
+            };
+
+            dbg!("canonname allocated");
+
+            let mut current_guest_node = current_guest_node_ptr
+                .deref_mut(ctx.memory(0))
+                .unwrap()
+                .get_mut();
+            // TODO order these
+            current_guest_node.ai_flags = (*current_host_node).ai_flags;
+            current_guest_node.ai_family = (*current_host_node).ai_family;
+            current_guest_node.ai_socktype = (*current_host_node).ai_socktype;
+            current_guest_node.ai_protocol = (*current_host_node).ai_protocol;
+            current_guest_node.ai_addrlen = host_addrlen;
+            current_guest_node.ai_addr = guest_sockaddr_ptr;
+            current_guest_node.ai_canonname = guest_canonname_ptr;
+            current_guest_node.ai_next = WasmPtr::new(0);
+
+            dbg!("Guest node updated");
+
+            previous_guest_node = Some(current_guest_node_ptr);
+            current_host_node = (*current_host_node).ai_next;
+            dbg!("End of loop bookkeeping finished");
+        }
+
+        dbg!("freeing memory");
+        // this frees all connected nodes on the linked list
+        freeaddrinfo(out_ptr);
+        head_of_list.unwrap_or(WasmPtr::new(0))
+    };
+
+    res_val_ptr
+        .deref(ctx.memory(0))
+        .unwrap()
+        .set(dbg!(head_of_list));
+
+    0
 }
 
 pub fn call_malloc(ctx: &mut Ctx, size: u32) -> u32 {
     get_emscripten_data(ctx).malloc.call(size).unwrap()
 }
 
+pub fn call_malloc_with_cast<T: Copy, Ty>(ctx: &mut Ctx, size: u32) -> WasmPtr<T, Ty> {
+    WasmPtr::new(get_emscripten_data(ctx).malloc.call(size).unwrap())
+}
+
 pub fn call_memalign(ctx: &mut Ctx, alignment: u32, size: u32) -> u32 {
     if let Some(memalign) = &get_emscripten_data(ctx).memalign {
         memalign.call(alignment, size).unwrap()
diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs
index 743264bf2..a890fbe48 100644
--- a/lib/emscripten/src/syscalls/unix.rs
+++ b/lib/emscripten/src/syscalls/unix.rs
@@ -434,6 +434,9 @@ pub fn ___syscall54(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
     }
 }
 
+const SOCK_NON_BLOCK: i32 = 2048;
+const SOCK_CLOEXC: i32 = 0x80000;
+
 // socketcall
 #[allow(clippy::cast_ptr_alignment)]
 pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
@@ -467,13 +470,22 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
             debug!("socket: socket");
             // socket (domain: c_int, ty: c_int, protocol: c_int) -> c_int
             let domain: i32 = socket_varargs.get(ctx);
-            let ty: i32 = socket_varargs.get(ctx);
+            let ty_and_flags: i32 = socket_varargs.get(ctx);
             let protocol: i32 = socket_varargs.get(ctx);
+            let ty = ty_and_flags & (!SOCK_NON_BLOCK) & (!SOCK_CLOEXC);
             let fd = unsafe { socket(domain, ty, protocol) };
-            // set_cloexec
-            unsafe {
-                ioctl(fd, FIOCLEX);
-            };
+
+            if ty_and_flags & SOCK_CLOEXC != 0 {
+                // set_cloexec
+                unsafe {
+                    ioctl(fd, FIOCLEX);
+                };
+            }
+
+            if ty_and_flags & SOCK_NON_BLOCK != 0 {
+                // do something here
+                unimplemented!("non blocking sockets");
+            }
 
             type T = u32;
             let payload = 1 as *const T as _;
@@ -620,6 +632,14 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
             let address_len: u32 = socket_varargs.get(ctx);
             let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as _;
             let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr;
+            dbg!(address);
+            unsafe {
+                dbg!(*(address as *mut u8));
+                dbg!(*(address as *mut u8).add(1));
+                for i in 0..14 {
+                    dbg!(*(address as *mut u8).add(1 + i));
+                }
+            }
             let address_len_addr =
                 emscripten_memory_pointer!(ctx.memory(0), address_len) as *mut socklen_t;
             unsafe {
@@ -642,18 +662,18 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
             // setsockopt (socket: c_int, level: c_int, name: c_int, value: *const c_void, option_len: socklen_t) -> c_int
 
             let socket = socket_varargs.get(ctx);
-            // SOL_SOCKET = 0xffff (BSD, Linux)
-            let level: i32 = SOL_SOCKET;
-            let _: u32 = socket_varargs.get(ctx);
-            // SO_REUSEADDR = 0x4 (BSD, Linux)
-            let name: i32 = SO_REUSEADDR;
-            let _: u32 = socket_varargs.get(ctx);
+            let level: i32 = socket_varargs.get(ctx);
+            // SOL_SOCKET = 0xffff (BSD, OSX)
+            let level = if level == 1 { SOL_SOCKET } else { level };
+            let name: i32 = socket_varargs.get(ctx);
+            // SO_REUSEADDR = 0x4 (BSD, OSX)
+            let name = if name == 2 { SO_REUSEADDR } else { name };
             let value: u32 = socket_varargs.get(ctx);
             let option_len = socket_varargs.get(ctx);
             let value_addr = emscripten_memory_pointer!(ctx.memory(0), value) as _; // Endian problem
             let ret = unsafe { setsockopt(socket, level, name, value_addr, option_len) };
 
-            debug!("=> socketfd: {}, level: {} (SOL_SOCKET/0xffff), name: {} (SO_REUSEADDR/4), value_addr: {:?}, option_len: {} = status: {}", socket, level, name, value_addr, option_len, ret);
+            debug!("=> socketfd: {}, level: {}, name: {}, value_addr: {:?}, option_len: {} = status: {}", socket, level, name, value_addr, option_len, ret);
             ret
         }
         15 => {
diff --git a/lib/runtime-core/src/memory/ptr.rs b/lib/runtime-core/src/memory/ptr.rs
index 892668ce5..fd249b5e3 100644
--- a/lib/runtime-core/src/memory/ptr.rs
+++ b/lib/runtime-core/src/memory/ptr.rs
@@ -57,6 +57,18 @@ impl<T: Copy + ValueType> WasmPtr<T, Item> {
             Some(&*cell_ptr)
         }
     }
+
+    #[inline]
+    pub unsafe fn deref_mut<'a>(self, memory: &'a Memory) -> Option<&'a mut Cell<T>> {
+        if (self.offset as usize) + mem::size_of::<T>() >= memory.size().bytes().0 {
+            return None;
+        }
+        let cell_ptr = align_pointer(
+            memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
+            mem::align_of::<T>(),
+        ) as *mut Cell<T>;
+        Some(&mut *cell_ptr)
+    }
 }
 
 impl<T: Copy + ValueType> WasmPtr<T, Array> {
@@ -81,6 +93,31 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
             Some(cell_ptrs)
         }
     }
+
+    #[inline]
+    pub unsafe fn deref_mut<'a>(
+        self,
+        memory: &'a Memory,
+        index: u32,
+        length: u32,
+    ) -> Option<&'a mut [Cell<T>]> {
+        // gets the size of the item in the array with padding added such that
+        // for any index, we will always result an aligned memory access
+        let item_size = mem::size_of::<T>() + (mem::size_of::<T>() % mem::align_of::<T>());
+        let slice_full_len = index as usize + length as usize;
+
+        if (self.offset as usize) + (item_size * slice_full_len) >= memory.size().bytes().0 {
+            return None;
+        }
+
+        let cell_ptr = align_pointer(
+            memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
+            mem::align_of::<T>(),
+        ) as *mut Cell<T>;
+        let cell_ptrs = &mut std::slice::from_raw_parts_mut(cell_ptr, slice_full_len)
+            [index as usize..slice_full_len];
+        Some(cell_ptrs)
+    }
 }
 
 unsafe impl<T: Copy, Ty> WasmExternType for WasmPtr<T, Ty> {