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