blob: 358d9b77a4302724c85b0ce92e781edd42034b21 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/* ARM EABI compliant unwinding routines
2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3 Contributed by Paul Brook
4
5 This file is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any
8 later version.
9
10 In addition to the permissions in the GNU General Public License, the
11 Free Software Foundation gives you unlimited permission to link the
12 compiled version of this file into combinations with other programs,
13 and to distribute those combinations without any restriction coming
14 from the use of this file. (The General Public License restrictions
15 do apply in other respects; for example, they cover modification of
16 the file, and distribution when not linked into a combine
17 executable.)
18
19 This file is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; see the file COPYING. If not, write to
26 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
27 Boston, MA 02110-1301, USA. */
28
29/****************************************************************************
30 * The functions here are derived from gcc/config/arm/pr-support.c from the
31 * 4.3.x release. The main changes here involve the use of ptrace to retrieve
32 * memory/processor states from a remote process.
33 ****************************************************************************/
34
35#include <sys/types.h>
36#include <unwind.h>
37
38#include "utility.h"
39
40/* We add a prototype for abort here to avoid creating a dependency on
41 target headers. */
42extern void abort (void);
43
44/* Derived from _Unwind_VRS_Pop to use ptrace */
45extern _Unwind_VRS_Result
46unwind_VRS_Pop_with_ptrace (_Unwind_Context *context,
47 _Unwind_VRS_RegClass regclass,
48 _uw discriminator,
49 _Unwind_VRS_DataRepresentation representation,
50 pid_t pid);
51
52typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
53
54/* Misc constants. */
55#define R_IP 12
56#define R_SP 13
57#define R_LR 14
58#define R_PC 15
59
60#define uint32_highbit (((_uw) 1) << 31)
61
62void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
63
64/* Unwind descriptors. */
65
66typedef struct
67{
68 _uw16 length;
69 _uw16 offset;
70} EHT16;
71
72typedef struct
73{
74 _uw length;
75 _uw offset;
76} EHT32;
77
78/* Personality routine helper functions. */
79
80#define CODE_FINISH (0xb0)
81
82/* Derived from next_unwind_byte to use ptrace */
83/* Return the next byte of unwinding information, or CODE_FINISH if there is
84 no data remaining. */
85static inline _uw8
86next_unwind_byte_with_ptrace (__gnu_unwind_state * uws, pid_t pid)
87{
88 _uw8 b;
89
90 if (uws->bytes_left == 0)
91 {
92 /* Load another word */
93 if (uws->words_left == 0)
94 return CODE_FINISH; /* Nothing left. */
95 uws->words_left--;
96 uws->data = get_remote_word(pid, uws->next);
97 uws->next++;
98 uws->bytes_left = 3;
99 }
100 else
101 uws->bytes_left--;
102
103 /* Extract the most significant byte. */
104 b = (uws->data >> 24) & 0xff;
105 uws->data <<= 8;
106 return b;
107}
108
109/* Execute the unwinding instructions described by UWS. */
110_Unwind_Reason_Code
111unwind_execute_with_ptrace(_Unwind_Context * context, __gnu_unwind_state * uws,
112 pid_t pid)
113{
114 _uw op;
115 int set_pc;
116 _uw reg;
117
118 set_pc = 0;
119 for (;;)
120 {
121 op = next_unwind_byte_with_ptrace (uws, pid);
122 if (op == CODE_FINISH)
123 {
124 /* If we haven't already set pc then copy it from lr. */
125 if (!set_pc)
126 {
127 _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
128 &reg);
129 _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
130 &reg);
131 set_pc = 1;
132 }
133 /* Drop out of the loop. */
134 break;
135 }
136 if ((op & 0x80) == 0)
137 {
138 /* vsp = vsp +- (imm6 << 2 + 4). */
139 _uw offset;
140
141 offset = ((op & 0x3f) << 2) + 4;
142 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
143 if (op & 0x40)
144 reg -= offset;
145 else
146 reg += offset;
147 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
148 continue;
149 }
150
151 if ((op & 0xf0) == 0x80)
152 {
153 op = (op << 8) | next_unwind_byte_with_ptrace (uws, pid);
154 if (op == 0x8000)
155 {
156 /* Refuse to unwind. */
157 return _URC_FAILURE;
158 }
159 /* Pop r4-r15 under mask. */
160 op = (op << 4) & 0xfff0;
161 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, op, _UVRSD_UINT32,
162 pid)
163 != _UVRSR_OK)
164 return _URC_FAILURE;
165 if (op & (1 << R_PC))
166 set_pc = 1;
167 continue;
168 }
169 if ((op & 0xf0) == 0x90)
170 {
171 op &= 0xf;
172 if (op == 13 || op == 15)
173 /* Reserved. */
174 return _URC_FAILURE;
175 /* vsp = r[nnnn]. */
176 _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, &reg);
177 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
178 continue;
179 }
180 if ((op & 0xf0) == 0xa0)
181 {
182 /* Pop r4-r[4+nnn], [lr]. */
183 _uw mask;
184
185 mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
186 if (op & 8)
187 mask |= (1 << R_LR);
188 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, mask, _UVRSD_UINT32,
189 pid)
190 != _UVRSR_OK)
191 return _URC_FAILURE;
192 continue;
193 }
194 if ((op & 0xf0) == 0xb0)
195 {
196 /* op == 0xb0 already handled. */
197 if (op == 0xb1)
198 {
199 op = next_unwind_byte_with_ptrace (uws, pid);
200 if (op == 0 || ((op & 0xf0) != 0))
201 /* Spare. */
202 return _URC_FAILURE;
203 /* Pop r0-r4 under mask. */
204 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, op,
205 _UVRSD_UINT32, pid)
206 != _UVRSR_OK)
207 return _URC_FAILURE;
208 continue;
209 }
210 if (op == 0xb2)
211 {
212 /* vsp = vsp + 0x204 + (uleb128 << 2). */
213 int shift;
214
215 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
216 &reg);
217 op = next_unwind_byte_with_ptrace (uws, pid);
218 shift = 2;
219 while (op & 0x80)
220 {
221 reg += ((op & 0x7f) << shift);
222 shift += 7;
223 op = next_unwind_byte_with_ptrace (uws, pid);
224 }
225 reg += ((op & 0x7f) << shift) + 0x204;
226 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
227 &reg);
228 continue;
229 }
230 if (op == 0xb3)
231 {
232 /* Pop VFP registers with fldmx. */
233 op = next_unwind_byte_with_ptrace (uws, pid);
234 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
235 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_VFPX,
236 pid)
237 != _UVRSR_OK)
238 return _URC_FAILURE;
239 continue;
240 }
241 if ((op & 0xfc) == 0xb4)
242 {
243 /* Pop FPA E[4]-E[4+nn]. */
244 op = 0x40000 | ((op & 3) + 1);
245 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_FPA, op, _UVRSD_FPAX,
246 pid)
247 != _UVRSR_OK)
248 return _URC_FAILURE;
249 continue;
250 }
251 /* op & 0xf8 == 0xb8. */
252 /* Pop VFP D[8]-D[8+nnn] with fldmx. */
253 op = 0x80000 | ((op & 7) + 1);
254 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_VFPX, pid)
255 != _UVRSR_OK)
256 return _URC_FAILURE;
257 continue;
258 }
259 if ((op & 0xf0) == 0xc0)
260 {
261 if (op == 0xc6)
262 {
263 /* Pop iWMMXt D registers. */
264 op = next_unwind_byte_with_ptrace (uws, pid);
265 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
266 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXD, op,
267 _UVRSD_UINT64, pid)
268 != _UVRSR_OK)
269 return _URC_FAILURE;
270 continue;
271 }
272 if (op == 0xc7)
273 {
274 op = next_unwind_byte_with_ptrace (uws, pid);
275 if (op == 0 || (op & 0xf0) != 0)
276 /* Spare. */
277 return _URC_FAILURE;
278 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
279 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXC, op,
280 _UVRSD_UINT32, pid)
281 != _UVRSR_OK)
282 return _URC_FAILURE;
283 continue;
284 }
285 if ((op & 0xf8) == 0xc0)
286 {
287 /* Pop iWMMXt wR[10]-wR[10+nnn]. */
288 op = 0xa0000 | ((op & 0xf) + 1);
289 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXD, op,
290 _UVRSD_UINT64, pid)
291 != _UVRSR_OK)
292 return _URC_FAILURE;
293 continue;
294 }
295 if (op == 0xc8)
296 {
297#ifndef __VFP_FP__
298 /* Pop FPA registers. */
299 op = next_unwind_byte_with_ptrace (uws, pid);
300 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
301 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_FPA, op, _UVRSD_FPAX,
302 pid)
303 != _UVRSR_OK)
304 return _URC_FAILURE;
305 continue;
306#else
307 /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */
308 op = next_unwind_byte_with_ptrace (uws, pid);
309 op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1);
310 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op,
311 _UVRSD_DOUBLE, pid)
312 != _UVRSR_OK)
313 return _URC_FAILURE;
314 continue;
315#endif
316 }
317 if (op == 0xc9)
318 {
319 /* Pop VFP registers with fldmd. */
320 op = next_unwind_byte_with_ptrace (uws, pid);
321 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
322 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op,
323 _UVRSD_DOUBLE, pid)
324 != _UVRSR_OK)
325 return _URC_FAILURE;
326 continue;
327 }
328 /* Spare. */
329 return _URC_FAILURE;
330 }
331 if ((op & 0xf8) == 0xd0)
332 {
333 /* Pop VFP D[8]-D[8+nnn] with fldmd. */
334 op = 0x80000 | ((op & 7) + 1);
335 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_DOUBLE,
336 pid)
337 != _UVRSR_OK)
338 return _URC_FAILURE;
339 continue;
340 }
341 /* Spare. */
342 return _URC_FAILURE;
343 }
344 return _URC_OK;
345}