• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libunwind - a platform-independent unwind library
2    Copyright (C) 2008 CodeSourcery
3 
4 This file is part of libunwind.
5 
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13 
14 The above copyright notice and this permission notice shall be
15 included in all copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
24 
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "unwind_i.h"
29 
30 #ifdef UNW_REMOTE_ONLY
31 
32 /* unw_local_addr_space is a NULL pointer in this case.  */
33 unw_addr_space_t unw_local_addr_space;
34 
35 #else /* !UNW_REMOTE_ONLY */
36 
37 static struct unw_addr_space local_addr_space;
38 
39 unw_addr_space_t unw_local_addr_space = &local_addr_space;
40 
41 static inline void *
uc_addr(unw_tdep_context_t * uc,int reg)42 uc_addr (unw_tdep_context_t *uc, int reg)
43 {
44   if (reg >= UNW_ARM_R0 && reg < UNW_ARM_R0 + 16)
45     return &uc->regs[reg - UNW_ARM_R0];
46   else
47     return NULL;
48 }
49 
50 # ifdef UNW_LOCAL_ONLY
51 
52 HIDDEN void *
tdep_uc_addr(unw_tdep_context_t * uc,int reg)53 tdep_uc_addr (unw_tdep_context_t *uc, int reg)
54 {
55   return uc_addr (uc, reg);
56 }
57 
58 # endif /* UNW_LOCAL_ONLY */
59 
60 static int
get_dyn_info_list_addr(unw_addr_space_t as,unw_word_t * dyn_info_list_addr,void * arg)61 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
62                         void *arg)
63 {
64 #ifndef UNW_LOCAL_ONLY
65 # pragma weak _U_dyn_info_list_addr
66   if (!_U_dyn_info_list_addr)
67     return -UNW_ENOINFO;
68 #endif
69   // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
70   *dyn_info_list_addr = _U_dyn_info_list_addr ();
71   return 0;
72 }
73 
74 #define PAGE_SIZE 4096
75 #define PAGE_START(a)	((a) & ~(PAGE_SIZE-1))
76 
77 /* Cache of already validated addresses */
78 #define NLGA 4
79 static unw_word_t last_good_addr[NLGA];
80 static int lga_victim;
81 
82 static int
validate_mem(unw_word_t addr)83 validate_mem (unw_word_t addr)
84 {
85   int i, victim;
86   size_t len;
87 
88   if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr))
89     len = PAGE_SIZE;
90   else
91     len = PAGE_SIZE * 2;
92 
93   addr = PAGE_START(addr);
94 
95   if (addr == 0)
96     return -1;
97 
98   for (i = 0; i < NLGA; i++)
99     {
100       if (last_good_addr[i] && (addr == last_good_addr[i]))
101       return 0;
102     }
103 
104   if (msync ((void *) addr, len, MS_ASYNC) == -1)
105     return -1;
106 
107   victim = lga_victim;
108   for (i = 0; i < NLGA; i++) {
109     if (!last_good_addr[victim]) {
110       last_good_addr[victim++] = addr;
111       return 0;
112     }
113     victim = (victim + 1) % NLGA;
114   }
115 
116   /* All slots full. Evict the victim. */
117   last_good_addr[victim] = addr;
118   victim = (victim + 1) % NLGA;
119   lga_victim = victim;
120 
121   return 0;
122 }
123 
124 static int
access_mem(unw_addr_space_t as,unw_word_t addr,unw_word_t * val,int write,void * arg)125 access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
126             void *arg)
127 {
128   /* validate address */
129     const struct cursor *c = (const struct cursor *) arg;
130     if (c && validate_mem(addr))
131       return -1;
132 
133   if (write)
134     {
135 #ifdef IS_VALIDATE_MEM
136       if (maps_is_writable(as->map_list, addr)) {
137 #endif
138         Debug (16, "mem[%x] <- %x\n", addr, *val);
139         *(unw_word_t *) addr = *val;
140 #ifdef IS_VALIDATE_MEM
141       } else {
142         Debug (16, "Unwritable memory mem[%lx] <- %lx\n", addr, *val);
143         return -1;
144       }
145 #endif
146     }
147   else
148     {
149 #ifdef IS_VALIDATE_MEM
150       if (maps_is_readable(as->map_list, addr)) {
151 #endif
152         *val = *(unw_word_t *) addr;
153         Debug (16, "mem[%x] -> %x\n", addr, *val);
154 #ifdef IS_VALIDATE_MEM
155       } else {
156         Debug (16, "Unreadable memory mem[%lx] <- %lx\n", addr, *val);
157         return -1;
158       }
159 #endif
160     }
161   return 0;
162 }
163 
164 static int
access_reg(unw_addr_space_t as,unw_regnum_t reg,unw_word_t * val,int write,void * arg)165 access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
166             void *arg)
167 {
168   unw_word_t *addr;
169   unw_tdep_context_t *uc = arg;
170 
171   if (unw_is_fpreg (reg))
172     goto badreg;
173 
174 Debug (16, "reg = %s\n", unw_regname (reg));
175   if (!(addr = uc_addr (uc, reg)))
176     goto badreg;
177 
178   if (write)
179     {
180       *(unw_word_t *) addr = *val;
181       Debug (12, "%s <- %x\n", unw_regname (reg), *val);
182     }
183   else
184     {
185       *val = *(unw_word_t *) addr;
186       Debug (12, "%s -> %x\n", unw_regname (reg), *val);
187     }
188   return 0;
189 
190  badreg:
191   Debug (1, "bad register number %u\n", reg);
192   return -UNW_EBADREG;
193 }
194 
195 static int
access_fpreg(unw_addr_space_t as,unw_regnum_t reg,unw_fpreg_t * val,int write,void * arg)196 access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
197               int write, void *arg)
198 {
199   unw_tdep_context_t *uc = arg;
200   unw_fpreg_t *addr;
201 
202   if (!unw_is_fpreg (reg))
203     goto badreg;
204 
205   if (!(addr = uc_addr (uc, reg)))
206     goto badreg;
207 
208   if (write)
209     {
210       Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
211              ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
212       *(unw_fpreg_t *) addr = *val;
213     }
214   else
215     {
216       *val = *(unw_fpreg_t *) addr;
217       Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
218              ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
219     }
220   return 0;
221 
222  badreg:
223   Debug (1, "bad register number %u\n", reg);
224   /* attempt to access a non-preserved register */
225   return -UNW_EBADREG;
226 }
227 
228 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)229 get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
230                       char *buf, size_t buf_len, unw_word_t *offp,
231                       void *arg)
232 {
233   return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp);
234 }
235 
236 HIDDEN void
arm_local_addr_space_init(void)237 arm_local_addr_space_init (void)
238 {
239   memset (&local_addr_space, 0, sizeof (local_addr_space));
240   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
241   local_addr_space.acc.find_proc_info = arm_find_proc_info;
242   local_addr_space.acc.put_unwind_info = arm_put_unwind_info;
243   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
244   local_addr_space.acc.access_mem = access_mem;
245   local_addr_space.acc.access_reg = access_reg;
246   local_addr_space.acc.access_fpreg = access_fpreg;
247   local_addr_space.acc.resume = arm_local_resume;
248   local_addr_space.acc.get_proc_name = get_static_proc_name;
249   unw_flush_cache (&local_addr_space, 0, 0);
250 }
251 
252 HIDDEN void
init_local_addr_space(unw_addr_space_t as)253 init_local_addr_space (unw_addr_space_t as)
254 {
255   memset (as, 0, sizeof (struct unw_addr_space));
256   as->caching_policy = UNW_CACHE_GLOBAL;
257   as->acc.find_proc_info = arm_find_proc_info;
258   as->acc.put_unwind_info = arm_put_unwind_info;
259   as->acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
260   as->acc.access_mem = access_mem;
261   as->acc.access_reg = access_reg;
262   as->acc.access_fpreg = access_fpreg;
263   as->acc.resume = arm_local_resume;
264   as->acc.get_proc_name = get_static_proc_name;
265   unw_flush_cache (as, 0, 0);
266 }
267 
268 #endif /* !UNW_REMOTE_ONLY */
269