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