1 /* libunwind - a platform-independent unwind library
2 Copyright (C) 2008 CodeSourcery
3 Copyright 2011 Linaro Limited
4 Copyright (C) 2012 Tommi Rantala <tt.rantala@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 "unwind_i.h"
28 #include "offsets.h"
29 #include "ex_tables.h"
30
31 #include <signal.h>
32
33 #define arm_exidx_step UNW_OBJ(arm_exidx_step)
34
35 static inline int
arm_exidx_step(struct cursor * c)36 arm_exidx_step (struct cursor *c)
37 {
38 unw_word_t old_ip, old_cfa;
39 uint8_t buf[32];
40 int ret;
41
42 old_ip = c->dwarf.ip;
43 old_cfa = c->dwarf.cfa;
44
45 /* mark PC unsaved */
46 c->dwarf.loc[UNW_ARM_R15] = DWARF_NULL_LOC;
47
48 if ((ret = tdep_find_proc_info (&c->dwarf, c->dwarf.ip, 1)) < 0)
49 return ret;
50
51 if (c->dwarf.pi.format != UNW_INFO_FORMAT_ARM_EXIDX)
52 return -UNW_ENOINFO;
53
54 ret = arm_exidx_extract (&c->dwarf, buf);
55 if (ret == -UNW_ESTOPUNWIND)
56 return 0;
57 else if (ret < 0)
58 return ret;
59
60 ret = arm_exidx_decode (buf, ret, &c->dwarf);
61 if (ret < 0)
62 return ret;
63
64 if (c->dwarf.ip == old_ip && c->dwarf.cfa == old_cfa)
65 {
66 Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
67 __FUNCTION__, (long) c->dwarf.ip);
68 return -UNW_EBADFRAME;
69 }
70
71 c->dwarf.pi_valid = 0;
72
73 return (c->dwarf.ip == 0) ? 0 : 1;
74 }
75
76 /* ANDROID support update. */
77
78 /* When taking a step back up the stack, the pc will point to the next
79 * instruction to execute, not the currently executing instruction. This
80 * function adjusts the pc to the currently executing instruction.
81 */
adjust_ip(struct cursor * c)82 static void adjust_ip(struct cursor *c)
83 {
84 unw_word_t ip, value;
85 ip = c->dwarf.ip;
86
87 if (ip)
88 {
89 int adjust = 4;
90 if (ip & 1)
91 {
92 /* Thumb instructions, the currently executing instruction could be
93 * 2 or 4 bytes, so adjust appropriately.
94 */
95 unw_addr_space_t as;
96 unw_accessors_t *a;
97 void *arg;
98
99 as = c->dwarf.as;
100 a = unw_get_accessors (as);
101 arg = c->dwarf.as_arg;
102
103 if (ip < 5 || (*a->access_mem) (as, ip-5, &value, 0, arg) < 0 ||
104 (value & 0xe000f000) != 0xe000f000)
105 adjust = 2;
106 }
107 c->dwarf.ip -= adjust;
108 }
109 }
110 /* End of ANDROID update. */
111
112 PROTECTED int
unw_handle_signal_frame(unw_cursor_t * cursor)113 unw_handle_signal_frame (unw_cursor_t *cursor)
114 {
115 struct cursor *c = (struct cursor *) cursor;
116 int ret;
117 unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa;
118 struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0);
119
120 if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0)
121 return -UNW_EUNSPEC;
122
123 /* Obtain signal frame type (non-RT or RT). */
124 ret = unw_is_signal_frame (cursor);
125
126 /* Save the SP and PC to be able to return execution at this point
127 later in time (unw_resume). */
128 c->sigcontext_sp = c->dwarf.cfa;
129 c->sigcontext_pc = c->dwarf.ip;
130
131 /* Since kernel version 2.6.18 the non-RT signal frame starts with a
132 ucontext while the RT signal frame starts with a siginfo, followed
133 by a sigframe whose first element is an ucontext.
134 Prior 2.6.18 the non-RT signal frame starts with a sigcontext while
135 the RT signal frame starts with two pointers followed by a siginfo
136 and an ucontext. The first pointer points to the start of the siginfo
137 structure and the second one to the ucontext structure. */
138
139 if (ret == 1)
140 {
141 /* Handle non-RT signal frames. Check if the first word on the stack
142 is the magic number. */
143 if (sp == 0x5ac3c35a)
144 {
145 c->sigcontext_format = ARM_SCF_LINUX_SIGFRAME;
146 sc_addr = sp_addr + LINUX_UC_MCONTEXT_OFF;
147 }
148 else
149 {
150 c->sigcontext_format = ARM_SCF_LINUX_OLD_SIGFRAME;
151 sc_addr = sp_addr;
152 }
153 }
154 else if (ret == 2)
155 {
156 /* Handle RT signal frames. Check if the first word on the stack is a
157 pointer to the siginfo structure. */
158 if (sp == sp_addr + 8)
159 {
160 c->sigcontext_format = ARM_SCF_LINUX_OLD_RT_SIGFRAME;
161 sc_addr = sp_addr + 8 + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF;
162 }
163 else
164 {
165 c->sigcontext_format = ARM_SCF_LINUX_RT_SIGFRAME;
166 sc_addr = sp_addr + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF;
167 }
168 }
169 else
170 return -UNW_EUNSPEC;
171
172 c->sigcontext_addr = sc_addr;
173
174 /* Update the dwarf cursor.
175 Set the location of the registers to the corresponding addresses of the
176 uc_mcontext / sigcontext structure contents. */
177 c->dwarf.loc[UNW_ARM_R0] = DWARF_LOC (sc_addr + LINUX_SC_R0_OFF, 0);
178 c->dwarf.loc[UNW_ARM_R1] = DWARF_LOC (sc_addr + LINUX_SC_R1_OFF, 0);
179 c->dwarf.loc[UNW_ARM_R2] = DWARF_LOC (sc_addr + LINUX_SC_R2_OFF, 0);
180 c->dwarf.loc[UNW_ARM_R3] = DWARF_LOC (sc_addr + LINUX_SC_R3_OFF, 0);
181 c->dwarf.loc[UNW_ARM_R4] = DWARF_LOC (sc_addr + LINUX_SC_R4_OFF, 0);
182 c->dwarf.loc[UNW_ARM_R5] = DWARF_LOC (sc_addr + LINUX_SC_R5_OFF, 0);
183 c->dwarf.loc[UNW_ARM_R6] = DWARF_LOC (sc_addr + LINUX_SC_R6_OFF, 0);
184 c->dwarf.loc[UNW_ARM_R7] = DWARF_LOC (sc_addr + LINUX_SC_R7_OFF, 0);
185 c->dwarf.loc[UNW_ARM_R8] = DWARF_LOC (sc_addr + LINUX_SC_R8_OFF, 0);
186 c->dwarf.loc[UNW_ARM_R9] = DWARF_LOC (sc_addr + LINUX_SC_R9_OFF, 0);
187 c->dwarf.loc[UNW_ARM_R10] = DWARF_LOC (sc_addr + LINUX_SC_R10_OFF, 0);
188 c->dwarf.loc[UNW_ARM_R11] = DWARF_LOC (sc_addr + LINUX_SC_FP_OFF, 0);
189 c->dwarf.loc[UNW_ARM_R12] = DWARF_LOC (sc_addr + LINUX_SC_IP_OFF, 0);
190 c->dwarf.loc[UNW_ARM_R13] = DWARF_LOC (sc_addr + LINUX_SC_SP_OFF, 0);
191 c->dwarf.loc[UNW_ARM_R14] = DWARF_LOC (sc_addr + LINUX_SC_LR_OFF, 0);
192 c->dwarf.loc[UNW_ARM_R15] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0);
193
194 /* Set SP/CFA and PC/IP. */
195 dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R13], &c->dwarf.cfa);
196 dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R15], &c->dwarf.ip);
197
198 c->dwarf.pi_valid = 0;
199
200 return 1;
201 }
202
203 PROTECTED int
unw_step(unw_cursor_t * cursor)204 unw_step (unw_cursor_t *cursor)
205 {
206 struct cursor *c = (struct cursor *) cursor;
207 int ret = -UNW_EUNSPEC;
208
209 Debug (1, "(cursor=%p)\n", c);
210
211 /* Check if this is a signal frame. */
212 if (unw_is_signal_frame (cursor))
213 {
214 ret = unw_handle_signal_frame (cursor);
215 }
216
217 #ifdef CONFIG_DEBUG_FRAME
218 /* First, try DWARF-based unwinding. */
219 if (ret < 0 && UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF))
220 {
221 ret = dwarf_step (&c->dwarf);
222 Debug(1, "dwarf_step()=%d\n", ret);
223
224 if (likely (ret > 0))
225 ret = 1;
226 else if (unlikely (ret == -UNW_ESTOPUNWIND))
227 ret = 0;
228 }
229 #endif /* CONFIG_DEBUG_FRAME */
230
231 /* Next, try extbl-based unwinding. */
232 if (ret < 0 && UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX))
233 {
234 ret = arm_exidx_step (c);
235 if (ret > 0)
236 ret = 1;
237 if (ret == -UNW_ESTOPUNWIND || ret == 0)
238 ret = 0;
239 }
240
241 /* Fall back on APCS frame parsing.
242 Note: This won't work in case the ARM EABI is used. */
243 if (unlikely (ret < 0))
244 {
245 if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME))
246 {
247 ret = UNW_ESUCCESS;
248 /* DWARF unwinding failed, try to follow APCS/optimized APCS frame chain */
249 unw_word_t instr, i;
250 Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
251 dwarf_loc_t ip_loc, fp_loc;
252 unw_word_t frame;
253 /* Mark all registers unsaved, since we don't know where
254 they are saved (if at all), except for the EBP and
255 EIP. */
256 if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R11], &frame) < 0)
257 {
258 return 0;
259 }
260 for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) {
261 c->dwarf.loc[i] = DWARF_NULL_LOC;
262 }
263 if (frame)
264 {
265 if (dwarf_get(&c->dwarf, DWARF_LOC(frame, 0), &instr) < 0)
266 {
267 return 0;
268 }
269 instr -= 8;
270 if (dwarf_get(&c->dwarf, DWARF_LOC(instr, 0), &instr) < 0)
271 {
272 return 0;
273 }
274 if ((instr & 0xFFFFD800) == 0xE92DD800)
275 {
276 /* Standard APCS frame. */
277 ip_loc = DWARF_LOC(frame - 4, 0);
278 fp_loc = DWARF_LOC(frame - 12, 0);
279 }
280 else
281 {
282 /* Codesourcery optimized normal frame. */
283 ip_loc = DWARF_LOC(frame, 0);
284 fp_loc = DWARF_LOC(frame - 4, 0);
285 }
286 if (dwarf_get(&c->dwarf, ip_loc, &c->dwarf.ip) < 0)
287 {
288 return 0;
289 }
290 c->dwarf.loc[UNW_ARM_R12] = ip_loc;
291 c->dwarf.loc[UNW_ARM_R11] = fp_loc;
292 c->dwarf.pi_valid = 0;
293 Debug(15, "ip=%x\n", c->dwarf.ip);
294 }
295 else
296 {
297 ret = -UNW_ENOINFO;
298 }
299 }
300 }
301
302 /* ANDROID support update. */
303 if (ret < 0 && UNW_TRY_METHOD(UNW_ARM_METHOD_LR) && c->dwarf.frame == 0)
304 {
305 /* If this is the first frame, the code may be executing garbage
306 * in the middle of nowhere. In this case, try using the lr as
307 * the pc.
308 */
309 unw_word_t lr;
310 if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R14], &lr) >= 0)
311 {
312 if (lr != c->dwarf.ip)
313 {
314 ret = 1;
315 c->dwarf.ip = lr;
316 }
317 }
318 }
319 /* End of ANDROID update. */
320
321 if (ret >= 0)
322 {
323 c->dwarf.frame++;
324 adjust_ip(c);
325 }
326 return ret == -UNW_ENOINFO ? 0 : ret;
327 }
328