• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "map_info.h"
34 
35 #define arm_exidx_step  UNW_OBJ(arm_exidx_step)
36 static inline int
arm_exidx_step(struct cursor * c)37 arm_exidx_step (struct cursor *c)
38 {
39   unw_word_t old_ip, old_cfa;
40   uint8_t buf[32];
41   int ret;
42 
43   old_ip = c->dwarf.ip;
44   old_cfa = c->dwarf.cfa;
45 
46   /* mark PC unsaved */
47   c->dwarf.loc[UNW_ARM_R15] = DWARF_NULL_LOC;
48   unw_word_t ip = c->dwarf.ip;
49   if (c->dwarf.use_prev_instr)
50     /* The least bit denotes thumb/arm mode, clear it. */
51     ip = (ip & ~(unw_word_t)0x1) - 1;
52 
53   /* check dynamic info first --- it overrides everything else */
54   ret = unwi_find_dynamic_proc_info (c->dwarf.as, ip, &c->dwarf.pi, 1,
55                                      c->dwarf.as_arg);
56   if (ret == -UNW_ENOINFO)
57     {
58       if ((ret = tdep_find_proc_info (&c->dwarf, ip, 1)) < 0)
59         return ret;
60     }
61 
62   if (c->dwarf.pi.format != UNW_INFO_FORMAT_ARM_EXIDX)
63     return -UNW_ENOINFO;
64 
65   ret = arm_exidx_extract (&c->dwarf, buf);
66   if (ret == -UNW_ESTOPUNWIND)
67     return 0;
68   else if (ret < 0)
69     return ret;
70 
71   ret = arm_exidx_decode (buf, ret, &c->dwarf);
72   if (ret < 0)
73     return ret;
74 
75   if (c->dwarf.ip == old_ip && c->dwarf.cfa == old_cfa)
76     {
77       Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
78                __FUNCTION__, (long) c->dwarf.ip);
79       return -UNW_EBADFRAME;
80     }
81 
82   c->dwarf.pi_valid = 0;
83   return (c->dwarf.ip == 0) ? 0 : 1;
84 }
85 
86 int
unw_step(unw_cursor_t * cursor)87 unw_step (unw_cursor_t *cursor)
88 {
89   struct cursor *c = (struct cursor *) cursor;
90   int ret = -UNW_EUNSPEC;
91 
92   Debug (1, "(cursor=%p)\n", c);
93 
94   /* Check if this is a signal frame. */
95   if (unw_is_signal_frame (cursor) > 0){
96       /* Add for using lr backtrace when pc is zero */
97       ret = arm_handle_signal_frame (cursor);
98       if ( c->dwarf.ip == 0x0 )
99       {
100           unw_word_t lr;
101           if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R14], &lr) >= 0)
102           {
103               if (lr != c->dwarf.ip)
104               {
105                   Debug(1, "fix ip = 0 action \n");
106                   c->dwarf.ip = lr;
107                   return ret;
108               }
109           }
110       }
111       return ret;
112       /* Add for using lr backtrace when pc is zero */
113   }
114 
115 #ifdef CONFIG_DEBUG_FRAME
116   /* First, try DWARF-based unwinding. */
117   if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF))
118     {
119       ret = dwarf_step (&c->dwarf);
120       Debug(1, "dwarf_step()=%d\n", ret);
121 
122       if (likely (ret > 0))
123         return 1;
124       else if (unlikely (ret == -UNW_ESTOPUNWIND))
125         return ret;
126 
127       if (ret < 0 && ret != -UNW_ENOINFO)
128         {
129           Debug (2, "returning %d\n", ret);
130           return ret;
131         }
132     }
133 #endif /* CONFIG_DEBUG_FRAME */
134 
135   /* Next, try extbl-based unwinding. */
136   if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX))
137     {
138       Debug (13, "%s(ret=%d), trying extbl\n",
139              UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) ? "dwarf_step() failed " : "",
140              ret);
141       ret = arm_exidx_step (c);
142       if (ret > 0)
143         return 1;
144       if (ret == -UNW_ESTOPUNWIND || ret == 0)
145         ret = -1; // try frame pointer
146     }
147 
148   /* Fall back on APCS frame parsing.
149      Note: This won't work in case the ARM EABI is used. */
150 #ifdef __FreeBSD__
151   if (0)
152 #else
153   if (unlikely (ret < 0))
154 #endif
155     {
156       if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME))
157         {
158           Debug (13, "%s%s%s%s(ret=%d), trying frame-chain\n",
159                  UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) ? "dwarf_step() " : "",
160                  (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) && UNW_TRY_METHOD(UNW_ARM_METHOD_EXIDX)) ? "and " : "",
161                  UNW_TRY_METHOD(UNW_ARM_METHOD_EXIDX) ? "arm_exidx_step() " : "",
162                  (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) || UNW_TRY_METHOD(UNW_ARM_METHOD_EXIDX)) ? "failed " : "",
163                  ret);
164           ret = UNW_ESUCCESS;
165           /* DWARF unwinding failed, try to follow APCS/optimized APCS frame chain */
166           unw_word_t instr, i;
167           dwarf_loc_t ip_loc, fp_loc;
168           unw_word_t frame;
169           /* Mark all registers unsaved, since we don't know where
170              they are saved (if at all), except for the EBP and
171              EIP.  */
172           if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R11], &frame) < 0)
173             {
174               return 0;
175             }
176           for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) {
177             c->dwarf.loc[i] = DWARF_NULL_LOC;
178           }
179           if (frame)
180             {
181 #ifndef CC_IS_CLANG
182               if (dwarf_get(&c->dwarf, DWARF_LOC(frame, 0), &instr) < 0)
183                 {
184                   return 0;
185                 }
186               instr -= 8;
187               if (dwarf_get(&c->dwarf, DWARF_LOC(instr, 0), &instr) < 0)
188                 {
189                   return 0;
190                 }
191               if ((instr & 0xFFFFD800) == 0xE92DD800)
192                 {
193                   /* Standard APCS frame. */
194                   ip_loc = DWARF_LOC(frame - 4, 0);
195                   fp_loc = DWARF_LOC(frame - 12, 0);
196                 }
197               else
198                 {
199                   /* Codesourcery optimized normal frame. */
200                   ip_loc = DWARF_LOC(frame, 0);
201                   fp_loc = DWARF_LOC(frame - 4, 0);
202                 }
203 #else
204               ip_loc = DWARF_LOC(frame + 4, 0);
205               fp_loc = DWARF_LOC(frame, 0);
206               if (dwarf_get(&c->dwarf, ip_loc, &c->dwarf.ip) < 0)
207                 {
208                   return 0;
209                 }
210               c->dwarf.loc[UNW_ARM_R12] = ip_loc;
211               c->dwarf.loc[UNW_ARM_R11] = fp_loc;
212               return 1;
213 #endif
214               if (dwarf_get(&c->dwarf, ip_loc, &c->dwarf.ip) < 0)
215                 {
216                   return 0;
217                 }
218               c->dwarf.loc[UNW_ARM_R12] = ip_loc;
219               c->dwarf.loc[UNW_ARM_R11] = fp_loc;
220               c->dwarf.pi_valid = 0;
221               Debug(15, "ip=%x\n", c->dwarf.ip);
222             }
223           else
224             {
225               ret = -UNW_ENOINFO;
226             }
227         }
228     }
229   return ret == -UNW_ENOINFO ? 0 : ret;
230 }
231