• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Advance to next CFI entry.
2    Copyright (C) 2009-2010, 2014 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
dwarf_next_cfi(const unsigned char e_ident[],Elf_Data * data,bool eh_frame_p,Dwarf_Off off,Dwarf_Off * next_off,Dwarf_CFI_Entry * entry)40 dwarf_next_cfi (const unsigned char e_ident[],
41 		Elf_Data *data,
42 		bool eh_frame_p,
43 		Dwarf_Off off,
44 		Dwarf_Off *next_off,
45 		Dwarf_CFI_Entry *entry)
46 {
47   /* Dummy struct for memory-access.h macros.  */
48   BYTE_ORDER_DUMMY (dw, e_ident);
49 
50   /* If we reached the end before don't do anything.  */
51   if (off == (Dwarf_Off) -1l
52       /* Make sure there is enough space in the .debug_frame section
53 	 for at least the initial word.  We cannot test the rest since
54 	 we don't know yet whether this is a 64-bit object or not.  */
55       || unlikely (off + 4 >= data->d_size))
56     {
57     done:
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 
84   /* Not explicitly in the DWARF spec, but mentioned in the LSB exception
85      frames (.eh_frame) spec. If Length contains the value 0, then this
86      CIE shall be considered a terminator and processing shall end.  */
87   if (length == 0)
88     goto done;
89 
90   if (unlikely ((uint64_t) (limit - bytes) < length)
91       || unlikely (length < offset_size + 1))
92     goto invalid;
93 
94   /* Now we know how large the entry is.  Note the trick in the
95      computation.  If the offset_size is 4 the '- 4' term undoes the
96      '2 *'.  If offset_size is 8 this term computes the size of the
97      escape value plus the 8 byte offset.  */
98   *next_off = off + (2 * offset_size - 4) + length;
99 
100   limit = bytes + length;
101 
102   const uint8_t *const cie_pointer_start = bytes;
103   if (offset_size == 8)
104     entry->cie.CIE_id = read_8ubyte_unaligned_inc (&dw, bytes);
105   else
106     {
107       entry->cie.CIE_id = read_4ubyte_unaligned_inc (&dw, bytes);
108       /* Canonicalize the 32-bit CIE_ID value to 64 bits.  */
109       if (!eh_frame_p && entry->cie.CIE_id == DW_CIE_ID_32)
110 	entry->cie.CIE_id = DW_CIE_ID_64;
111     }
112   if (eh_frame_p)
113     {
114       /* Canonicalize the .eh_frame CIE pointer to .debug_frame format.  */
115       if (entry->cie.CIE_id == 0)
116 	entry->cie.CIE_id = DW_CIE_ID_64;
117       else
118 	{
119 	  /* In .eh_frame format, a CIE pointer is the distance from where
120 	     it appears back to the beginning of the CIE.  */
121 	  ptrdiff_t pos = cie_pointer_start - (const uint8_t *) data->d_buf;
122 	  if (unlikely (entry->cie.CIE_id > (Dwarf_Off) pos)
123 	      || unlikely (pos <= (ptrdiff_t) offset_size))
124 	    goto invalid;
125 	  entry->cie.CIE_id = pos - entry->cie.CIE_id;
126 	}
127     }
128 
129   if (entry->cie.CIE_id == DW_CIE_ID_64)
130     {
131       /* Read the version stamp.  Always an 8-bit value.  */
132       uint8_t version = *bytes++;
133 
134       if (version != 1 && (unlikely (version < 3) || unlikely (version > 4)))
135 	goto invalid;
136 
137       entry->cie.augmentation = (const char *) bytes;
138 
139       bytes = memchr (bytes, '\0', limit - bytes);
140       if (unlikely (bytes == NULL))
141 	goto invalid;
142       ++bytes;
143 
144       /* The address size for CFI is implicit in the ELF class.  */
145       uint_fast8_t address_size = e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
146       uint_fast8_t segment_size = 0;
147       if (version >= 4)
148 	{
149 	  if (unlikely (limit - bytes < 5))
150 	    goto invalid;
151 	  /* XXX We don't actually support address_size not matching the class.
152 	     To do so, we'd have to return it here so that intern_new_cie
153 	     could use it choose a specific fde_encoding.  */
154 	  if (unlikely (*bytes != address_size))
155 	    {
156 	      __libdw_seterrno (DWARF_E_VERSION);
157 	      return -1;
158 	    }
159 	  address_size = *bytes++;
160 	  segment_size = *bytes++;
161 	  /* We don't actually support segment selectors.  We'd have to
162 	     roll this into the fde_encoding bits or something.  */
163 	  if (unlikely (segment_size != 0))
164 	    {
165 	      __libdw_seterrno (DWARF_E_VERSION);
166 	      return -1;
167 	    }
168 	}
169 
170       const char *ap = entry->cie.augmentation;
171 
172       /* g++ v2 "eh" has pointer immediately following augmentation string,
173 	 so it must be handled first.  */
174       if (unlikely (ap[0] == 'e' && ap[1] == 'h'))
175 	{
176 	  ap += 2;
177 	  bytes += address_size;
178 	}
179 
180       if (bytes >= limit)
181 	goto invalid;
182       get_uleb128 (entry->cie.code_alignment_factor, bytes, limit);
183 
184       if (bytes >= limit)
185 	goto invalid;
186       get_sleb128 (entry->cie.data_alignment_factor, bytes, limit);
187 
188       if (bytes >= limit)
189 	goto invalid;
190 
191       if (version >= 3)		/* DWARF 3+ */
192 	get_uleb128 (entry->cie.return_address_register, bytes, limit);
193       else			/* DWARF 2 */
194 	entry->cie.return_address_register = *bytes++;
195 
196       entry->cie.fde_augmentation_data_size = 0;
197       entry->cie.augmentation_data = bytes;
198       bool sized_augmentation = *ap == 'z';
199       if (sized_augmentation)
200 	{
201 	  ++ap;
202 	  if (bytes >= limit)
203 	    goto invalid;
204 	  get_uleb128 (entry->cie.augmentation_data_size, bytes, limit);
205 	  if ((Dwarf_Word) (limit - bytes) < entry->cie.augmentation_data_size)
206 	    goto invalid;
207 	  entry->cie.augmentation_data = bytes;
208 	}
209 
210       for (; *ap != '\0'; ++ap)
211 	{
212 	  uint8_t encoding;
213 	  switch (*ap)
214 	    {
215 	    case 'L':
216 	      if (sized_augmentation)
217 		{
218 		  /* Skip LSDA pointer encoding byte.  */
219 		  encoding = *bytes++;
220 		  entry->cie.fde_augmentation_data_size
221 		    += encoded_value_size (data, e_ident, encoding, NULL);
222 		  continue;
223 		}
224 	      break;
225 	    case 'R':
226 	      if (sized_augmentation)
227 		{
228 		  /* Skip FDE address encoding byte.  */
229 		  encoding = *bytes++;
230 		  continue;
231 		}
232 	      break;
233 	    case 'P':
234 	      if (sized_augmentation)
235 		{
236 		  /* Skip encoded personality routine pointer. */
237 		  encoding = *bytes++;
238 		  bytes += encoded_value_size (data, e_ident, encoding, bytes);
239 		  continue;
240 		}
241 	      break;
242 	    case 'S':
243 	      if (sized_augmentation)
244 		/* Skip signal-frame flag.  */
245 		continue;
246 	      break;
247 	    default:
248 	      /* Unknown augmentation string.  initial_instructions might
249 		 actually start with some augmentation data.  */
250 	      break;
251 	    }
252 	  break;
253 	}
254       if (! sized_augmentation)
255 	entry->cie.augmentation_data_size = bytes - entry->cie.augmentation_data;
256       else
257 	{
258 	  if (bytes > entry->cie.augmentation_data + entry->cie.augmentation_data_size)
259 	    goto invalid;
260 	  bytes = entry->cie.augmentation_data + entry->cie.augmentation_data_size;
261 	}
262 
263       entry->cie.initial_instructions = bytes;
264       entry->cie.initial_instructions_end = limit;
265     }
266   else
267     {
268       entry->fde.start = bytes;
269       entry->fde.end = limit;
270     }
271 
272   return 0;
273 }
274 INTDEF (dwarf_next_cfi)
275