Imported Upstream version 0.155
[platform/upstream/elfutils.git] / libdw / dwarf_next_cfi.c
1 /* Advance to next CFI entry.
2    Copyright (C) 2009-2010 Red Hat, Inc.
3    This file is part of elfutils.
4
5    This file is free software; you can redistribute it and/or modify
6    it under the terms of either
7
8      * the GNU Lesser General Public License as published by the Free
9        Software Foundation; either version 3 of the License, or (at
10        your option) any later version
11
12    or
13
14      * the GNU General Public License as published by the Free
15        Software Foundation; either version 2 of the License, or (at
16        your option) any later version
17
18    or both in parallel, as here.
19
20    elfutils is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23    General Public License for more details.
24
25    You should have received copies of the GNU General Public License and
26    the GNU Lesser General Public License along with this program.  If
27    not, see <http://www.gnu.org/licenses/>.  */
28
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32
33 #include "cfi.h"
34 #include "encoded-value.h"
35
36 #include <string.h>
37
38
39 int
40 dwarf_next_cfi (e_ident, data, eh_frame_p, off, next_off, entry)
41      const unsigned char e_ident[];
42      Elf_Data *data;
43      bool eh_frame_p;
44      Dwarf_Off off;
45      Dwarf_Off *next_off;
46      Dwarf_CFI_Entry *entry;
47 {
48   /* Dummy struct for memory-access.h macros.  */
49   BYTE_ORDER_DUMMY (dw, e_ident);
50
51   /* If we reached the end before don't do anything.  */
52   if (off == (Dwarf_Off) -1l
53       /* Make sure there is enough space in the .debug_frame section
54          for at least the initial word.  We cannot test the rest since
55          we don't know yet whether this is a 64-bit object or not.  */
56       || unlikely (off + 4 >= data->d_size))
57     {
58       *next_off = (Dwarf_Off) -1l;
59       return 1;
60     }
61
62   /* This points into the .debug_frame section at the start of the entry.  */
63   const uint8_t *bytes = data->d_buf + off;
64   const uint8_t *limit = data->d_buf + data->d_size;
65
66   /* The format of a CFI entry is described in DWARF3 6.4.1:
67    */
68
69   uint64_t length = read_4ubyte_unaligned_inc (&dw, bytes);
70   size_t offset_size = 4;
71   if (length == DWARF3_LENGTH_64_BIT)
72     {
73       /* This is the 64-bit DWARF format.  */
74       offset_size = 8;
75       if (unlikely (limit - bytes < 8))
76         {
77         invalid:
78           __libdw_seterrno (DWARF_E_INVALID_DWARF);
79           return -1;
80         }
81       length = read_8ubyte_unaligned_inc (&dw, bytes);
82     }
83   if (unlikely ((uint64_t) (limit - bytes) < length)
84       || unlikely (length < offset_size + 1))
85     goto invalid;
86
87   /* Now we know how large the entry is.  Note the trick in the
88      computation.  If the offset_size is 4 the '- 4' term undoes the
89      '2 *'.  If offset_size is 8 this term computes the size of the
90      escape value plus the 8 byte offset.  */
91   *next_off = off + (2 * offset_size - 4) + length;
92
93   limit = bytes + length;
94
95   const uint8_t *const cie_pointer_start = bytes;
96   if (offset_size == 8)
97     entry->cie.CIE_id = read_8ubyte_unaligned_inc (&dw, bytes);
98   else
99     {
100       entry->cie.CIE_id = read_4ubyte_unaligned_inc (&dw, bytes);
101       /* Canonicalize the 32-bit CIE_ID value to 64 bits.  */
102       if (!eh_frame_p && entry->cie.CIE_id == DW_CIE_ID_32)
103         entry->cie.CIE_id = DW_CIE_ID_64;
104     }
105   if (eh_frame_p)
106     {
107       /* Canonicalize the .eh_frame CIE pointer to .debug_frame format.  */
108       if (entry->cie.CIE_id == 0)
109         entry->cie.CIE_id = DW_CIE_ID_64;
110       else
111         {
112           /* In .eh_frame format, a CIE pointer is the distance from where
113              it appears back to the beginning of the CIE.  */
114           ptrdiff_t pos = cie_pointer_start - (const uint8_t *) data->d_buf;
115           if (unlikely (entry->cie.CIE_id > (Dwarf_Off) pos)
116               || unlikely (pos <= (ptrdiff_t) offset_size))
117             goto invalid;
118           entry->cie.CIE_id = pos - entry->cie.CIE_id;
119         }
120     }
121
122   if (entry->cie.CIE_id == DW_CIE_ID_64)
123     {
124       /* Read the version stamp.  Always an 8-bit value.  */
125       uint8_t version = *bytes++;
126
127       if (version != 1 && (unlikely (version < 3) || unlikely (version > 4)))
128         goto invalid;
129
130       entry->cie.augmentation = (const char *) bytes;
131
132       bytes = memchr (bytes, '\0', limit - bytes);
133       if (unlikely (bytes == NULL))
134         goto invalid;
135       ++bytes;
136
137       /* The address size for CFI is implicit in the ELF class.  */
138       uint_fast8_t address_size = e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
139       uint_fast8_t segment_size = 0;
140       if (version >= 4)
141         {
142           if (unlikely (limit - bytes < 5))
143             goto invalid;
144           /* XXX We don't actually support address_size not matching the class.
145              To do so, we'd have to return it here so that intern_new_cie
146              could use it choose a specific fde_encoding.  */
147           if (unlikely (*bytes != address_size))
148             {
149               __libdw_seterrno (DWARF_E_VERSION);
150               return -1;
151             }
152           address_size = *bytes++;
153           segment_size = *bytes++;
154           /* We don't actually support segment selectors.  We'd have to
155              roll this into the fde_encoding bits or something.  */
156           if (unlikely (segment_size != 0))
157             {
158               __libdw_seterrno (DWARF_E_VERSION);
159               return -1;
160             }
161         }
162
163       const char *ap = entry->cie.augmentation;
164
165       /* g++ v2 "eh" has pointer immediately following augmentation string,
166          so it must be handled first.  */
167       if (unlikely (ap[0] == 'e' && ap[1] == 'h'))
168         {
169           ap += 2;
170           bytes += address_size;
171         }
172
173       get_uleb128 (entry->cie.code_alignment_factor, bytes);
174       get_sleb128 (entry->cie.data_alignment_factor, bytes);
175
176       if (version >= 3)         /* DWARF 3+ */
177         get_uleb128 (entry->cie.return_address_register, bytes);
178       else                      /* DWARF 2 */
179         entry->cie.return_address_register = *bytes++;
180
181       /* If we have sized augmentation data,
182          we don't need to grok it all.  */
183       entry->cie.fde_augmentation_data_size = 0;
184       bool sized_augmentation = *ap == 'z';
185       if (sized_augmentation)
186         {
187           get_uleb128 (entry->cie.augmentation_data_size, bytes);
188           if ((Dwarf_Word) (limit - bytes) < entry->cie.augmentation_data_size)
189             goto invalid;
190           entry->cie.augmentation_data = bytes;
191           bytes += entry->cie.augmentation_data_size;
192         }
193       else
194         {
195           entry->cie.augmentation_data = bytes;
196
197           for (; *ap != '\0'; ++ap)
198             {
199               uint8_t encoding;
200               switch (*ap)
201                 {
202                 case 'L':               /* Skip LSDA pointer encoding byte.  */
203                 case 'R':               /* Skip FDE address encoding byte.  */
204                   encoding = *bytes++;
205                   entry->cie.fde_augmentation_data_size
206                     += encoded_value_size (data, e_ident, encoding, NULL);
207                   continue;
208                 case 'P':   /* Skip encoded personality routine pointer. */
209                   encoding = *bytes++;
210                   bytes += encoded_value_size (data, e_ident, encoding, bytes);
211                   continue;
212                 case 'S':               /* Skip signal-frame flag.  */
213                   continue;
214                 default:
215                   /* Unknown augmentation string.  initial_instructions might
216                      actually start with some augmentation data.  */
217                   break;
218                 }
219               break;
220             }
221           entry->cie.augmentation_data_size
222             = bytes - entry->cie.augmentation_data;
223         }
224
225       entry->cie.initial_instructions = bytes;
226       entry->cie.initial_instructions_end = limit;
227     }
228   else
229     {
230       entry->fde.start = bytes;
231       entry->fde.end = limit;
232     }
233
234   return 0;
235 }
236 INTDEF (dwarf_next_cfi)