• 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 PROTECTED 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 PROTECTED 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 HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
61 
62 /* XXX fix me: there is currently no way to locate the dyn-info list
63        by a remote unwinder.  On ia64, this is done via a special
64        unwind-table entry.  Perhaps something similar can be done with
65        DWARF2 unwind info.  */
66 
67 static int
get_dyn_info_list_addr(unw_addr_space_t as,unw_word_t * dyn_info_list_addr,void * arg)68 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
69 			void *arg)
70 {
71   *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
72   return 0;
73 }
74 
75 static int
access_mem(unw_addr_space_t as,unw_word_t addr,unw_word_t * val,int write,void * arg)76 access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
77 	    void *arg)
78 {
79   if (write)
80     {
81       /* ANDROID support update. */
82 #ifdef UNW_LOCAL_ONLY
83       if (map_local_is_writable (addr, sizeof(unw_word_t)))
84         {
85 #endif
86           Debug (16, "mem[%x] <- %x\n", addr, *val);
87           *(unw_word_t *) addr = *val;
88 #ifdef UNW_LOCAL_ONLY
89         }
90       else
91         {
92           Debug (16, "Unwritable memory mem[%x] <- %x\n", addr, *val);
93           return -1;
94         }
95 #endif
96       /* End of ANDROID update. */
97     }
98   else
99     {
100       /* ANDROID support update. */
101 #ifdef UNW_LOCAL_ONLY
102       if (map_local_is_readable (addr, sizeof(unw_word_t)))
103         {
104 #endif
105           *val = *(unw_word_t *) addr;
106           Debug (16, "mem[%x] -> %x\n", addr, *val);
107 #ifdef UNW_LOCAL_ONLY
108         }
109       else
110         {
111           Debug (16, "Unreadable memory mem[%x] -> XXX\n", addr);
112           return -1;
113         }
114 #endif
115       /* End of ANDROID update. */
116     }
117   return 0;
118 }
119 
120 static int
access_reg(unw_addr_space_t as,unw_regnum_t reg,unw_word_t * val,int write,void * arg)121 access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
122 	    void *arg)
123 {
124   unw_word_t *addr;
125   unw_tdep_context_t *uc = arg;
126 
127   if (unw_is_fpreg (reg))
128     goto badreg;
129 
130 Debug (16, "reg = %s\n", unw_regname (reg));
131   if (!(addr = uc_addr (uc, reg)))
132     goto badreg;
133 
134   if (write)
135     {
136       *(unw_word_t *) addr = *val;
137       Debug (12, "%s <- %x\n", unw_regname (reg), *val);
138     }
139   else
140     {
141       *val = *(unw_word_t *) addr;
142       Debug (12, "%s -> %x\n", unw_regname (reg), *val);
143     }
144   return 0;
145 
146  badreg:
147   Debug (1, "bad register number %u\n", reg);
148   return -UNW_EBADREG;
149 }
150 
151 static int
access_fpreg(unw_addr_space_t as,unw_regnum_t reg,unw_fpreg_t * val,int write,void * arg)152 access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
153 	      int write, void *arg)
154 {
155   unw_tdep_context_t *uc = arg;
156   unw_fpreg_t *addr;
157 
158   if (!unw_is_fpreg (reg))
159     goto badreg;
160 
161   if (!(addr = uc_addr (uc, reg)))
162     goto badreg;
163 
164   if (write)
165     {
166       Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
167 	     ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
168       *(unw_fpreg_t *) addr = *val;
169     }
170   else
171     {
172       *val = *(unw_fpreg_t *) addr;
173       Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
174 	     ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
175     }
176   return 0;
177 
178  badreg:
179   Debug (1, "bad register number %u\n", reg);
180   /* attempt to access a non-preserved register */
181   return -UNW_EBADREG;
182 }
183 
184 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)185 get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
186 		      char *buf, size_t buf_len, unw_word_t *offp,
187 		      void *arg)
188 {
189   return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp, arg);
190 }
191 
192 static int
access_mem_unrestricted(unw_addr_space_t as,unw_word_t addr,unw_word_t * val,int write,void * arg)193 access_mem_unrestricted (unw_addr_space_t as, unw_word_t addr, unw_word_t *val,
194                          int write, void *arg)
195 {
196   if (write)
197     return -1;
198 
199   *val = *(unw_word_t *) addr;
200   Debug (16, "mem[%x] -> %x\n", addr, *val);
201   return 0;
202 }
203 
204 // This initializes just enough of the address space to call the
205 // access memory function.
206 PROTECTED void
unw_local_access_addr_space_init(unw_addr_space_t as)207 unw_local_access_addr_space_init (unw_addr_space_t as)
208 {
209   memset (as, 0, sizeof (*as));
210   as->acc.access_mem = access_mem_unrestricted;
211 }
212 
213 HIDDEN void
arm_local_addr_space_init(void)214 arm_local_addr_space_init (void)
215 {
216   memset (&local_addr_space, 0, sizeof (local_addr_space));
217   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
218   local_addr_space.acc.find_proc_info = arm_find_proc_info;
219   local_addr_space.acc.put_unwind_info = arm_put_unwind_info;
220   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
221   local_addr_space.acc.access_mem = access_mem;
222   local_addr_space.acc.access_reg = access_reg;
223   local_addr_space.acc.access_fpreg = access_fpreg;
224   local_addr_space.acc.resume = arm_local_resume;
225   local_addr_space.acc.get_proc_name = get_static_proc_name;
226   unw_flush_cache (&local_addr_space, 0, 0);
227 
228   map_local_init ();
229 }
230 
231 #endif /* !UNW_REMOTE_ONLY */
232