• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libunwind - a platform-independent unwind library
2    Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
3         Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4 
5 This file is part of libunwind.
6 
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14 
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
25 
26 #include "dwarf_i.h"
27 #define UPDATE_VERSION 3
28 static inline int
is_cie_id(unw_word_t val,int is_debug_frame)29 is_cie_id (unw_word_t val, int is_debug_frame)
30 {
31   /* The CIE ID is normally 0xffffffff (for 32-bit ELF) or
32      0xffffffffffffffff (for 64-bit ELF).  However, .eh_frame
33      uses 0.  */
34   if (is_debug_frame)
35       return (val == (uint32_t)(-1) || val == (uint64_t)(-1));
36   else
37     return (val == 0);
38 }
39 
40 /* Note: we don't need to keep track of more than the first four
41    characters of the augmentation string, because we (a) ignore any
42    augmentation string contents once we find an unrecognized character
43    and (b) those characters that we do recognize, can't be
44    repeated.  */
45 static inline int
parse_cie(unw_addr_space_t as,unw_accessors_t * a,unw_word_t addr,const unw_proc_info_t * pi,struct dwarf_cie_info * dci,int is_debug_frame,void * arg)46 parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
47            const unw_proc_info_t *pi, struct dwarf_cie_info *dci,
48            int is_debug_frame, void *arg)
49 {
50   uint8_t version, ch, augstr[5], fde_encoding, handler_encoding;
51   uint8_t address_size, segment_size;
52   unw_word_t len, cie_end_addr, aug_size;
53   uint32_t u32val;
54   uint64_t u64val;
55   size_t i;
56   int ret;
57 # define STR2(x)        #x
58 # define STR(x)         STR2(x)
59 
60   /* Pick appropriate default for FDE-encoding.  DWARF spec says
61      start-IP (initial_location) and the code-size (address_range) are
62      "address-unit sized constants".  The `R' augmentation can be used
63      to override this, but by default, we pick an address-sized unit
64      for fde_encoding.  */
65   switch (dwarf_addr_size (as))
66     {
67     case 4:     fde_encoding = DW_EH_PE_udata4; break;
68     case 8:     fde_encoding = DW_EH_PE_udata8; break;
69     default:    fde_encoding = DW_EH_PE_omit; break;
70     }
71 
72   dci->lsda_encoding = DW_EH_PE_omit;
73   dci->handler = 0;
74 
75   if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0)
76     return ret;
77 
78   if (u32val != 0xffffffff)
79     {
80       /* the CIE is in the 32-bit DWARF format */
81       uint32_t cie_id;
82       /* DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 */
83       const uint32_t expected_id = (is_debug_frame) ? 0xffffffff : 0;
84 
85       len = u32val;
86       cie_end_addr = addr + len;
87       if ((ret = dwarf_readu32 (as, a, &addr, &cie_id, arg)) < 0)
88         return ret;
89       if (cie_id != expected_id)
90         {
91           Debug (1, "Unexpected CIE id %x\n", cie_id);
92           return -UNW_EINVAL;
93         }
94     }
95   else
96     {
97       /* the CIE is in the 64-bit DWARF format */
98       uint64_t cie_id;
99       /* DWARF says CIE id should be 0xffffffffffffffff, but in
100          .eh_frame, it's 0 */
101       const uint64_t expected_id = (is_debug_frame) ? 0xffffffffffffffffull : 0;
102 
103       if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0)
104         return ret;
105       len = u64val;
106       cie_end_addr = addr + len;
107       if ((ret = dwarf_readu64 (as, a, &addr, &cie_id, arg)) < 0)
108         return ret;
109       if (cie_id != expected_id)
110         {
111           Debug (1, "Unexpected CIE id %llx\n", (long long) cie_id);
112           return -UNW_EINVAL;
113         }
114     }
115   dci->cie_instr_end = cie_end_addr;
116 
117   if ((ret = dwarf_readu8 (as, a, &addr, &version, arg)) < 0)
118     return ret;
119 
120   /* GCC emits version 1??? */
121   if (version != 1 && (version < DWARF_CIE_VERSION || version > DWARF_CIE_VERSION_MAX))
122     {
123       Debug (1, "Got CIE version %u, expected version 1 or between "
124              STR (DWARF_CIE_VERSION) " and " STR (DWARF_CIE_VERSION_MAX) "\n", version);
125       return -UNW_EBADVERSION;
126     }
127 
128   /* read and parse the augmentation string: */
129   memset (augstr, 0, sizeof (augstr));
130   for (i = 0;;)
131     {
132       if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0)
133         return ret;
134 
135       if (!ch)
136         break;  /* end of augmentation string */
137 
138       if (i < sizeof (augstr) - 1)
139         augstr[i++] = ch;
140     }
141 
142   if (version > UPDATE_VERSION)
143   {
144     if ((ret = dwarf_readu8(as, a, &addr, &address_size, arg)) < 0)
145       return ret;
146 
147     if ((ret = dwarf_readu8(as, a, &addr, &segment_size, arg)) < 0)
148       return ret;
149   }
150 
151   if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->code_align, arg)) < 0
152       || (ret = dwarf_read_sleb128 (as, a, &addr, &dci->data_align, arg)) < 0)
153     return ret;
154 
155   /* Read the return-address column either as a u8 or as a uleb128.  */
156   if (version == 1)
157     {
158       if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0)
159         return ret;
160       dci->ret_addr_column = ch;
161     }
162   else if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->ret_addr_column,
163                                       arg)) < 0)
164     return ret;
165 
166   i = 0;
167   if (augstr[0] == 'z')
168     {
169       dci->sized_augmentation = 1;
170       if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0)
171         return ret;
172       i++;
173     }
174 
175   for (; i < sizeof (augstr) && augstr[i]; ++i)
176     switch (augstr[i])
177       {
178       case 'L':
179         /* read the LSDA pointer-encoding format.  */
180         if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0)
181           return ret;
182         dci->lsda_encoding = ch;
183         break;
184 
185       case 'R':
186         /* read the FDE pointer-encoding format.  */
187         if ((ret = dwarf_readu8 (as, a, &addr, &fde_encoding, arg)) < 0)
188           return ret;
189         break;
190 
191       case 'P':
192         /* read the personality-routine pointer-encoding format.  */
193         if ((ret = dwarf_readu8 (as, a, &addr, &handler_encoding, arg)) < 0)
194           return ret;
195         if ((ret = dwarf_read_encoded_pointer (as, a, &addr, handler_encoding,
196                                                pi, &dci->handler, arg)) < 0)
197           return ret;
198         break;
199 
200       case 'S':
201         /* This is a signal frame. */
202         dci->signal_frame = 1;
203 
204         /* Temporarily set it to one so dwarf_parse_fde() knows that
205            it should fetch the actual ABI/TAG pair from the FDE.  */
206         dci->have_abi_marker = 1;
207         break;
208 
209       default:
210         Debug (1, "Unexpected augmentation string `%s'\n", augstr);
211         if (dci->sized_augmentation)
212           /* If we have the size of the augmentation body, we can skip
213              over the parts that we don't understand, so we're OK. */
214           goto done;
215         else
216           return -UNW_EINVAL;
217       }
218  done:
219   dci->fde_encoding = fde_encoding;
220   dci->cie_instr_start = addr;
221   Debug (15, "CIE parsed OK, augmentation = \"%s\", handler=0x%lx\n",
222          augstr, (long) dci->handler);
223   return 0;
224 }
225 
226 /* Extract proc-info from the FDE starting at address ADDR.
227 
228    Pass BASE as zero for eh_frame behaviour, or a pointer to
229    debug_frame base for debug_frame behaviour.  */
230 
231 HIDDEN int
dwarf_extract_proc_info_from_fde(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addrp,unw_proc_info_t * pi,unw_word_t base,int need_unwind_info,int is_debug_frame,void * arg)232 dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a,
233                                   unw_word_t *addrp, unw_proc_info_t *pi,
234                                   unw_word_t base,
235                                   int need_unwind_info, int is_debug_frame,
236                                   void *arg)
237 {
238   unw_word_t fde_end_addr, cie_addr, cie_offset_addr, aug_end_addr = 0;
239   unw_word_t start_ip, ip_range, aug_size, addr = *addrp;
240   int ret, ip_range_encoding;
241   struct dwarf_cie_info dci;
242   uint64_t u64val;
243   uint32_t u32val;
244 
245   Debug (12, "FDE @ 0x%lx\n", (long) addr);
246 
247   memset (&dci, 0, sizeof (dci));
248 
249   if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0)
250     return ret;
251 
252   if (u32val != 0xffffffff)
253     {
254       int32_t cie_offset = 0;
255 
256       /* In some configurations, an FDE with a 0 length indicates the
257          end of the FDE-table.  */
258       if (u32val == 0)
259         return -UNW_ENOINFO;
260 
261       /* the FDE is in the 32-bit DWARF format */
262 
263       *addrp = fde_end_addr = addr + u32val;
264       cie_offset_addr = addr;
265 
266       if ((ret = dwarf_reads32 (as, a, &addr, &cie_offset, arg)) < 0)
267         return ret;
268 
269       if (is_cie_id (cie_offset, is_debug_frame))
270         /* ignore CIEs (happens during linear searches) */
271         return 0;
272 
273       if (is_debug_frame)
274         cie_addr = base + cie_offset;
275       else
276         /* DWARF says that the CIE_pointer in the FDE is a
277            .debug_frame-relative offset, but the GCC-generated .eh_frame
278            sections instead store a "pcrelative" offset, which is just
279            as fine as it's self-contained.  */
280         cie_addr = cie_offset_addr - cie_offset;
281     }
282   else
283     {
284       int64_t cie_offset = 0;
285 
286       /* the FDE is in the 64-bit DWARF format */
287 
288       if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0)
289         return ret;
290 
291       *addrp = fde_end_addr = addr + u64val;
292       cie_offset_addr = addr;
293 
294       if ((ret = dwarf_reads64 (as, a, &addr, &cie_offset, arg)) < 0)
295         return ret;
296 
297       if (is_cie_id (cie_offset, is_debug_frame))
298         /* ignore CIEs (happens during linear searches) */
299         return 0;
300 
301       if (is_debug_frame)
302         cie_addr = base + cie_offset;
303       else
304         /* DWARF says that the CIE_pointer in the FDE is a
305            .debug_frame-relative offset, but the GCC-generated .eh_frame
306            sections instead store a "pcrelative" offset, which is just
307            as fine as it's self-contained.  */
308         cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset);
309     }
310 
311   Debug (15, "looking for CIE at address %lx\n", (long) cie_addr);
312 
313   if ((ret = parse_cie (as, a, cie_addr, pi, &dci, is_debug_frame, arg)) < 0)
314     return ret;
315 
316   /* IP-range has same encoding as FDE pointers, except that it's
317      always an absolute value: */
318   ip_range_encoding = dci.fde_encoding & DW_EH_PE_FORMAT_MASK;
319 
320   if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.fde_encoding,
321                                          pi, &start_ip, arg)) < 0
322       || (ret = dwarf_read_encoded_pointer (as, a, &addr, ip_range_encoding,
323                                             pi, &ip_range, arg)) < 0)
324     return ret;
325   pi->start_ip = start_ip;
326   pi->end_ip = start_ip + ip_range;
327   pi->handler = dci.handler;
328 
329   if (dci.sized_augmentation)
330     {
331       if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0)
332         return ret;
333       aug_end_addr = addr + aug_size;
334     }
335 
336   if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.lsda_encoding,
337                                          pi, &pi->lsda, arg)) < 0)
338     return ret;
339 
340   Debug (15, "FDE covers IP 0x%lx-0x%lx, LSDA=0x%lx\n",
341          (long) pi->start_ip, (long) pi->end_ip, (long) pi->lsda);
342 
343   if (need_unwind_info)
344     {
345       pi->format = UNW_INFO_FORMAT_TABLE;
346       pi->unwind_info_size = sizeof (dci);
347       pi->unwind_info = mempool_alloc (&dwarf_cie_info_pool);
348       if (!pi->unwind_info)
349         return -UNW_ENOMEM;
350 
351       if (dci.have_abi_marker)
352         {
353           if ((ret = dwarf_readu16 (as, a, &addr, &dci.abi, arg)) < 0
354               || (ret = dwarf_readu16 (as, a, &addr, &dci.tag, arg)) < 0)
355             return ret;
356           Debug (13, "Found ABI marker = (abi=%u, tag=%u)\n",
357                  dci.abi, dci.tag);
358         }
359 
360       if (dci.sized_augmentation)
361         dci.fde_instr_start = aug_end_addr;
362       else
363         dci.fde_instr_start = addr;
364       dci.fde_instr_end = fde_end_addr;
365 
366       memcpy (pi->unwind_info, &dci, sizeof (dci));
367     }
368   return 0;
369 }
370