/src/elfutils/libdw/dwarf_next_cfi.c
Line | Count | Source |
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 |
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 | 0 | { |
47 | | /* Dummy struct for memory-access.h macros. */ |
48 | 0 | BYTE_ORDER_DUMMY (dw, e_ident); |
49 | | |
50 | | /* If we reached the end before don't do anything. */ |
51 | 0 | 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 | 0 | || unlikely (off + 4 >= data->d_size)) |
56 | 0 | { |
57 | 0 | done: |
58 | 0 | *next_off = (Dwarf_Off) -1l; |
59 | 0 | return 1; |
60 | 0 | } |
61 | | |
62 | | /* This points into the .debug_frame section at the start of the entry. */ |
63 | 0 | const uint8_t *bytes = data->d_buf + off; |
64 | 0 | 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 | 0 | uint64_t length = read_4ubyte_unaligned_inc (&dw, bytes); |
70 | 0 | size_t offset_size = 4; |
71 | 0 | if (length == DWARF3_LENGTH_64_BIT) |
72 | 0 | { |
73 | | /* This is the 64-bit DWARF format. */ |
74 | 0 | offset_size = 8; |
75 | 0 | if (unlikely (limit - bytes < 8)) |
76 | 0 | { |
77 | 0 | invalid: |
78 | 0 | __libdw_seterrno (DWARF_E_INVALID_DWARF); |
79 | 0 | return -1; |
80 | 0 | } |
81 | 0 | length = read_8ubyte_unaligned_inc (&dw, bytes); |
82 | 0 | } |
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 | 0 | if (length == 0) |
88 | 0 | goto done; |
89 | | |
90 | 0 | if (unlikely ((uint64_t) (limit - bytes) < length) |
91 | 0 | || unlikely (length < offset_size + 1)) |
92 | 0 | 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 | 0 | *next_off = off + (2 * offset_size - 4) + length; |
99 | |
|
100 | 0 | limit = bytes + length; |
101 | |
|
102 | 0 | const uint8_t *const cie_pointer_start = bytes; |
103 | 0 | if (offset_size == 8) |
104 | 0 | entry->cie.CIE_id = read_8ubyte_unaligned_inc (&dw, bytes); |
105 | 0 | else |
106 | 0 | { |
107 | 0 | entry->cie.CIE_id = read_4ubyte_unaligned_inc (&dw, bytes); |
108 | | /* Canonicalize the 32-bit CIE_ID value to 64 bits. */ |
109 | 0 | if (!eh_frame_p && entry->cie.CIE_id == DW_CIE_ID_32) |
110 | 0 | entry->cie.CIE_id = DW_CIE_ID_64; |
111 | 0 | } |
112 | 0 | if (eh_frame_p) |
113 | 0 | { |
114 | | /* Canonicalize the .eh_frame CIE pointer to .debug_frame format. */ |
115 | 0 | if (entry->cie.CIE_id == 0) |
116 | 0 | entry->cie.CIE_id = DW_CIE_ID_64; |
117 | 0 | else |
118 | 0 | { |
119 | | /* In .eh_frame format, a CIE pointer is the distance from where |
120 | | it appears back to the beginning of the CIE. */ |
121 | 0 | ptrdiff_t pos = cie_pointer_start - (const uint8_t *) data->d_buf; |
122 | 0 | if (unlikely (entry->cie.CIE_id > (Dwarf_Off) pos) |
123 | 0 | || unlikely (pos <= (ptrdiff_t) offset_size)) |
124 | 0 | goto invalid; |
125 | 0 | entry->cie.CIE_id = pos - entry->cie.CIE_id; |
126 | 0 | } |
127 | 0 | } |
128 | | |
129 | 0 | if (entry->cie.CIE_id == DW_CIE_ID_64) |
130 | 0 | { |
131 | | /* Read the version stamp. Always an 8-bit value. */ |
132 | 0 | uint8_t version = *bytes++; |
133 | |
|
134 | 0 | if (version != 1 && (unlikely (version < 3) || unlikely (version > 4))) |
135 | 0 | goto invalid; |
136 | | |
137 | 0 | entry->cie.augmentation = (const char *) bytes; |
138 | |
|
139 | 0 | bytes = memchr (bytes, '\0', limit - bytes); |
140 | 0 | if (unlikely (bytes == NULL)) |
141 | 0 | goto invalid; |
142 | 0 | ++bytes; |
143 | | |
144 | | /* The address size for CFI is implicit in the ELF class. */ |
145 | 0 | uint_fast8_t address_size = e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; |
146 | 0 | uint_fast8_t segment_size = 0; |
147 | 0 | if (version >= 4) |
148 | 0 | { |
149 | 0 | if (unlikely (limit - bytes < 5)) |
150 | 0 | 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 | 0 | if (unlikely (*bytes != address_size)) |
155 | 0 | { |
156 | 0 | __libdw_seterrno (DWARF_E_VERSION); |
157 | 0 | return -1; |
158 | 0 | } |
159 | 0 | address_size = *bytes++; |
160 | 0 | 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 | 0 | if (unlikely (segment_size != 0)) |
164 | 0 | { |
165 | 0 | __libdw_seterrno (DWARF_E_VERSION); |
166 | 0 | return -1; |
167 | 0 | } |
168 | 0 | } |
169 | | |
170 | 0 | 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 | 0 | if (unlikely (ap[0] == 'e' && ap[1] == 'h')) |
175 | 0 | { |
176 | 0 | ap += 2; |
177 | 0 | bytes += address_size; |
178 | 0 | } |
179 | |
|
180 | 0 | if (bytes >= limit) |
181 | 0 | goto invalid; |
182 | 0 | get_uleb128 (entry->cie.code_alignment_factor, bytes, limit); |
183 | |
|
184 | 0 | if (bytes >= limit) |
185 | 0 | goto invalid; |
186 | 0 | get_sleb128 (entry->cie.data_alignment_factor, bytes, limit); |
187 | |
|
188 | 0 | if (bytes >= limit) |
189 | 0 | goto invalid; |
190 | | |
191 | 0 | if (version >= 3) /* DWARF 3+ */ |
192 | 0 | get_uleb128 (entry->cie.return_address_register, bytes, limit); |
193 | 0 | else /* DWARF 2 */ |
194 | 0 | entry->cie.return_address_register = *bytes++; |
195 | |
|
196 | 0 | entry->cie.fde_augmentation_data_size = 0; |
197 | 0 | entry->cie.augmentation_data = bytes; |
198 | 0 | bool sized_augmentation = *ap == 'z'; |
199 | 0 | if (sized_augmentation) |
200 | 0 | { |
201 | 0 | ++ap; |
202 | 0 | if (bytes >= limit) |
203 | 0 | goto invalid; |
204 | 0 | get_uleb128 (entry->cie.augmentation_data_size, bytes, limit); |
205 | 0 | if ((Dwarf_Word) (limit - bytes) < entry->cie.augmentation_data_size) |
206 | 0 | goto invalid; |
207 | 0 | entry->cie.augmentation_data = bytes; |
208 | 0 | } |
209 | | |
210 | 0 | for (; *ap != '\0'; ++ap) |
211 | 0 | { |
212 | 0 | uint8_t encoding; |
213 | 0 | switch (*ap) |
214 | 0 | { |
215 | 0 | case 'L': |
216 | 0 | if (sized_augmentation) |
217 | 0 | { |
218 | | /* Skip LSDA pointer encoding byte. */ |
219 | 0 | encoding = *bytes++; |
220 | 0 | entry->cie.fde_augmentation_data_size |
221 | 0 | += encoded_value_size (data, e_ident, encoding, NULL); |
222 | 0 | continue; |
223 | 0 | } |
224 | 0 | break; |
225 | 0 | case 'R': |
226 | 0 | if (sized_augmentation) |
227 | 0 | { |
228 | | /* Skip FDE address encoding byte. */ |
229 | 0 | bytes++; |
230 | 0 | continue; |
231 | 0 | } |
232 | 0 | break; |
233 | 0 | case 'P': |
234 | 0 | if (sized_augmentation) |
235 | 0 | { |
236 | | /* Skip encoded personality routine pointer. */ |
237 | 0 | encoding = *bytes++; |
238 | 0 | bytes += encoded_value_size (data, e_ident, encoding, bytes); |
239 | 0 | continue; |
240 | 0 | } |
241 | 0 | break; |
242 | 0 | case 'S': |
243 | 0 | if (sized_augmentation) |
244 | | /* Skip signal-frame flag. */ |
245 | 0 | continue; |
246 | 0 | break; |
247 | 0 | default: |
248 | | /* Unknown augmentation string. initial_instructions might |
249 | | actually start with some augmentation data. */ |
250 | 0 | break; |
251 | 0 | } |
252 | 0 | break; |
253 | 0 | } |
254 | 0 | if (! sized_augmentation) |
255 | 0 | entry->cie.augmentation_data_size = bytes - entry->cie.augmentation_data; |
256 | 0 | else |
257 | 0 | { |
258 | 0 | if (bytes > entry->cie.augmentation_data + entry->cie.augmentation_data_size) |
259 | 0 | goto invalid; |
260 | 0 | bytes = entry->cie.augmentation_data + entry->cie.augmentation_data_size; |
261 | 0 | } |
262 | | |
263 | 0 | entry->cie.initial_instructions = bytes; |
264 | 0 | entry->cie.initial_instructions_end = limit; |
265 | 0 | } |
266 | 0 | else |
267 | 0 | { |
268 | 0 | entry->fde.start = bytes; |
269 | 0 | entry->fde.end = limit; |
270 | 0 | } |
271 | | |
272 | 0 | return 0; |
273 | 0 | } |
274 | | INTDEF (dwarf_next_cfi) |