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