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 <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_AARCH64_X0 && reg <= UNW_AARCH64_X30)
50 return &uc->uc_mcontext.regs[reg];
51 else if (reg == UNW_AARCH64_SP)
52 return &uc->uc_mcontext.sp;
53 else if (reg == UNW_AARCH64_PC)
54 return &uc->uc_mcontext.pc;
55 else if (reg >= UNW_AARCH64_V0 && reg <= UNW_AARCH64_V31)
56 return &GET_FPCTX(uc)->vregs[reg - UNW_AARCH64_V0];
57 else
58 return NULL;
59 }
60
61 # ifdef UNW_LOCAL_ONLY
62
63 HIDDEN void *
tdep_uc_addr(unw_tdep_context_t * uc,int reg)64 tdep_uc_addr (unw_tdep_context_t *uc, int reg)
65 {
66 return uc_addr (uc, reg);
67 }
68
69 # endif /* UNW_LOCAL_ONLY */
70
71 static void
put_unwind_info(unw_addr_space_t as,unw_proc_info_t * proc_info,void * arg)72 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
73 {
74 /* it's a no-op */
75 }
76
77 static int
get_dyn_info_list_addr(unw_addr_space_t as,unw_word_t * dyn_info_list_addr,void * arg)78 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
79 void *arg)
80 {
81 #ifndef UNW_LOCAL_ONLY
82 # pragma weak _U_dyn_info_list_addr
83 if (!_U_dyn_info_list_addr)
84 return -UNW_ENOINFO;
85 #endif
86 // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
87 *dyn_info_list_addr = _U_dyn_info_list_addr ();
88 return 0;
89 }
90
91 #define PAGE_SIZE 4096
92 #define PAGE_START(a) ((a) & ~(PAGE_SIZE-1))
93
94 static int mem_validate_pipe[2] = {-1, -1};
95
96 #ifdef HAVE_PIPE2
97 static inline void
do_pipe2(int pipefd[2])98 do_pipe2 (int pipefd[2])
99 {
100 pipe2 (pipefd, O_CLOEXEC | O_NONBLOCK);
101 }
102 #else
103 static inline void
set_pipe_flags(int fd)104 set_pipe_flags (int fd)
105 {
106 int fd_flags = fcntl (fd, F_GETFD, 0);
107 int status_flags = fcntl (fd, F_GETFL, 0);
108
109 fd_flags |= FD_CLOEXEC;
110 fcntl (fd, F_SETFD, fd_flags);
111
112 status_flags |= O_NONBLOCK;
113 fcntl (fd, F_SETFL, status_flags);
114 }
115
116 static inline void
do_pipe2(int pipefd[2])117 do_pipe2 (int pipefd[2])
118 {
119 pipe (pipefd);
120 set_pipe_flags(pipefd[0]);
121 set_pipe_flags(pipefd[1]);
122 }
123 #endif
124
125 static inline void
open_pipe(void)126 open_pipe (void)
127 {
128 if (mem_validate_pipe[0] != -1)
129 close (mem_validate_pipe[0]);
130 if (mem_validate_pipe[1] != -1)
131 close (mem_validate_pipe[1]);
132
133 do_pipe2 (mem_validate_pipe);
134 }
135
136 ALWAYS_INLINE
137 static int
write_validate(void * addr)138 write_validate (void *addr)
139 {
140 int ret = -1;
141 ssize_t bytes = 0;
142
143 do
144 {
145 char buf;
146 bytes = read (mem_validate_pipe[0], &buf, 1);
147 }
148 while ( errno == EINTR );
149
150 int valid_read = (bytes > 0 || errno == EAGAIN || errno == EWOULDBLOCK);
151 if (!valid_read)
152 {
153 // re-open closed pipe
154 open_pipe ();
155 }
156
157 do
158 {
159 ret = write (mem_validate_pipe[1], addr, 1);
160 }
161 while ( errno == EINTR );
162
163 return ret;
164 }
165
166 static int (*mem_validate_func) (void *addr, size_t len);
msync_validate(void * addr,size_t len)167 static int msync_validate (void *addr, size_t len)
168 {
169 if (msync (addr, len, MS_ASYNC) != 0)
170 {
171 return -1;
172 }
173
174 return write_validate (addr);
175 }
176
177 #ifdef HAVE_MINCORE
mincore_validate(void * addr,size_t len)178 static int mincore_validate (void *addr, size_t len)
179 {
180 unsigned char mvec[2]; /* Unaligned access may cross page boundary */
181
182 /* mincore could fail with EAGAIN but we conservatively return -1
183 instead of looping. */
184 if (mincore (addr, len, (unsigned char *)mvec) != 0)
185 {
186 return -1;
187 }
188
189 return write_validate (addr);
190 }
191 #endif
192
193 /* Initialise memory validation method. On linux kernels <2.6.21,
194 mincore() returns incorrect value for MAP_PRIVATE mappings,
195 such as stacks. If mincore() was available at compile time,
196 check if we can actually use it. If not, use msync() instead. */
197 HIDDEN void
tdep_init_mem_validate(void)198 tdep_init_mem_validate (void)
199 {
200 open_pipe ();
201
202 #ifdef HAVE_MINCORE
203 unsigned char present = 1;
204 unw_word_t addr = PAGE_START((unw_word_t)&present);
205 unsigned char mvec[1];
206 int ret;
207 while ((ret = mincore ((void*)addr, PAGE_SIZE, (unsigned char *)mvec)) == -1 &&
208 errno == EAGAIN) {}
209 if (ret == 0)
210 {
211 Debug(1, "using mincore to validate memory\n");
212 mem_validate_func = mincore_validate;
213 }
214 else
215 #endif
216 {
217 Debug(1, "using msync to validate memory\n");
218 mem_validate_func = msync_validate;
219 }
220 }
221
222 /* Cache of already validated addresses */
223 #define NLGA 4
224 #if defined(HAVE___CACHE_PER_THREAD) && HAVE___CACHE_PER_THREAD
225 // thread-local variant
226 static _Thread_local unw_word_t last_good_addr[NLGA];
227 static _Thread_local int lga_victim;
228
229 static int
is_cached_valid_mem(unw_word_t addr)230 is_cached_valid_mem(unw_word_t addr)
231 {
232 int i;
233 for (i = 0; i < NLGA; i++)
234 {
235 if (addr == last_good_addr[i])
236 return 1;
237 }
238 return 0;
239 }
240
241 static void
cache_valid_mem(unw_word_t addr)242 cache_valid_mem(unw_word_t addr)
243 {
244 int i, victim;
245 victim = lga_victim;
246 for (i = 0; i < NLGA; i++) {
247 if (last_good_addr[victim] == 0) {
248 last_good_addr[victim] = addr;
249 return;
250 }
251 victim = (victim + 1) % NLGA;
252 }
253
254 /* All slots full. Evict the victim. */
255 last_good_addr[victim] = addr;
256 victim = (victim + 1) % NLGA;
257 lga_victim = victim;
258 }
259
260 #else
261 // global, thread safe variant
262 static _Atomic unw_word_t last_good_addr[NLGA];
263 static _Atomic int lga_victim;
264
265 static int
is_cached_valid_mem(unw_word_t addr)266 is_cached_valid_mem(unw_word_t addr)
267 {
268 int i;
269 for (i = 0; i < NLGA; i++)
270 {
271 if (addr == atomic_load(&last_good_addr[i]))
272 return 1;
273 }
274 return 0;
275 }
276
277 static void
cache_valid_mem(unw_word_t addr)278 cache_valid_mem(unw_word_t addr)
279 {
280 int i, victim;
281 victim = atomic_load(&lga_victim);
282 unw_word_t zero = 0;
283 for (i = 0; i < NLGA; i++) {
284 if (atomic_compare_exchange_strong(&last_good_addr[victim], &zero, addr)) {
285 return;
286 }
287 victim = (victim + 1) % NLGA;
288 }
289
290 /* All slots full. Evict the victim. */
291 atomic_store(&last_good_addr[victim], addr);
292 victim = (victim + 1) % NLGA;
293 atomic_store(&lga_victim, victim);
294 }
295 #endif
296
297 static int
validate_mem(unw_word_t addr)298 validate_mem (unw_word_t addr)
299 {
300 size_t len;
301
302 if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr))
303 len = PAGE_SIZE;
304 else
305 len = PAGE_SIZE * 2;
306
307 addr = PAGE_START(addr);
308
309 if (addr == 0)
310 return -1;
311
312 if (is_cached_valid_mem(addr))
313 return 0;
314
315 if (mem_validate_func ((void *) addr, len) == -1)
316 return -1;
317
318 cache_valid_mem(addr);
319
320 return 0;
321 }
322
323 static int
access_mem(unw_addr_space_t as,unw_word_t addr,unw_word_t * val,int write,void * arg)324 access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
325 void *arg)
326 {
327 if (unlikely (write))
328 {
329 #ifdef IS_VALIDATE_MEM
330 if (maps_is_writable(as->map_list, addr)) {
331 #endif
332 Debug (16, "mem[%lx] <- %lx\n", addr, *val);
333 *(unw_word_t *) addr = *val;
334 #ifdef IS_VALIDATE_MEM
335 } else {
336 Debug (16, "Unwritable memory mem[%lx] <- %lx\n", addr, *val);
337 return -1;
338 }
339 #endif
340 }
341 else
342 {
343 /* validate address */
344 const struct cursor *c = (const struct cursor *)arg;
345 if (likely (c != NULL) && unlikely (c->validate)
346 && unlikely (validate_mem (addr))) {
347 Debug (16, "mem[%016lx] -> invalid\n", addr);
348 return -1;
349 }
350 #ifdef IS_VALIDATE_MEM
351 if (maps_is_readable(as->map_list, addr)) {
352 #endif
353 *val = *(unw_word_t *) addr;
354 Debug (16, "mem[%lx] -> %lx\n", addr, *val);
355 #ifdef IS_VALIDATE_MEM
356 } else {
357 Debug (16, "Unreadable memory mem[%lx] <- %lx\n", addr, *val);
358 return -1;
359 }
360 #endif
361 }
362 return 0;
363 }
364
365 static int
access_reg(unw_addr_space_t as,unw_regnum_t reg,unw_word_t * val,int write,void * arg)366 access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
367 void *arg)
368 {
369 unw_word_t *addr;
370 unw_tdep_context_t *uc = ((struct cursor *)arg)->uc;
371
372 if (unw_is_fpreg (reg))
373 goto badreg;
374
375 if (!(addr = uc_addr (uc, reg)))
376 goto badreg;
377
378 if (write)
379 {
380 *(unw_word_t *) addr = *val;
381 Debug (12, "%s <- %lx\n", unw_regname (reg), *val);
382 }
383 else
384 {
385 *val = *(unw_word_t *) addr;
386 Debug (12, "%s -> %lx\n", unw_regname (reg), *val);
387 }
388 return 0;
389
390 badreg:
391 Debug (1, "bad register number %u\n", reg);
392 return -UNW_EBADREG;
393 }
394
395 static int
access_fpreg(unw_addr_space_t as,unw_regnum_t reg,unw_fpreg_t * val,int write,void * arg)396 access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
397 int write, void *arg)
398 {
399 unw_tdep_context_t *uc = ((struct cursor *)arg)->uc;
400 unw_fpreg_t *addr;
401
402 if (!unw_is_fpreg (reg))
403 goto badreg;
404
405 if (!(addr = uc_addr (uc, reg)))
406 goto badreg;
407
408 if (write)
409 {
410 Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
411 ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
412 *(unw_fpreg_t *) addr = *val;
413 }
414 else
415 {
416 *val = *(unw_fpreg_t *) addr;
417 Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
418 ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
419 }
420 return 0;
421
422 badreg:
423 Debug (1, "bad register number %u\n", reg);
424 /* attempt to access a non-preserved register */
425 return -UNW_EBADREG;
426 }
427
428 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)429 get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
430 char *buf, size_t buf_len, unw_word_t *offp,
431 void *arg)
432 {
433 return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp);
434 }
435
436 HIDDEN void
aarch64_local_addr_space_init(void)437 aarch64_local_addr_space_init (void)
438 {
439 memset (&local_addr_space, 0, sizeof (local_addr_space));
440 local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
441 local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
442 local_addr_space.acc.put_unwind_info = put_unwind_info;
443 local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
444 local_addr_space.acc.access_mem = access_mem;
445 local_addr_space.acc.access_reg = access_reg;
446 local_addr_space.acc.access_fpreg = access_fpreg;
447 local_addr_space.acc.resume = aarch64_local_resume;
448 local_addr_space.acc.get_proc_name = get_static_proc_name;
449 local_addr_space.big_endian = target_is_big_endian();
450 unw_flush_cache (&local_addr_space, 0, 0);
451 }
452
453 HIDDEN void
init_local_addr_space(unw_addr_space_t as)454 init_local_addr_space (unw_addr_space_t as)
455 {
456 memset (as, 0, sizeof (struct unw_addr_space));
457 as->caching_policy = UNW_CACHE_GLOBAL;
458 as->acc.find_proc_info = dwarf_find_proc_info;
459 as->acc.put_unwind_info = put_unwind_info;
460 as->acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
461 as->acc.access_mem = access_mem;
462 as->acc.access_reg = access_reg;
463 as->acc.access_fpreg = access_fpreg;
464 as->acc.resume = aarch64_local_resume;
465 as->acc.get_proc_name = get_static_proc_name;
466 as->big_endian = target_is_big_endian();
467 unw_flush_cache (as, 0, 0);
468 }
469
470 #endif /* !UNW_REMOTE_ONLY */
471