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>
6 This file is part of libunwind.
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:
16 The above copyright notice and this permission notice shall be
17 included in all copies or substantial portions of the Software.
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. */
29 #include "ex_tables.h"
33 #define arm_exidx_step UNW_OBJ(arm_exidx_step)
36 arm_exidx_step (struct cursor *c)
38 unw_word_t old_ip, old_cfa;
43 old_cfa = c->dwarf.cfa;
46 c->dwarf.loc[UNW_ARM_R15] = DWARF_NULL_LOC;
47 unw_word_t ip = c->dwarf.ip;
48 if (c->dwarf.use_prev_instr)
51 /* check dynamic info first --- it overrides everything else */
52 ret = unwi_find_dynamic_proc_info (c->dwarf.as, ip, &c->dwarf.pi, 1,
54 if (ret == -UNW_ENOINFO)
56 if ((ret = tdep_find_proc_info (&c->dwarf, ip, 1)) < 0)
60 if (c->dwarf.pi.format != UNW_INFO_FORMAT_ARM_EXIDX)
63 ret = arm_exidx_extract (&c->dwarf, buf);
64 if (ret == -UNW_ESTOPUNWIND)
69 ret = arm_exidx_decode (buf, ret, &c->dwarf);
73 if (c->dwarf.ip == old_ip && c->dwarf.cfa == old_cfa)
75 Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
76 __FUNCTION__, (long) c->dwarf.ip);
77 return -UNW_EBADFRAME;
80 c->dwarf.pi_valid = 0;
82 return (c->dwarf.ip == 0) ? 0 : 1;
86 unw_step (unw_cursor_t *cursor)
88 struct cursor *c = (struct cursor *) cursor;
89 int ret = -UNW_EUNSPEC;
91 Debug (1, "(cursor=%p)\n", c);
93 /* Check if this is a signal frame. */
94 if (unw_is_signal_frame (cursor) > 0)
95 return arm_handle_signal_frame (cursor);
97 #ifdef CONFIG_DEBUG_FRAME
98 /* First, try DWARF-based unwinding. */
99 if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF))
101 ret = dwarf_step (&c->dwarf);
102 Debug(1, "dwarf_step()=%d\n", ret);
104 if (likely (ret > 0))
106 else if (unlikely (ret == -UNW_ESTOPUNWIND))
109 if (ret < 0 && ret != -UNW_ENOINFO)
111 Debug (2, "returning %d\n", ret);
115 #endif /* CONFIG_DEBUG_FRAME */
117 /* Next, try extbl-based unwinding. */
118 if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX))
120 ret = arm_exidx_step (c);
123 if (ret == -UNW_ESTOPUNWIND || ret == 0)
127 /* Fall back on APCS frame parsing.
128 Note: This won't work in case the ARM EABI is used. */
132 if (unlikely (ret < 0))
135 if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME))
137 Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
139 /* DWARF unwinding failed, try to follow APCS/optimized APCS frame chain */
141 dwarf_loc_t ip_loc, fp_loc;
143 /* Mark all registers unsaved, since we don't know where
144 they are saved (if at all), except for the EBP and
146 if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R11], &frame) < 0)
150 for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) {
151 c->dwarf.loc[i] = DWARF_NULL_LOC;
155 if (dwarf_get(&c->dwarf, DWARF_LOC(frame, 0), &instr) < 0)
160 if (dwarf_get(&c->dwarf, DWARF_LOC(instr, 0), &instr) < 0)
164 if ((instr & 0xFFFFD800) == 0xE92DD800)
166 /* Standard APCS frame. */
167 ip_loc = DWARF_LOC(frame - 4, 0);
168 fp_loc = DWARF_LOC(frame - 12, 0);
172 /* Codesourcery optimized normal frame. */
173 ip_loc = DWARF_LOC(frame, 0);
174 fp_loc = DWARF_LOC(frame - 4, 0);
176 if (dwarf_get(&c->dwarf, ip_loc, &c->dwarf.ip) < 0)
180 c->dwarf.loc[UNW_ARM_R12] = ip_loc;
181 c->dwarf.loc[UNW_ARM_R11] = fp_loc;
182 c->dwarf.pi_valid = 0;
183 Debug(15, "ip=%x\n", c->dwarf.ip);
191 return ret == -UNW_ENOINFO ? 0 : ret;