1 #include <assert.h> 2 #include <errno.h> 3 #include <signal.h> 4 #include <string.h> 5 #include <sys/mman.h> 6 #include <sys/ucontext.h> 7 #include <unistd.h> 8 9 #include "wasmtime-platform.h" 10 11 #ifdef WASMTIME_VIRTUAL_MEMORY 12 13 static int wasmtime_to_mmap_prot_flags(uint32_t prot_flags) { 14 int flags = 0; 15 if (prot_flags & WASMTIME_PROT_READ) 16 flags |= PROT_READ; 17 if (prot_flags & WASMTIME_PROT_WRITE) 18 flags |= PROT_WRITE; 19 if (prot_flags & WASMTIME_PROT_EXEC) 20 flags |= PROT_EXEC; 21 return flags; 22 } 23 24 int wasmtime_mmap_new(uintptr_t size, uint32_t prot_flags, uint8_t **ret) { 25 void *rc = mmap(NULL, size, wasmtime_to_mmap_prot_flags(prot_flags), 26 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 27 if (rc == MAP_FAILED) 28 return errno; 29 *ret = rc; 30 return 0; 31 } 32 33 int wasmtime_mmap_remap(uint8_t *addr, uintptr_t size, uint32_t prot_flags) { 34 void *rc = mmap(addr, size, wasmtime_to_mmap_prot_flags(prot_flags), 35 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 36 if (rc == MAP_FAILED) 37 return errno; 38 return 0; 39 } 40 41 int wasmtime_munmap(uint8_t *ptr, uintptr_t size) { 42 int rc = munmap(ptr, size); 43 if (rc != 0) 44 return errno; 45 return 0; 46 } 47 48 int wasmtime_mprotect(uint8_t *ptr, uintptr_t size, uint32_t prot_flags) { 49 int rc = mprotect(ptr, size, wasmtime_to_mmap_prot_flags(prot_flags)); 50 if (rc != 0) 51 return errno; 52 return 0; 53 } 54 55 uintptr_t wasmtime_page_size(void) { return sysconf(_SC_PAGESIZE); } 56 57 #endif // WASMTIME_VIRTUAL_MEMORY 58 59 #ifdef WASMTIME_NATIVE_SIGNALS 60 61 static wasmtime_trap_handler_t g_handler = NULL; 62 63 static void handle_signal(int signo, siginfo_t *info, void *context) { 64 assert(g_handler != NULL); 65 uintptr_t ip, fp; 66 #if defined(__aarch64__) 67 ucontext_t *cx = context; 68 ip = cx->uc_mcontext.pc; 69 fp = cx->uc_mcontext.regs[29]; 70 #elif defined(__x86_64__) 71 ucontext_t *cx = context; 72 ip = cx->uc_mcontext.gregs[REG_RIP]; 73 fp = cx->uc_mcontext.gregs[REG_RBP]; 74 #else 75 #error "Unsupported platform" 76 #endif 77 78 bool has_faulting_addr = signo == SIGSEGV; 79 uintptr_t faulting_addr = 0; 80 if (has_faulting_addr) 81 faulting_addr = (uintptr_t)info->si_addr; 82 g_handler(ip, fp, has_faulting_addr, faulting_addr); 83 84 // If wasmtime didn't handle this trap then reset the handler to the default 85 // behavior which will probably abort the process. 86 signal(signo, SIG_DFL); 87 } 88 89 int wasmtime_init_traps(wasmtime_trap_handler_t handler) { 90 int rc; 91 g_handler = handler; 92 93 struct sigaction action; 94 memset(&action, 0, sizeof(action)); 95 96 action.sa_sigaction = handle_signal; 97 action.sa_flags = SA_SIGINFO | SA_NODEFER; 98 sigemptyset(&action.sa_mask); 99 100 rc = sigaction(SIGILL, &action, NULL); 101 if (rc != 0) 102 return errno; 103 rc = sigaction(SIGSEGV, &action, NULL); 104 if (rc != 0) 105 return errno; 106 rc = sigaction(SIGFPE, &action, NULL); 107 if (rc != 0) 108 return errno; 109 return 0; 110 } 111 112 #endif // WASMTIME_NATIVE_SIGNALS 113 114 #ifdef WASMTIME_VIRTUAL_MEMORY 115 116 int wasmtime_memory_image_new(const uint8_t *ptr, uintptr_t len, 117 struct wasmtime_memory_image **ret) { 118 *ret = NULL; 119 return 0; 120 } 121 122 int wasmtime_memory_image_map_at(struct wasmtime_memory_image *image, 123 uint8_t *addr, uintptr_t len) { 124 abort(); 125 } 126 127 void wasmtime_memory_image_free(struct wasmtime_memory_image *image) { 128 abort(); 129 } 130 131 #endif // WASMTIME_VIRTUAL_MEMORY 132 133 #ifdef WASMTIME_CUSTOM_SYNC 134 135 // Multi-threaded TLS using pthread 136 #include <pthread.h> 137 138 static pthread_key_t wasmtime_tls_key; 139 static pthread_once_t wasmtime_tls_key_once = PTHREAD_ONCE_INIT; 140 141 static void make_tls_key(void) { pthread_key_create(&wasmtime_tls_key, NULL); } 142 143 uint8_t *wasmtime_tls_get(void) { 144 pthread_once(&wasmtime_tls_key_once, make_tls_key); 145 return (uint8_t *)pthread_getspecific(wasmtime_tls_key); 146 } 147 148 void wasmtime_tls_set(uint8_t *val) { 149 pthread_once(&wasmtime_tls_key_once, make_tls_key); 150 pthread_setspecific(wasmtime_tls_key, val); 151 } 152 153 #else 154 155 // Single-threaded TLS using a static variable 156 static uint8_t *WASMTIME_TLS = NULL; 157 158 uint8_t *wasmtime_tls_get(void) { return WASMTIME_TLS; } 159 160 void wasmtime_tls_set(uint8_t *val) { WASMTIME_TLS = val; } 161 162 #endif 163 164 #ifdef WASMTIME_CUSTOM_SYNC 165 166 #include <stdlib.h> 167 168 void wasmtime_sync_lock_free(uintptr_t *lock) { 169 if (*lock != 0) { 170 pthread_mutex_t *mutex = (pthread_mutex_t *)*lock; 171 pthread_mutex_destroy(mutex); 172 free(mutex); 173 *lock = 0; 174 } 175 } 176 177 static pthread_mutex_t *mutex_lazy_init(uintptr_t *lock) { 178 pthread_mutex_t *mutex = (pthread_mutex_t *)*lock; 179 if (mutex == NULL) { 180 pthread_mutex_t *new_mutex = malloc(sizeof(pthread_mutex_t)); 181 if (new_mutex == NULL) { 182 abort(); 183 } 184 pthread_mutex_init(new_mutex, NULL); 185 186 // Atomically set lock only if it's still NULL 187 if (!__sync_bool_compare_and_swap(lock, 0, (uintptr_t)new_mutex)) { 188 pthread_mutex_destroy(new_mutex); 189 free(new_mutex); 190 } 191 mutex = (pthread_mutex_t *)*lock; 192 } 193 return mutex; 194 } 195 196 void wasmtime_sync_lock_acquire(uintptr_t *lock) { 197 pthread_mutex_t *mutex = mutex_lazy_init(lock); 198 pthread_mutex_lock(mutex); 199 } 200 201 void wasmtime_sync_lock_release(uintptr_t *lock) { 202 pthread_mutex_t *mutex = mutex_lazy_init(lock); 203 pthread_mutex_unlock(mutex); 204 } 205 206 void wasmtime_sync_rwlock_free(uintptr_t *lock) { 207 if (*lock != 0) { 208 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)*lock; 209 pthread_rwlock_destroy(rwlock); 210 free(rwlock); 211 *lock = 0; 212 } 213 } 214 215 static pthread_rwlock_t *rwlock_lazy_init(uintptr_t *lock) { 216 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)*lock; 217 if (rwlock == NULL) { 218 pthread_rwlock_t *new_rwlock = malloc(sizeof(pthread_rwlock_t)); 219 if (new_rwlock == NULL) { 220 abort(); 221 } 222 pthread_rwlock_init(new_rwlock, NULL); 223 224 // Atomically set lock only if it's still NULL 225 if (!__sync_bool_compare_and_swap(lock, 0, (uintptr_t)new_rwlock)) { 226 // Another thread won the race, discard our allocation 227 pthread_rwlock_destroy(new_rwlock); 228 free(new_rwlock); 229 } 230 rwlock = (pthread_rwlock_t *)*lock; 231 } 232 return rwlock; 233 } 234 235 void wasmtime_sync_rwlock_read(uintptr_t *lock) { 236 pthread_rwlock_t *rwlock = rwlock_lazy_init(lock); 237 pthread_rwlock_rdlock(rwlock); 238 } 239 240 void wasmtime_sync_rwlock_read_release(uintptr_t *lock) { 241 pthread_rwlock_t *rwlock = rwlock_lazy_init(lock); 242 pthread_rwlock_unlock(rwlock); 243 } 244 245 void wasmtime_sync_rwlock_write(uintptr_t *lock) { 246 pthread_rwlock_t *rwlock = rwlock_lazy_init(lock); 247 pthread_rwlock_wrlock(rwlock); 248 } 249 250 void wasmtime_sync_rwlock_write_release(uintptr_t *lock) { 251 pthread_rwlock_t *rwlock = rwlock_lazy_init(lock); 252 pthread_rwlock_unlock(rwlock); 253 } 254 255 #endif // WASMTIME_CUSTOM_SYNC 256