1 #include <assert.h>
2 #include <errno.h>
3 #include <setjmp.h>
4 #include <signal.h>
5 #include <string.h>
6 #include <sys/mman.h>
7 #include <sys/ucontext.h>
8 #include <unistd.h>
9 
10 #include "wasmtime-platform.h"
11 
12 #ifdef WASMTIME_VIRTUAL_MEMORY
13 
14 static int wasmtime_to_mmap_prot_flags(uint32_t prot_flags) {
15   int flags = 0;
16   if (prot_flags & WASMTIME_PROT_READ)
17     flags |= PROT_READ;
18   if (prot_flags & WASMTIME_PROT_WRITE)
19     flags |= PROT_WRITE;
20   if (prot_flags & WASMTIME_PROT_EXEC)
21     flags |= PROT_EXEC;
22   return flags;
23 }
24 
25 int wasmtime_mmap_new(uintptr_t size, uint32_t prot_flags, uint8_t **ret) {
26   void *rc = mmap(NULL, size, wasmtime_to_mmap_prot_flags(prot_flags),
27                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
28   if (rc == MAP_FAILED)
29     return errno;
30   *ret = rc;
31   return 0;
32 }
33 
34 int wasmtime_mmap_remap(uint8_t *addr, uintptr_t size, uint32_t prot_flags) {
35   void *rc = mmap(addr, size, wasmtime_to_mmap_prot_flags(prot_flags),
36                   MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
37   if (rc == MAP_FAILED)
38     return errno;
39   return 0;
40 }
41 
42 int wasmtime_munmap(uint8_t *ptr, uintptr_t size) {
43   int rc = munmap(ptr, size);
44   if (rc != 0)
45     return errno;
46   return 0;
47 }
48 
49 int wasmtime_mprotect(uint8_t *ptr, uintptr_t size, uint32_t prot_flags) {
50   int rc = mprotect(ptr, size, wasmtime_to_mmap_prot_flags(prot_flags));
51   if (rc != 0)
52     return errno;
53   return 0;
54 }
55 
56 uintptr_t wasmtime_page_size(void) { return sysconf(_SC_PAGESIZE); }
57 
58 #endif // WASMTIME_VIRTUAL_MEMORY
59 
60 bool wasmtime_setjmp(const uint8_t **jmp_buf_out,
61                      bool (*callback)(uint8_t *, uint8_t *), uint8_t *payload,
62                      uint8_t *callee) {
63   jmp_buf buf;
64   if (setjmp(buf) != 0)
65     return false;
66   *jmp_buf_out = (uint8_t *)&buf;
67   return callback(payload, callee);
68 }
69 
70 void wasmtime_longjmp(const uint8_t *jmp_buf_ptr) {
71   longjmp(*(jmp_buf *)jmp_buf_ptr, 1);
72 }
73 
74 #ifdef WASMTIME_NATIVE_SIGNALS
75 
76 static wasmtime_trap_handler_t g_handler = NULL;
77 
78 static void handle_signal(int signo, siginfo_t *info, void *context) {
79   assert(g_handler != NULL);
80   uintptr_t ip, fp;
81 #if defined(__aarch64__)
82   ucontext_t *cx = context;
83   ip = cx->uc_mcontext.pc;
84   fp = cx->uc_mcontext.regs[29];
85 #elif defined(__x86_64__)
86   ucontext_t *cx = context;
87   ip = cx->uc_mcontext.gregs[REG_RIP];
88   fp = cx->uc_mcontext.gregs[REG_RBP];
89 #else
90 #error "Unsupported platform"
91 #endif
92 
93   bool has_faulting_addr = signo == SIGSEGV;
94   uintptr_t faulting_addr = 0;
95   if (has_faulting_addr)
96     faulting_addr = (uintptr_t)info->si_addr;
97   g_handler(ip, fp, has_faulting_addr, faulting_addr);
98 
99   // If wasmtime didn't handle this trap then reset the handler to the default
100   // behavior which will probably abort the process.
101   signal(signo, SIG_DFL);
102 }
103 
104 int wasmtime_init_traps(wasmtime_trap_handler_t handler) {
105   int rc;
106   g_handler = handler;
107 
108   struct sigaction action;
109   memset(&action, 0, sizeof(action));
110 
111   action.sa_sigaction = handle_signal;
112   action.sa_flags = SA_SIGINFO | SA_NODEFER;
113   sigemptyset(&action.sa_mask);
114 
115   rc = sigaction(SIGILL, &action, NULL);
116   if (rc != 0)
117     return errno;
118   rc = sigaction(SIGSEGV, &action, NULL);
119   if (rc != 0)
120     return errno;
121   rc = sigaction(SIGFPE, &action, NULL);
122   if (rc != 0)
123     return errno;
124   return 0;
125 }
126 
127 #endif // WASMTIME_NATIVE_SIGNALS
128 
129 #ifdef WASMTIME_VIRTUAL_MEMORY
130 
131 int wasmtime_memory_image_new(const uint8_t *ptr, uintptr_t len,
132                               struct wasmtime_memory_image **ret) {
133   *ret = NULL;
134   return 0;
135 }
136 
137 int wasmtime_memory_image_map_at(struct wasmtime_memory_image *image,
138                                  uint8_t *addr, uintptr_t len) {
139   abort();
140 }
141 
142 void wasmtime_memory_image_free(struct wasmtime_memory_image *image) {
143   abort();
144 }
145 
146 #endif // WASMTIME_VIRTUAL_MEMORY
147 
148 // Pretend that this platform doesn't have threads where storing in a static is
149 // ok.
150 static uint8_t *WASMTIME_TLS = NULL;
151 
152 uint8_t *wasmtime_tls_get() { return WASMTIME_TLS; }
153 
154 void wasmtime_tls_set(uint8_t *val) { WASMTIME_TLS = val; }
155