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
wasmtime_to_mmap_prot_flags(uint32_t prot_flags)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
wasmtime_mmap_new(uintptr_t size,uint32_t prot_flags,uint8_t ** ret)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
wasmtime_mmap_remap(uint8_t * addr,uintptr_t size,uint32_t prot_flags)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
wasmtime_munmap(uint8_t * ptr,uintptr_t size)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
wasmtime_mprotect(uint8_t * ptr,uintptr_t size,uint32_t prot_flags)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
wasmtime_page_size(void)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
handle_signal(int signo,siginfo_t * info,void * context)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
wasmtime_init_traps(wasmtime_trap_handler_t handler)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
wasmtime_memory_image_new(const uint8_t * ptr,uintptr_t len,struct wasmtime_memory_image ** ret)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
wasmtime_memory_image_map_at(struct wasmtime_memory_image * image,uint8_t * addr,uintptr_t len)122 int wasmtime_memory_image_map_at(struct wasmtime_memory_image *image,
123 uint8_t *addr, uintptr_t len) {
124 abort();
125 }
126
wasmtime_memory_image_free(struct wasmtime_memory_image * image)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
make_tls_key(void)141 static void make_tls_key(void) { pthread_key_create(&wasmtime_tls_key, NULL); }
142
wasmtime_tls_get(void)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
wasmtime_tls_set(uint8_t * val)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
wasmtime_tls_get(void)158 uint8_t *wasmtime_tls_get(void) { return WASMTIME_TLS; }
159
wasmtime_tls_set(uint8_t * val)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
wasmtime_sync_lock_free(uintptr_t * lock)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
mutex_lazy_init(uintptr_t * lock)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
wasmtime_sync_lock_acquire(uintptr_t * lock)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
wasmtime_sync_lock_release(uintptr_t * lock)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
wasmtime_sync_rwlock_free(uintptr_t * lock)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
rwlock_lazy_init(uintptr_t * lock)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
wasmtime_sync_rwlock_read(uintptr_t * lock)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
wasmtime_sync_rwlock_read_release(uintptr_t * lock)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
wasmtime_sync_rwlock_write(uintptr_t * lock)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
wasmtime_sync_rwlock_write_release(uintptr_t * lock)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