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