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