1 /* libunwind - a platform-independent unwind library
2 Copyright (C) 2002 Hewlett-Packard Co
3 Copyright (C) 2007 David Mosberger-Tang
4 Contributed by David Mosberger-Tang <dmosberger@gmail.com>
6 Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
8 This file is part of libunwind.
10 Permission is hereby granted, free of charge, to any person obtaining
11 a copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sublicense, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
18 The above copyright notice and this permission notice shall be
19 included in all copies or substantial portions of the Software.
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
37 #include <sys/syscall.h>
41 #ifdef UNW_REMOTE_ONLY
43 /* unw_local_addr_space is a NULL pointer in this case. */
44 unw_addr_space_t unw_local_addr_space;
46 #else /* !UNW_REMOTE_ONLY */
48 static struct unw_addr_space local_addr_space;
50 unw_addr_space_t unw_local_addr_space = &local_addr_space;
52 HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
54 /* XXX fix me: there is currently no way to locate the dyn-info list
55 by a remote unwinder. On ia64, this is done via a special
56 unwind-table entry. Perhaps something similar can be done with
57 DWARF2 unwind info. */
60 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
66 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
69 *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
73 #define PAGE_SIZE 4096
74 #define PAGE_START(a) ((a) & ~(PAGE_SIZE-1))
76 static int mem_validate_pipe[2] = {-1, -1};
81 /* ignore errors for closing invalid fd's */
82 close (mem_validate_pipe[0]);
83 close (mem_validate_pipe[1]);
85 pipe2 (mem_validate_pipe, O_CLOEXEC | O_NONBLOCK);
90 write_validate (void *addr)
98 bytes = read (mem_validate_pipe[0], &buf, 1);
100 while ( errno == EINTR );
102 int valid_read = (bytes > 0 || errno == EAGAIN || errno == EWOULDBLOCK);
105 // re-open closed pipe
111 /* use syscall insteadof write() so that ASAN does not complain */
112 ret = syscall (SYS_write, mem_validate_pipe[1], addr, 1);
114 while ( errno == EINTR );
119 static int (*mem_validate_func) (void *addr, size_t len);
120 static int msync_validate (void *addr, size_t len)
122 if (msync (addr, len, MS_ASYNC) != 0)
127 return write_validate (addr);
131 static int mincore_validate (void *addr, size_t len)
133 unsigned char mvec[2]; /* Unaligned access may cross page boundary */
136 /* mincore could fail with EAGAIN but we conservatively return -1
137 instead of looping. */
138 if (mincore (addr, len, mvec) != 0)
143 for (i = 0; i < (len + PAGE_SIZE - 1) / PAGE_SIZE; i++)
145 if (!(mvec[i] & 1)) return -1;
148 return write_validate (addr);
152 /* Initialise memory validation method. On linux kernels <2.6.21,
153 mincore() returns incorrect value for MAP_PRIVATE mappings,
154 such as stacks. If mincore() was available at compile time,
155 check if we can actually use it. If not, use msync() instead. */
157 tdep_init_mem_validate (void)
162 unsigned char present = 1;
163 unw_word_t addr = PAGE_START((unw_word_t)&present);
164 unsigned char mvec[1];
166 while ((ret = mincore ((void*)addr, PAGE_SIZE, mvec)) == -1 &&
168 if (ret == 0 && (mvec[0] & 1))
170 Debug(1, "using mincore to validate memory\n");
171 mem_validate_func = mincore_validate;
176 Debug(1, "using msync to validate memory\n");
177 mem_validate_func = msync_validate;
181 /* Cache of already validated addresses */
183 static unw_word_t last_good_addr[NLGA];
184 static int lga_victim;
187 validate_mem (unw_word_t addr)
192 if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr))
197 addr = PAGE_START(addr);
202 for (i = 0; i < NLGA; i++)
204 if (last_good_addr[i] && (addr == last_good_addr[i]))
208 if (mem_validate_func ((void *) addr, len) == -1)
212 for (i = 0; i < NLGA; i++) {
213 if (!last_good_addr[victim]) {
214 last_good_addr[victim++] = addr;
217 victim = (victim + 1) % NLGA;
220 /* All slots full. Evict the victim. */
221 last_good_addr[victim] = addr;
222 victim = (victim + 1) % NLGA;
229 access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
232 if (unlikely (write))
234 Debug (16, "mem[%016lx] <- %lx\n", addr, *val);
235 *(unw_word_t *) addr = *val;
239 /* validate address */
240 const struct cursor *c = (const struct cursor *)arg;
241 if (likely (c != NULL) && unlikely (c->validate)
242 && unlikely (validate_mem (addr))) {
243 Debug (16, "mem[%016lx] -> invalid\n", addr);
246 *val = *(unw_word_t *) addr;
247 Debug (16, "mem[%016lx] -> %lx\n", addr, *val);
253 access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
257 ucontext_t *uc = ((struct cursor *)arg)->uc;
259 if (unw_is_fpreg (reg))
262 if (!(addr = x86_64_r_uc_addr (uc, reg)))
267 *(unw_word_t *) addr = *val;
268 Debug (12, "%s <- 0x%016lx\n", unw_regname (reg), *val);
272 *val = *(unw_word_t *) addr;
273 Debug (12, "%s -> 0x%016lx\n", unw_regname (reg), *val);
278 Debug (1, "bad register number %u\n", reg);
283 access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
284 int write, void *arg)
286 ucontext_t *uc = ((struct cursor *)arg)->uc;
289 if (!unw_is_fpreg (reg))
292 if (!(addr = x86_64_r_uc_addr (uc, reg)))
297 Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
298 ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
299 *(unw_fpreg_t *) addr = *val;
303 *val = *(unw_fpreg_t *) addr;
304 Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
305 ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
310 Debug (1, "bad register number %u\n", reg);
311 /* attempt to access a non-preserved register */
316 get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
317 char *buf, size_t buf_len, unw_word_t *offp,
320 return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp);
324 x86_64_local_addr_space_init (void)
326 memset (&local_addr_space, 0, sizeof (local_addr_space));
327 local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
328 local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
329 local_addr_space.acc.put_unwind_info = put_unwind_info;
330 local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
331 local_addr_space.acc.access_mem = access_mem;
332 local_addr_space.acc.access_reg = access_reg;
333 local_addr_space.acc.access_fpreg = access_fpreg;
334 local_addr_space.acc.resume = x86_64_local_resume;
335 local_addr_space.acc.get_proc_name = get_static_proc_name;
336 unw_flush_cache (&local_addr_space, 0, 0);
338 memset (last_good_addr, 0, sizeof (unw_word_t) * NLGA);
342 #endif /* !UNW_REMOTE_ONLY */