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