• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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