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