• 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(e_ident,data,eh_frame_p,off,next_off,entry)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       if (bytes >= limit)
174 	goto invalid;
175       get_uleb128 (entry->cie.code_alignment_factor, bytes, limit);
176 
177       if (bytes >= limit)
178 	goto invalid;
179       get_sleb128 (entry->cie.data_alignment_factor, bytes, limit);
180 
181       if (bytes >= limit)
182 	goto invalid;
183 
184       if (version >= 3)		/* DWARF 3+ */
185 	get_uleb128 (entry->cie.return_address_register, bytes, limit);
186       else			/* DWARF 2 */
187 	entry->cie.return_address_register = *bytes++;
188 
189       /* If we have sized augmentation data,
190 	 we don't need to grok it all.  */
191       entry->cie.fde_augmentation_data_size = 0;
192       bool sized_augmentation = *ap == 'z';
193       if (sized_augmentation)
194 	{
195 	  if (bytes >= limit)
196 	    goto invalid;
197 	  get_uleb128 (entry->cie.augmentation_data_size, bytes, limit);
198 	  if ((Dwarf_Word) (limit - bytes) < entry->cie.augmentation_data_size)
199 	    goto invalid;
200 	  entry->cie.augmentation_data = bytes;
201 	  bytes += entry->cie.augmentation_data_size;
202 	}
203       else
204 	{
205 	  entry->cie.augmentation_data = bytes;
206 
207 	  for (; *ap != '\0'; ++ap)
208 	    {
209 	      uint8_t encoding;
210 	      switch (*ap)
211 		{
212 		case 'L':		/* Skip LSDA pointer encoding byte.  */
213 		case 'R':		/* Skip FDE address encoding byte.  */
214 		  encoding = *bytes++;
215 		  entry->cie.fde_augmentation_data_size
216 		    += encoded_value_size (data, e_ident, encoding, NULL);
217 		  continue;
218 		case 'P':   /* Skip encoded personality routine pointer. */
219 		  encoding = *bytes++;
220 		  bytes += encoded_value_size (data, e_ident, encoding, bytes);
221 		  continue;
222 		case 'S':		/* Skip signal-frame flag.  */
223 		  continue;
224 		default:
225 		  /* Unknown augmentation string.  initial_instructions might
226 		     actually start with some augmentation data.  */
227 		  break;
228 		}
229 	      break;
230 	    }
231 	  entry->cie.augmentation_data_size
232 	    = bytes - entry->cie.augmentation_data;
233 	}
234 
235       entry->cie.initial_instructions = bytes;
236       entry->cie.initial_instructions_end = limit;
237     }
238   else
239     {
240       entry->fde.start = bytes;
241       entry->fde.end = limit;
242     }
243 
244   return 0;
245 }
246 INTDEF (dwarf_next_cfi)
247