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
39int
40dwarf_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}
274INTDEF (dwarf_next_cfi)
275