1 /* libunwind - a platform-independent unwind library
2 Copyright (C) 2008 CodeSourcery
3
4 This file is part of libunwind.
5
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice shall be
15 included in all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
24
25 #include <errno.h>
26 #include <pthread.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/mman.h>
30 #include <sys/syscall.h>
31 #include <stdatomic.h>
32
33 #include "unwind_i.h"
34
35 #ifdef UNW_REMOTE_ONLY
36
37 /* unw_local_addr_space is a NULL pointer in this case. */
38 unw_addr_space_t unw_local_addr_space;
39
40 #else /* !UNW_REMOTE_ONLY */
41
42 static struct unw_addr_space local_addr_space;
43
44 unw_addr_space_t unw_local_addr_space = &local_addr_space;
45
46 static inline void *
uc_addr(unw_tdep_context_t * uc,int reg)47 uc_addr (unw_tdep_context_t *uc, int reg)
48 {
49 if (reg >= UNW_ARM_R0 && reg < UNW_ARM_R0 + 16)
50 return &uc->regs[reg - UNW_ARM_R0];
51 else
52 return NULL;
53 }
54
55 # ifdef UNW_LOCAL_ONLY
56
57 HIDDEN void *
tdep_uc_addr(unw_tdep_context_t * uc,int reg)58 tdep_uc_addr (unw_tdep_context_t *uc, int reg)
59 {
60 return uc_addr (uc, reg);
61 }
62
63 # endif /* UNW_LOCAL_ONLY */
64
65 static int
get_dyn_info_list_addr(unw_addr_space_t as,unw_word_t * dyn_info_list_addr,void * arg)66 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
67 void *arg)
68 {
69 #ifndef UNW_LOCAL_ONLY
70 # pragma weak _U_dyn_info_list_addr
71 if (!_U_dyn_info_list_addr)
72 return -UNW_ENOINFO;
73 #endif
74 // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
75 *dyn_info_list_addr = _U_dyn_info_list_addr ();
76 return 0;
77 }
78
79 #define PAGE_SIZE 4096
80 #define PAGE_START(a) ((a) & ~(PAGE_SIZE-1))
81
82 static int mem_validate_pipe[2] = {-1, -1};
83 pthread_mutex_t g_mutex;
84 #ifdef HAVE_PIPE2
85 static inline void
do_pipe2(int pipefd[2])86 do_pipe2 (int pipefd[2])
87 {
88 pipe2 (pipefd, O_CLOEXEC | O_NONBLOCK);
89 }
90 #else
91 static inline void
set_pipe_flags(int fd)92 set_pipe_flags (int fd)
93 {
94 int fd_flags = fcntl (fd, F_GETFD, 0);
95 int status_flags = fcntl (fd, F_GETFL, 0);
96
97 fd_flags |= FD_CLOEXEC;
98 fcntl (fd, F_SETFD, fd_flags);
99
100 status_flags |= O_NONBLOCK;
101 fcntl (fd, F_SETFL, status_flags);
102 }
103
104 static inline void
do_pipe2(int pipefd[2])105 do_pipe2 (int pipefd[2])
106 {
107 pipe (pipefd);
108 set_pipe_flags(pipefd[0]);
109 set_pipe_flags(pipefd[1]);
110 }
111 #endif
112
113 static inline void
open_pipe(void)114 open_pipe (void)
115 {
116 if (mem_validate_pipe[0] != -1)
117 close (mem_validate_pipe[0]);
118 if (mem_validate_pipe[1] != -1)
119 close (mem_validate_pipe[1]);
120
121 do_pipe2 (mem_validate_pipe);
122 }
123
write_validate(void * addr)124 ALWAYS_INLINE NO_SANITIZE static int write_validate (void *addr)
125 {
126 int ret = -1;
127 ssize_t bytes = 0;
128 pthread_mutex_lock(&g_mutex);
129
130 do
131 {
132 char buf;
133 bytes = syscall(SYS_read, mem_validate_pipe[0], &buf, 1);
134 }
135 while ( errno == EINTR );
136
137 int valid_read = (bytes > 0 || errno == EAGAIN || errno == EWOULDBLOCK);
138 if (!valid_read)
139 {
140 // re-open closed pipe
141 open_pipe ();
142 }
143
144 do
145 {
146 ret = syscall(SYS_write, mem_validate_pipe[1], addr, 1);
147 }
148 while ( errno == EINTR );
149 pthread_mutex_unlock(&g_mutex);
150 return ret;
151 }
152
153 static int (*mem_validate_func) (void *addr, size_t len);
msync_validate(void * addr,size_t len)154 static int msync_validate (void *addr, size_t len)
155 {
156 if (msync (addr, len, MS_ASYNC) != 0)
157 {
158 return -1;
159 }
160
161 return write_validate (addr);
162 }
163
164 #ifdef HAVE_MINCORE
mincore_validate(void * addr,size_t len)165 static int mincore_validate (void *addr, size_t len)
166 {
167 unsigned char mvec[2]; /* Unaligned access may cross page boundary */
168
169 /* mincore could fail with EAGAIN but we conservatively return -1
170 instead of looping. */
171 if (mincore (addr, len, (unsigned char *)mvec) != 0)
172 {
173 return -1;
174 }
175
176 return write_validate (addr);
177 }
178 #endif
179
180 /* Initialise memory validation method. On linux kernels <2.6.21,
181 mincore() returns incorrect value for MAP_PRIVATE mappings,
182 such as stacks. If mincore() was available at compile time,
183 check if we can actually use it. If not, use msync() instead. */
184 HIDDEN void
tdep_init_mem_validate(void)185 tdep_init_mem_validate (void)
186 {
187 open_pipe ();
188
189 #ifdef HAVE_MINCORE
190 unsigned char present = 1;
191 unw_word_t addr = PAGE_START((unw_word_t)&present);
192 unsigned char mvec[1];
193 int ret;
194 while ((ret = mincore ((void*)addr, PAGE_SIZE, (unsigned char *)mvec)) == -1 &&
195 errno == EAGAIN) {}
196 if (ret == 0)
197 {
198 Debug(1, "using mincore to validate memory\n");
199 mem_validate_func = mincore_validate;
200 }
201 else
202 #endif
203 {
204 Debug(1, "using msync to validate memory\n");
205 mem_validate_func = msync_validate;
206 }
207 }
208
209 /* Cache of already validated addresses */
210 #define NLGA 4
211 #if defined(HAVE___CACHE_PER_THREAD) && HAVE___CACHE_PER_THREAD
212 // thread-local variant
213 static _Thread_local unw_word_t last_good_addr[NLGA];
214 static _Thread_local int lga_victim;
215
216 static int
is_cached_valid_mem(unw_word_t addr)217 is_cached_valid_mem(unw_word_t addr)
218 {
219 int i;
220 for (i = 0; i < NLGA; i++)
221 {
222 if (addr == last_good_addr[i])
223 return 1;
224 }
225 return 0;
226 }
227
228 static void
cache_valid_mem(unw_word_t addr)229 cache_valid_mem(unw_word_t addr)
230 {
231 int i, victim;
232 victim = lga_victim;
233 for (i = 0; i < NLGA; i++) {
234 if (last_good_addr[victim] == 0) {
235 last_good_addr[victim] = addr;
236 return;
237 }
238 victim = (victim + 1) % NLGA;
239 }
240
241 /* All slots full. Evict the victim. */
242 last_good_addr[victim] = addr;
243 victim = (victim + 1) % NLGA;
244 lga_victim = victim;
245 }
246
247 #else
248 // global, thread safe variant
249 static _Atomic unw_word_t last_good_addr[NLGA];
250 static _Atomic int lga_victim;
251
252 static int
is_cached_valid_mem(unw_word_t addr)253 is_cached_valid_mem(unw_word_t addr)
254 {
255 int i;
256 for (i = 0; i < NLGA; i++)
257 {
258 if (addr == atomic_load(&last_good_addr[i]))
259 return 1;
260 }
261 return 0;
262 }
263
264 static void
cache_valid_mem(unw_word_t addr)265 cache_valid_mem(unw_word_t addr)
266 {
267 int i, victim;
268 victim = atomic_load(&lga_victim);
269 unw_word_t zero = 0;
270 for (i = 0; i < NLGA; i++) {
271 if (atomic_compare_exchange_strong(&last_good_addr[victim], &zero, addr)) {
272 return;
273 }
274 victim = (victim + 1) % NLGA;
275 }
276
277 /* All slots full. Evict the victim. */
278 atomic_store(&last_good_addr[victim], addr);
279 victim = (victim + 1) % NLGA;
280 atomic_store(&lga_victim, victim);
281 }
282 #endif
283
284 static int
validate_mem(unw_word_t addr)285 validate_mem (unw_word_t addr)
286 {
287 size_t len;
288
289 if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr))
290 len = PAGE_SIZE;
291 else
292 len = PAGE_SIZE * 2;
293
294 addr = PAGE_START(addr);
295
296 if (addr == 0)
297 return -1;
298
299 if (is_cached_valid_mem(addr))
300 return 0;
301
302 if (mem_validate_func ((void *) addr, len) == -1)
303 return -1;
304
305 cache_valid_mem(addr);
306
307 return 0;
308 }
309
access_mem(unw_addr_space_t as,unw_word_t addr,unw_word_t * val,int write,void * arg)310 NO_SANITIZE static int access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
311 void *arg)
312 {
313 /* validate address */
314 const struct cursor *c = (const struct cursor *) arg;
315 if (c && validate_mem(addr))
316 return -1;
317
318 if (write)
319 {
320 Debug (16, "mem[%x] <- %x\n", addr, *val);
321 *(unw_word_t *) addr = *val;
322 }
323 else
324 {
325 *val = *(unw_word_t *) addr;
326 Debug (16, "mem[%x] -> %x\n", addr, *val);
327 }
328 return 0;
329 }
330
331 static int
access_reg(unw_addr_space_t as,unw_regnum_t reg,unw_word_t * val,int write,void * arg)332 access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
333 void *arg)
334 {
335 unw_word_t *addr;
336 unw_tdep_context_t *uc = arg;
337
338 if (unw_is_fpreg (reg))
339 goto badreg;
340
341 Debug (16, "reg = %s\n", unw_regname (reg));
342 if (!(addr = uc_addr (uc, reg)))
343 goto badreg;
344
345 if (write)
346 {
347 *(unw_word_t *) addr = *val;
348 Debug (12, "%s <- %x\n", unw_regname (reg), *val);
349 }
350 else
351 {
352 *val = *(unw_word_t *) addr;
353 Debug (12, "%s -> %x\n", unw_regname (reg), *val);
354 }
355 return 0;
356
357 badreg:
358 Debug (1, "bad register number %u\n", reg);
359 return -UNW_EBADREG;
360 }
361
362 static int
access_fpreg(unw_addr_space_t as,unw_regnum_t reg,unw_fpreg_t * val,int write,void * arg)363 access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
364 int write, void *arg)
365 {
366 unw_tdep_context_t *uc = arg;
367 unw_fpreg_t *addr;
368
369 if (!unw_is_fpreg (reg))
370 goto badreg;
371
372 if (!(addr = uc_addr (uc, reg)))
373 goto badreg;
374
375 if (write)
376 {
377 Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
378 ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
379 *(unw_fpreg_t *) addr = *val;
380 }
381 else
382 {
383 *val = *(unw_fpreg_t *) addr;
384 Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
385 ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
386 }
387 return 0;
388
389 badreg:
390 Debug (1, "bad register number %u\n", reg);
391 /* attempt to access a non-preserved register */
392 return -UNW_EBADREG;
393 }
394
395 static int
get_static_proc_name(unw_addr_space_t as,unw_word_t ip,char * buf,size_t buf_len,unw_word_t * offp,void * arg)396 get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
397 char *buf, size_t buf_len, unw_word_t *offp,
398 void *arg)
399 {
400 return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp);
401 }
402
403 HIDDEN void
arm_local_addr_space_init(void)404 arm_local_addr_space_init (void)
405 {
406 memset (&local_addr_space, 0, sizeof (local_addr_space));
407 local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
408 local_addr_space.acc.find_proc_info = arm_find_proc_info;
409 local_addr_space.acc.put_unwind_info = arm_put_unwind_info;
410 local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
411 local_addr_space.acc.access_mem = access_mem;
412 local_addr_space.acc.access_reg = access_reg;
413 local_addr_space.acc.access_fpreg = access_fpreg;
414 local_addr_space.acc.resume = arm_local_resume;
415 local_addr_space.acc.get_proc_name = get_static_proc_name;
416 unw_flush_cache (&local_addr_space, 0, 0);
417 }
418
419 #endif /* !UNW_REMOTE_ONLY */
420