1 /* libunwind - a platform-independent unwind library
2 Copyright (C) 2002, 2004 Hewlett-Packard Co
3 Copyright (C) 2007 David Mosberger-Tang
4 Contributed by David Mosberger-Tang <dmosberger@gmail.com>
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 void *addr;
47
48 if ((unsigned) (reg - UNW_HPPA_GR) < 32)
49 addr = &uc->uc_mcontext.sc_gr[reg - UNW_HPPA_GR];
50 else if ((unsigned) (reg - UNW_HPPA_FR) < 32)
51 addr = &uc->uc_mcontext.sc_fr[reg - UNW_HPPA_FR];
52 else
53 addr = NULL;
54 return addr;
55 }
56
57 # ifdef UNW_LOCAL_ONLY
58
59 void *
_Uhppa_uc_addr(ucontext_t * uc,int reg)60 _Uhppa_uc_addr (ucontext_t *uc, int reg)
61 {
62 return uc_addr (uc, reg);
63 }
64
65 # endif /* UNW_LOCAL_ONLY */
66
67 HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
68
69 /* XXX fix me: there is currently no way to locate the dyn-info list
70 by a remote unwinder. On ia64, this is done via a special
71 unwind-table entry. Perhaps something similar can be done with
72 DWARF2 unwind info. */
73
74 static void
put_unwind_info(unw_addr_space_t as,unw_proc_info_t * proc_info,void * arg)75 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
76 {
77 /* it's a no-op */
78 }
79
80 static int
get_dyn_info_list_addr(unw_addr_space_t as,unw_word_t * dyn_info_list_addr,void * arg)81 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
82 void *arg)
83 {
84 *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
85 return 0;
86 }
87
88 static int
access_mem(unw_addr_space_t as,unw_word_t addr,unw_word_t * val,int write,void * arg)89 access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
90 void *arg)
91 {
92 if (write)
93 {
94 /* ANDROID support update. */
95 #ifdef UNW_LOCAL_ONLY
96 if (map_local_is_writable (addr, sizeof(unw_word_t)))
97 {
98 #endif
99 Debug (12, "mem[%x] <- %x\n", addr, *val);
100 *(unw_word_t *) addr = *val;
101 #ifdef UNW_LOCAL_ONLY
102 }
103 else
104 {
105 Debug (12, "Unwritable memory mem[%x] <- %x\n", addr, *val);
106 return -1;
107 }
108 #endif
109 /* End of ANDROID update. */
110 }
111 else
112 {
113 /* ANDROID support update. */
114 #ifdef UNW_LOCAL_ONLY
115 if (map_local_is_readable (addr, sizeof(unw_word_t)))
116 {
117 #endif
118 *val = *(unw_word_t *) addr;
119 Debug (12, "mem[%x] -> %x\n", addr, *val);
120 #ifdef UNW_LOCAL_ONLY
121 }
122 else
123 {
124 Debug (12, "Unreadable memory mem[%x] -> XXX\n", addr);
125 return -1;
126 }
127 #endif
128 /* End of ANDROID update. */
129 }
130 return 0;
131 }
132
133 static int
access_reg(unw_addr_space_t as,unw_regnum_t reg,unw_word_t * val,int write,void * arg)134 access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
135 void *arg)
136 {
137 unw_word_t *addr;
138 ucontext_t *uc = arg;
139
140 if ((unsigned int) (reg - UNW_HPPA_FR) < 32)
141 goto badreg;
142
143 addr = uc_addr (uc, reg);
144 if (!addr)
145 goto badreg;
146
147 if (write)
148 {
149 *(unw_word_t *) addr = *val;
150 Debug (12, "%s <- %x\n", unw_regname (reg), *val);
151 }
152 else
153 {
154 *val = *(unw_word_t *) addr;
155 Debug (12, "%s -> %x\n", unw_regname (reg), *val);
156 }
157 return 0;
158
159 badreg:
160 Debug (1, "bad register number %u\n", reg);
161 return -UNW_EBADREG;
162 }
163
164 static int
access_fpreg(unw_addr_space_t as,unw_regnum_t reg,unw_fpreg_t * val,int write,void * arg)165 access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
166 int write, void *arg)
167 {
168 ucontext_t *uc = arg;
169 unw_fpreg_t *addr;
170
171 if ((unsigned) (reg - UNW_HPPA_FR) > 32)
172 goto badreg;
173
174 addr = uc_addr (uc, reg);
175 if (!addr)
176 goto badreg;
177
178 if (write)
179 {
180 Debug (12, "%s <- %08x.%08x\n",
181 unw_regname (reg), val->raw.bits[1], val->raw.bits[0]);
182 *(unw_fpreg_t *) addr = *val;
183 }
184 else
185 {
186 *val = *(unw_fpreg_t *) addr;
187 Debug (12, "%s -> %08x.%08x\n",
188 unw_regname (reg), val->raw.bits[1], val->raw.bits[0]);
189 }
190 return 0;
191
192 badreg:
193 Debug (1, "bad register number %u\n", reg);
194 /* attempt to access a non-preserved register */
195 return -UNW_EBADREG;
196 }
197
198 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)199 get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
200 char *buf, size_t buf_len, unw_word_t *offp,
201 void *arg)
202 {
203 return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp, arg);
204 }
205
206 HIDDEN void
hppa_local_addr_space_init(void)207 hppa_local_addr_space_init (void)
208 {
209 memset (&local_addr_space, 0, sizeof (local_addr_space));
210 local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
211 local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
212 local_addr_space.acc.put_unwind_info = put_unwind_info;
213 local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
214 local_addr_space.acc.access_mem = access_mem;
215 local_addr_space.acc.access_reg = access_reg;
216 local_addr_space.acc.access_fpreg = access_fpreg;
217 local_addr_space.acc.resume = hppa_local_resume;
218 local_addr_space.acc.get_proc_name = get_static_proc_name;
219 unw_flush_cache (&local_addr_space, 0, 0);
220
221 map_local_init ();
222 }
223
224 #endif /* !UNW_REMOTE_ONLY */
225