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