• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libunwind - a platform-independent unwind library
2    Copyright (C) 2006-2007 IBM
3    Contributed by
4      Corey Ashford <cjashfor@us.ibm.com>
5      Jose Flavio Aguilar Paulino <jflavio@br.ibm.com> <joseflavio@gmail.com>
6 
7 This file is part of libunwind.
8 
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16 
17 The above copyright notice and this permission notice shall be
18 included in all copies or substantial portions of the Software.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
27 
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "ucontext_i.h"
32 #include "unwind_i.h"
33 
34 #ifdef UNW_REMOTE_ONLY
35 
36 /* unw_local_addr_space is a NULL pointer in this case.  */
37 unw_addr_space_t unw_local_addr_space;
38 
39 #else /* !UNW_REMOTE_ONLY */
40 
41 static struct unw_addr_space local_addr_space;
42 
43 unw_addr_space_t unw_local_addr_space = &local_addr_space;
44 
45 static void *
uc_addr(ucontext_t * uc,int reg)46 uc_addr (ucontext_t *uc, int reg)
47 {
48   void *addr;
49 
50   if ((unsigned) (reg - UNW_PPC64_R0) < 32)
51 #if defined(__linux__)
52     addr = &uc->uc_mcontext.gp_regs[reg - UNW_PPC64_R0];
53 #elif defined(__FreeBSD__)
54     addr = &uc->uc_mcontext.mc_gpr[reg - UNW_PPC64_R0];
55 #endif
56 
57   else if ((unsigned) (reg - UNW_PPC64_F0) < 32)
58 #if defined(__linux__)
59     addr = &uc->uc_mcontext.fp_regs[reg - UNW_PPC64_F0];
60 #elif defined(__FreeBSD__)
61     addr = &uc->uc_mcontext.mc_fpreg[reg - UNW_PPC64_F0];
62 #endif
63 
64   else if ((unsigned) (reg - UNW_PPC64_V0) < 32)
65 #if defined(__linux__)
66     addr = (uc->uc_mcontext.v_regs == 0) ? NULL : &uc->uc_mcontext.v_regs->vrregs[reg - UNW_PPC64_V0][0];
67 #elif defined(__FreeBSD__)
68     addr = &uc->uc_mcontext.mc_avec[(reg - UNW_PPC64_V0)*2];
69 #endif
70 
71   else
72     {
73       unsigned gregs_idx;
74 
75       switch (reg)
76         {
77         case UNW_PPC64_NIP:
78           gregs_idx = NIP_IDX;
79           break;
80         case UNW_PPC64_CTR:
81           gregs_idx = CTR_IDX;
82           break;
83         case UNW_PPC64_LR:
84           gregs_idx = LINK_IDX;
85           break;
86         case UNW_PPC64_XER:
87           gregs_idx = XER_IDX;
88           break;
89         case UNW_PPC64_CR0:
90           gregs_idx = CCR_IDX;
91           break;
92         default:
93           return NULL;
94         }
95 #if defined(__linux__)
96       addr = &uc->uc_mcontext.gp_regs[gregs_idx];
97 #elif defined(__FreeBSD__)
98       addr = &uc->uc_mcontext.mc_gpr[gregs_idx];
99 #endif
100     }
101   return addr;
102 }
103 
104 # ifdef UNW_LOCAL_ONLY
105 
106 HIDDEN void *
tdep_uc_addr(ucontext_t * uc,int reg)107 tdep_uc_addr (ucontext_t *uc, int reg)
108 {
109   return uc_addr (uc, reg);
110 }
111 
112 # endif /* UNW_LOCAL_ONLY */
113 
114 static void
put_unwind_info(unw_addr_space_t as,unw_proc_info_t * proc_info,void * arg)115 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
116 {
117   /* it's a no-op */
118 }
119 
120 static int
get_dyn_info_list_addr(unw_addr_space_t as,unw_word_t * dyn_info_list_addr,void * arg)121 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
122                         void *arg)
123 {
124 #ifndef UNW_LOCAL_ONLY
125 # pragma weak _U_dyn_info_list_addr
126   if (!_U_dyn_info_list_addr)
127     return -UNW_ENOINFO;
128 #endif
129   // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
130   *dyn_info_list_addr = _U_dyn_info_list_addr ();
131   return 0;
132 }
133 
134 static int
access_mem(unw_addr_space_t as,unw_word_t addr,unw_word_t * val,int write,void * arg)135 access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
136             void *arg)
137 {
138   if (write)
139     {
140       Debug (12, "mem[%lx] <- %lx\n", addr, *val);
141       *(unw_word_t *) addr = *val;
142     }
143   else
144     {
145       *val = *(unw_word_t *) addr;
146       Debug (12, "mem[%lx] -> %lx\n", addr, *val);
147     }
148   return 0;
149 }
150 
151 static int
access_reg(unw_addr_space_t as,unw_regnum_t reg,unw_word_t * val,int write,void * arg)152 access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
153             int write, void *arg)
154 {
155   unw_word_t *addr;
156   ucontext_t *uc = arg;
157 
158   if (UNW_PPC64_F0 <= reg && reg <= UNW_PPC64_F31)
159     goto badreg;
160   if (UNW_PPC64_V0 <= reg && reg <= UNW_PPC64_V31)
161     goto badreg;
162 
163   addr = uc_addr (uc, reg);
164   if (!addr)
165     goto badreg;
166 
167   if (write)
168     {
169       *(unw_word_t *) addr = *val;
170       Debug (12, "%s <- %lx\n", unw_regname (reg), *val);
171     }
172   else
173     {
174       *val = *(unw_word_t *) addr;
175       Debug (12, "%s -> %lx\n", unw_regname (reg), *val);
176     }
177   return 0;
178 
179 badreg:
180   Debug (1, "bad register number %u\n", reg);
181   return -UNW_EBADREG;
182 }
183 
184 static int
access_fpreg(unw_addr_space_t as,unw_regnum_t reg,unw_fpreg_t * val,int write,void * arg)185 access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
186               int write, void *arg)
187 {
188   ucontext_t *uc = arg;
189   unw_fpreg_t *addr;
190 
191   /* Allow only 32 fregs and 32 vregs */
192   if (!(((unsigned) (reg - UNW_PPC64_F0) < 32)
193 	||((unsigned) (reg - UNW_PPC64_V0) < 32)))
194     goto badreg;
195 
196   addr = uc_addr (uc, reg);
197   if (!addr)
198     goto badreg;
199 
200   if (write)
201     {
202       Debug (12, "%s <- %016Lf\n", unw_regname (reg), *val);
203       *(unw_fpreg_t *) addr = *val;
204     }
205   else
206     {
207       *val = *(unw_fpreg_t *) addr;
208       Debug (12, "%s -> %016Lf\n", unw_regname (reg), *val);
209     }
210   return 0;
211 
212 badreg:
213   Debug (1, "bad register number %u\n", reg);
214   /* attempt to access a non-preserved register */
215   return -UNW_EBADREG;
216 }
217 
218 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)219 get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
220                       char *buf, size_t buf_len, unw_word_t *offp,
221                       void *arg)
222 {
223   return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp);
224 }
225 
226 HIDDEN void
ppc64_local_addr_space_init(void)227 ppc64_local_addr_space_init (void)
228 {
229   memset (&local_addr_space, 0, sizeof (local_addr_space));
230   local_addr_space.big_endian = target_is_big_endian();
231 #if _CALL_ELF == 2
232   local_addr_space.abi = UNW_PPC64_ABI_ELFv2;
233 #else
234   local_addr_space.abi = UNW_PPC64_ABI_ELFv1;
235 #endif
236   local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
237   local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
238   local_addr_space.acc.put_unwind_info = put_unwind_info;
239   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
240   local_addr_space.acc.access_mem = access_mem;
241   local_addr_space.acc.access_reg = access_reg;
242   local_addr_space.acc.access_fpreg = access_fpreg;
243   local_addr_space.acc.resume = ppc64_local_resume;
244   local_addr_space.acc.get_proc_name = get_static_proc_name;
245   unw_flush_cache (&local_addr_space, 0, 0);
246 }
247 
248 #endif /* !UNW_REMOTE_ONLY */
249