• 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       Debug (16, "mem[%x] <- %x\n", addr, *val);
136       *(unw_word_t *) addr = *val;
137     }
138   else
139     {
140       *val = *(unw_word_t *) addr;
141       Debug (16, "mem[%x] -> %x\n", addr, *val);
142     }
143   return 0;
144 }
145 
146 static int
access_reg(unw_addr_space_t as,unw_regnum_t reg,unw_word_t * val,int write,void * arg)147 access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
148             void *arg)
149 {
150   unw_word_t *addr;
151   unw_tdep_context_t *uc = arg;
152 
153   if (unw_is_fpreg (reg))
154     goto badreg;
155 
156 Debug (16, "reg = %s\n", unw_regname (reg));
157   if (!(addr = uc_addr (uc, reg)))
158     goto badreg;
159 
160   if (write)
161     {
162       *(unw_word_t *) addr = *val;
163       Debug (12, "%s <- %x\n", unw_regname (reg), *val);
164     }
165   else
166     {
167       *val = *(unw_word_t *) addr;
168       Debug (12, "%s -> %x\n", unw_regname (reg), *val);
169     }
170   return 0;
171 
172  badreg:
173   Debug (1, "bad register number %u\n", reg);
174   return -UNW_EBADREG;
175 }
176 
177 static int
access_fpreg(unw_addr_space_t as,unw_regnum_t reg,unw_fpreg_t * val,int write,void * arg)178 access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
179               int write, void *arg)
180 {
181   unw_tdep_context_t *uc = arg;
182   unw_fpreg_t *addr;
183 
184   if (!unw_is_fpreg (reg))
185     goto badreg;
186 
187   if (!(addr = uc_addr (uc, reg)))
188     goto badreg;
189 
190   if (write)
191     {
192       Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
193              ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
194       *(unw_fpreg_t *) addr = *val;
195     }
196   else
197     {
198       *val = *(unw_fpreg_t *) addr;
199       Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
200              ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
201     }
202   return 0;
203 
204  badreg:
205   Debug (1, "bad register number %u\n", reg);
206   /* attempt to access a non-preserved register */
207   return -UNW_EBADREG;
208 }
209 
210 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)211 get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
212                       char *buf, size_t buf_len, unw_word_t *offp,
213                       void *arg)
214 {
215   return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp);
216 }
217 
218 HIDDEN void
arm_local_addr_space_init(void)219 arm_local_addr_space_init (void)
220 {
221   memset (&local_addr_space, 0, sizeof (local_addr_space));
222   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
223   local_addr_space.acc.find_proc_info = arm_find_proc_info;
224   local_addr_space.acc.put_unwind_info = arm_put_unwind_info;
225   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
226   local_addr_space.acc.access_mem = access_mem;
227   local_addr_space.acc.access_reg = access_reg;
228   local_addr_space.acc.access_fpreg = access_fpreg;
229   local_addr_space.acc.resume = arm_local_resume;
230   local_addr_space.acc.get_proc_name = get_static_proc_name;
231   unw_flush_cache (&local_addr_space, 0, 0);
232 }
233 
234 HIDDEN void
init_local_addr_space(unw_addr_space_t as)235 init_local_addr_space (unw_addr_space_t as)
236 {
237   memset (as, 0, sizeof (struct unw_addr_space));
238   as->caching_policy = UNW_CACHE_GLOBAL;
239   as->acc.find_proc_info = arm_find_proc_info;
240   as->acc.put_unwind_info = arm_put_unwind_info;
241   as->acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
242   as->acc.access_mem = access_mem;
243   as->acc.access_reg = access_reg;
244   as->acc.access_fpreg = access_fpreg;
245   as->acc.resume = arm_local_resume;
246   as->acc.get_proc_name = get_static_proc_name;
247   unw_flush_cache (as, 0, 0);
248 }
249 
250 #endif /* !UNW_REMOTE_ONLY */
251