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 "dwarf_i.h"
29 #include "ex_tables.h"
30 #include "offsets.h"
31
32 #include <signal.h>
33
34 static inline int
arm_exidx_step(struct cursor * c)35 arm_exidx_step (struct cursor *c)
36 {
37 unw_word_t old_ip, old_cfa;
38 uint8_t buf[32];
39 int ret;
40
41 old_ip = c->dwarf.ip;
42 old_cfa = c->dwarf.cfa;
43
44 /* mark PC unsaved */
45 c->dwarf.loc[UNW_ARM_R15] = DWARF_NULL_LOC;
46
47 if ((ret = tdep_find_proc_info (&c->dwarf, c->dwarf.ip, 1)) < 0)
48 return ret;
49
50 if (c->dwarf.pi.format != UNW_INFO_FORMAT_ARM_EXIDX)
51 return -UNW_ENOINFO;
52
53 ret = arm_exidx_extract (&c->dwarf, buf);
54 if (ret == -UNW_ESTOPUNWIND)
55 return 0;
56 else if (ret < 0)
57 return ret;
58
59 ret = arm_exidx_decode (buf, ret, &c->dwarf);
60 if (ret < 0)
61 return ret;
62
63 if (c->dwarf.ip == old_ip && c->dwarf.cfa == old_cfa)
64 {
65 Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
66 __FUNCTION__, (long) c->dwarf.ip);
67 return -UNW_EBADFRAME;
68 }
69
70 c->dwarf.pi_valid = 0;
71
72 return (c->dwarf.ip == 0) ? 0 : 1;
73 }
74
75 PROTECTED int
unw_step(unw_cursor_t * cursor)76 unw_step (unw_cursor_t *cursor)
77 {
78 struct cursor *c = (struct cursor *) cursor;
79 int ret = -UNW_EUNSPEC;
80
81 Debug (1, "(cursor=%p, ip=0x%lx, cfa=0x%lx))\n",
82 c, (long) c->dwarf.ip, (long) c->dwarf.cfa);
83
84 /* Check if this is a signal frame. */
85 ret = unw_is_signal_frame (cursor);
86 if (ret < 0)
87 {
88 Debug (2, "returning %d\n", ret);
89 return ret;
90 }
91 if (ret)
92 {
93 ret = unw_handle_signal_frame (cursor);
94 Debug (2, "returning %d\n", ret);
95 return ret;
96 }
97
98 #ifdef CONFIG_DEBUG_FRAME
99 /* First, try DWARF-based unwinding. */
100 if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF))
101 {
102 ret = dwarf_step (&c->dwarf);
103 Debug(1, "dwarf_step()=%d\n", ret);
104
105 if (likely (ret > 0))
106 return 1;
107 else if (unlikely (ret == -UNW_ESTOPUNWIND))
108 return ret;
109
110 if (ret < 0 && ret != -UNW_ENOINFO)
111 {
112 Debug (2, "returning %d\n", ret);
113 return ret;
114 }
115 }
116 #endif /* CONFIG_DEBUG_FRAME */
117
118 /* Next, try extbl-based unwinding. */
119 if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX))
120 {
121 ret = arm_exidx_step (c);
122 if (ret > 0)
123 return 1;
124 if (ret == -UNW_ESTOPUNWIND || ret == 0)
125 return ret;
126 }
127
128 /* Fall back on APCS frame parsing.
129 Note: This won't work in case the ARM EABI is used. */
130 if (unlikely (ret < 0))
131 {
132 if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME))
133 {
134 ret = UNW_ESUCCESS;
135 /* DWARF unwinding failed, try to follow APCS/optimized APCS frame chain */
136 unw_word_t instr, i;
137 Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
138 dwarf_loc_t ip_loc, fp_loc;
139 unw_word_t frame;
140 /* Mark all registers unsaved, since we don't know where
141 they are saved (if at all), except for the EBP and
142 EIP. */
143 if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R11], &frame) < 0)
144 {
145 return 0;
146 }
147 for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) {
148 c->dwarf.loc[i] = DWARF_NULL_LOC;
149 }
150 if (frame)
151 {
152 if (dwarf_get(&c->dwarf, DWARF_LOC(frame, 0), &instr) < 0)
153 {
154 return 0;
155 }
156 instr -= 8;
157 if (dwarf_get(&c->dwarf, DWARF_LOC(instr, 0), &instr) < 0)
158 {
159 return 0;
160 }
161 if ((instr & 0xFFFFD800) == 0xE92DD800)
162 {
163 /* Standard APCS frame. */
164 ip_loc = DWARF_LOC(frame - 4, 0);
165 fp_loc = DWARF_LOC(frame - 12, 0);
166 }
167 else
168 {
169 /* Codesourcery optimized normal frame. */
170 ip_loc = DWARF_LOC(frame, 0);
171 fp_loc = DWARF_LOC(frame - 4, 0);
172 }
173 if (dwarf_get(&c->dwarf, ip_loc, &c->dwarf.ip) < 0)
174 {
175 return 0;
176 }
177 c->dwarf.loc[UNW_ARM_R12] = ip_loc;
178 c->dwarf.loc[UNW_ARM_R11] = fp_loc;
179 c->dwarf.pi_valid = 0;
180 Debug(15, "ip=%lx\n", (long) c->dwarf.ip);
181 }
182 else
183 {
184 ret = -UNW_ENOINFO;
185 }
186 }
187 }
188 return ret == -UNW_ENOINFO ? 0 : 1;
189 }
190