/src/elfutils/libdw/dwarf_formudata.c
Line | Count | Source |
1 | | /* Return unsigned constant represented by attribute. |
2 | | Copyright (C) 2003-2012, 2014, 2017 Red Hat, Inc. |
3 | | This file is part of elfutils. |
4 | | Written by Ulrich Drepper <drepper@redhat.com>, 2003. |
5 | | |
6 | | This file is free software; you can redistribute it and/or modify |
7 | | it under the terms of either |
8 | | |
9 | | * the GNU Lesser General Public License as published by the Free |
10 | | Software Foundation; either version 3 of the License, or (at |
11 | | your option) any later version |
12 | | |
13 | | or |
14 | | |
15 | | * the GNU General Public License as published by the Free |
16 | | Software Foundation; either version 2 of the License, or (at |
17 | | your option) any later version |
18 | | |
19 | | or both in parallel, as here. |
20 | | |
21 | | elfutils is distributed in the hope that it will be useful, but |
22 | | WITHOUT ANY WARRANTY; without even the implied warranty of |
23 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
24 | | General Public License for more details. |
25 | | |
26 | | You should have received copies of the GNU General Public License and |
27 | | the GNU Lesser General Public License along with this program. If |
28 | | not, see <http://www.gnu.org/licenses/>. */ |
29 | | |
30 | | #ifdef HAVE_CONFIG_H |
31 | | # include <config.h> |
32 | | #endif |
33 | | |
34 | | #include <dwarf.h> |
35 | | #include "libdwP.h" |
36 | | |
37 | | internal_function const unsigned char * |
38 | | __libdw_formptr (Dwarf_Attribute *attr, int sec_index, |
39 | | int err_nodata, const unsigned char **endpp, |
40 | | Dwarf_Off *offsetp) |
41 | 0 | { |
42 | 0 | if (attr == NULL) |
43 | 0 | return NULL; |
44 | | |
45 | 0 | const Elf_Data *d = attr->cu->dbg->sectiondata[sec_index]; |
46 | 0 | Dwarf_CU *skel = NULL; /* See below, needed for GNU DebugFission. */ |
47 | 0 | if (unlikely (d == NULL |
48 | 0 | && sec_index == IDX_debug_ranges |
49 | 0 | && attr->cu->version < 5 |
50 | 0 | && attr->cu->unit_type == DW_UT_split_compile)) |
51 | 0 | { |
52 | 0 | skel = __libdw_find_split_unit (attr->cu); |
53 | 0 | if (skel != NULL) |
54 | 0 | d = skel->dbg->sectiondata[IDX_debug_ranges]; |
55 | 0 | } |
56 | |
|
57 | 0 | if (unlikely (d == NULL)) |
58 | 0 | { |
59 | 0 | __libdw_seterrno (err_nodata); |
60 | 0 | return NULL; |
61 | 0 | } |
62 | | |
63 | 0 | Dwarf_Word offset; |
64 | 0 | if (attr->form == DW_FORM_sec_offset) |
65 | 0 | { |
66 | | /* GNU DebugFission is slightly odd. It uses DW_FORM_sec_offset |
67 | | in split units, but they are really (unrelocated) offsets |
68 | | from the skeleton DW_AT_GNU_ranges_base (which is only used |
69 | | for the split unit, not the skeleton ranges itself, see also |
70 | | DW_AT_rnglists_base, which is used in DWARF5 for both, but |
71 | | points to the offsets index). So it isn't really a formptr, |
72 | | but an offset + base calculation. */ |
73 | 0 | if (unlikely (skel != NULL)) |
74 | 0 | { |
75 | 0 | Elf_Data *data = attr->cu->dbg->sectiondata[cu_sec_idx (attr->cu)]; |
76 | 0 | const unsigned char *datap = attr->valp; |
77 | 0 | size_t size = attr->cu->offset_size; |
78 | 0 | if (unlikely (data == NULL |
79 | 0 | || datap < (const unsigned char *) data->d_buf |
80 | 0 | || data->d_size < size |
81 | 0 | || ((size_t) (datap |
82 | 0 | - (const unsigned char *) data->d_buf) |
83 | 0 | > data->d_size - size))) |
84 | 0 | goto invalid; |
85 | | |
86 | 0 | if (size == 4) |
87 | 0 | offset = read_4ubyte_unaligned (attr->cu->dbg, datap); |
88 | 0 | else |
89 | 0 | offset = read_8ubyte_unaligned (attr->cu->dbg, datap); |
90 | |
|
91 | 0 | offset += __libdw_cu_ranges_base (skel); |
92 | 0 | } |
93 | 0 | else |
94 | 0 | { |
95 | 0 | if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg, |
96 | 0 | cu_sec_idx (attr->cu), attr->valp, |
97 | 0 | attr->cu->offset_size, &offset, |
98 | 0 | sec_index, 0)) |
99 | 0 | return NULL; |
100 | 0 | } |
101 | 0 | } |
102 | 0 | else if (attr->cu->version > 3) |
103 | 0 | goto invalid; |
104 | 0 | else |
105 | 0 | switch (attr->form) |
106 | 0 | { |
107 | 0 | case DW_FORM_data4: |
108 | 0 | case DW_FORM_data8: |
109 | 0 | if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg, |
110 | 0 | cu_sec_idx (attr->cu), |
111 | 0 | attr->valp, |
112 | 0 | attr->form == DW_FORM_data4 ? 4 : 8, |
113 | 0 | &offset, sec_index, 0)) |
114 | 0 | return NULL; |
115 | 0 | break; |
116 | | |
117 | 0 | default: |
118 | 0 | if (INTUSE(dwarf_formudata) (attr, &offset)) |
119 | 0 | return NULL; |
120 | 0 | }; |
121 | |
|
122 | 0 | unsigned char *readp = d->d_buf + offset; |
123 | 0 | unsigned char *endp = d->d_buf + d->d_size; |
124 | 0 | if (unlikely (readp >= endp)) |
125 | 0 | { |
126 | 0 | invalid: |
127 | 0 | __libdw_seterrno (DWARF_E_INVALID_DWARF); |
128 | 0 | return NULL; |
129 | 0 | } |
130 | | |
131 | 0 | if (endpp != NULL) |
132 | 0 | *endpp = endp; |
133 | 0 | if (offsetp != NULL) |
134 | 0 | *offsetp = offset; |
135 | 0 | return readp; |
136 | 0 | } |
137 | | |
138 | | int |
139 | | dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) |
140 | 0 | { |
141 | 0 | if (attr == NULL) |
142 | 0 | return -1; |
143 | | |
144 | 0 | const unsigned char *datap = attr->valp; |
145 | 0 | const unsigned char *endp = attr->cu->endp; |
146 | |
|
147 | 0 | switch (attr->form) |
148 | 0 | { |
149 | 0 | case DW_FORM_data1: |
150 | 0 | if (datap + 1 > endp) |
151 | 0 | { |
152 | 0 | invalid: |
153 | 0 | __libdw_seterrno (DWARF_E_INVALID_DWARF); |
154 | 0 | return -1; |
155 | 0 | } |
156 | 0 | *return_uval = *attr->valp; |
157 | 0 | break; |
158 | | |
159 | 0 | case DW_FORM_data2: |
160 | 0 | if (datap + 2 > endp) |
161 | 0 | goto invalid; |
162 | 0 | *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); |
163 | 0 | break; |
164 | | |
165 | 0 | case DW_FORM_data4: |
166 | 0 | case DW_FORM_data8: |
167 | 0 | case DW_FORM_sec_offset: |
168 | | /* Before DWARF4 data4 and data8 are pure constants unless the |
169 | | attribute also allows offsets (*ptr classes), since DWARF4 |
170 | | they are always just constants (start_scope is special though, |
171 | | since it only could express a rangelist since DWARF4). */ |
172 | 0 | if (attr->form == DW_FORM_sec_offset |
173 | 0 | || (attr->cu->version < 4 && attr->code != DW_AT_start_scope)) |
174 | 0 | { |
175 | 0 | switch (attr->code) |
176 | 0 | { |
177 | 0 | case DW_AT_data_member_location: |
178 | 0 | case DW_AT_frame_base: |
179 | 0 | case DW_AT_location: |
180 | 0 | case DW_AT_return_addr: |
181 | 0 | case DW_AT_segment: |
182 | 0 | case DW_AT_static_link: |
183 | 0 | case DW_AT_string_length: |
184 | 0 | case DW_AT_use_location: |
185 | 0 | case DW_AT_vtable_elem_location: |
186 | 0 | case DW_AT_GNU_locviews: |
187 | 0 | case DW_AT_loclists_base: |
188 | 0 | if (attr->cu->version < 5) |
189 | 0 | { |
190 | | /* loclistptr */ |
191 | 0 | if (__libdw_formptr (attr, IDX_debug_loc, |
192 | 0 | DWARF_E_NO_DEBUG_LOC, NULL, |
193 | 0 | return_uval) == NULL) |
194 | 0 | return -1; |
195 | 0 | } |
196 | 0 | else |
197 | 0 | { |
198 | | /* loclist, loclistsptr */ |
199 | 0 | if (__libdw_formptr (attr, IDX_debug_loclists, |
200 | 0 | DWARF_E_NO_DEBUG_LOCLISTS, NULL, |
201 | 0 | return_uval) == NULL) |
202 | 0 | return -1; |
203 | 0 | } |
204 | 0 | break; |
205 | | |
206 | 0 | case DW_AT_macro_info: |
207 | | /* macptr into .debug_macinfo */ |
208 | 0 | if (__libdw_formptr (attr, IDX_debug_macinfo, |
209 | 0 | DWARF_E_NO_ENTRY, NULL, |
210 | 0 | return_uval) == NULL) |
211 | 0 | return -1; |
212 | 0 | break; |
213 | | |
214 | 0 | case DW_AT_GNU_macros: |
215 | 0 | case DW_AT_macros: |
216 | | /* macptr into .debug_macro */ |
217 | 0 | if (__libdw_formptr (attr, IDX_debug_macro, |
218 | 0 | DWARF_E_NO_ENTRY, NULL, |
219 | 0 | return_uval) == NULL) |
220 | 0 | return -1; |
221 | 0 | break; |
222 | | |
223 | 0 | case DW_AT_ranges: |
224 | 0 | case DW_AT_start_scope: |
225 | 0 | case DW_AT_GNU_ranges_base: |
226 | 0 | case DW_AT_rnglists_base: |
227 | 0 | if (attr->cu->version < 5) |
228 | 0 | { |
229 | | /* rangelistptr */ |
230 | 0 | if (__libdw_formptr (attr, IDX_debug_ranges, |
231 | 0 | DWARF_E_NO_DEBUG_RANGES, NULL, |
232 | 0 | return_uval) == NULL) |
233 | 0 | return -1; |
234 | 0 | } |
235 | 0 | else |
236 | 0 | { |
237 | | /* rnglistsptr */ |
238 | 0 | if (__libdw_formptr (attr, IDX_debug_rnglists, |
239 | 0 | DWARF_E_NO_DEBUG_RNGLISTS, NULL, |
240 | 0 | return_uval) == NULL) |
241 | 0 | return -1; |
242 | 0 | } |
243 | 0 | break; |
244 | | |
245 | 0 | case DW_AT_stmt_list: |
246 | | /* lineptr */ |
247 | 0 | if (__libdw_formptr (attr, IDX_debug_line, |
248 | 0 | DWARF_E_NO_DEBUG_LINE, NULL, |
249 | 0 | return_uval) == NULL) |
250 | 0 | return -1; |
251 | 0 | break; |
252 | | |
253 | 0 | case DW_AT_addr_base: |
254 | 0 | case DW_AT_GNU_addr_base: |
255 | | /* addrptr */ |
256 | 0 | if (__libdw_formptr (attr, IDX_debug_addr, |
257 | 0 | DWARF_E_NO_DEBUG_ADDR, NULL, |
258 | 0 | return_uval) == NULL) |
259 | 0 | return -1; |
260 | 0 | break; |
261 | | |
262 | 0 | case DW_AT_str_offsets_base: |
263 | | /* stroffsetsptr */ |
264 | 0 | if (__libdw_formptr (attr, IDX_debug_str_offsets, |
265 | 0 | DWARF_E_NO_STR_OFFSETS, NULL, |
266 | 0 | return_uval) == NULL) |
267 | 0 | return -1; |
268 | 0 | break; |
269 | | |
270 | 0 | default: |
271 | | /* sec_offset can only be used by one of the above attrs. */ |
272 | 0 | if (attr->form == DW_FORM_sec_offset) |
273 | 0 | { |
274 | 0 | __libdw_seterrno (DWARF_E_INVALID_DWARF); |
275 | 0 | return -1; |
276 | 0 | } |
277 | | |
278 | | /* Not one of the special attributes, just a constant. */ |
279 | 0 | if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu), |
280 | 0 | attr->valp, |
281 | 0 | attr->form == DW_FORM_data4 ? 4 : 8, |
282 | 0 | return_uval)) |
283 | 0 | return -1; |
284 | 0 | break; |
285 | 0 | } |
286 | 0 | } |
287 | 0 | else |
288 | 0 | { |
289 | | /* We are dealing with a constant data4 or data8. */ |
290 | 0 | if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu), |
291 | 0 | attr->valp, |
292 | 0 | attr->form == DW_FORM_data4 ? 4 : 8, |
293 | 0 | return_uval)) |
294 | 0 | return -1; |
295 | 0 | } |
296 | 0 | break; |
297 | | |
298 | 0 | case DW_FORM_sdata: |
299 | 0 | if (datap + 1 > endp) |
300 | 0 | goto invalid; |
301 | 0 | get_sleb128 (*return_uval, datap, endp); |
302 | 0 | break; |
303 | | |
304 | 0 | case DW_FORM_udata: |
305 | 0 | case DW_FORM_rnglistx: |
306 | 0 | case DW_FORM_loclistx: |
307 | 0 | if (datap + 1 > endp) |
308 | 0 | goto invalid; |
309 | 0 | get_uleb128 (*return_uval, datap, endp); |
310 | 0 | break; |
311 | | |
312 | 0 | case DW_FORM_implicit_const: |
313 | | // The data comes from the abbrev, which has been bounds checked. |
314 | 0 | get_sleb128_unchecked (*return_uval, datap); |
315 | 0 | break; |
316 | | |
317 | | /* These are indexes into the .debug_addr section, normally resolved |
318 | | with dwarf_formaddr. Here treat as constants. */ |
319 | 0 | case DW_FORM_GNU_addr_index: |
320 | 0 | case DW_FORM_addrx: |
321 | 0 | if (datap >= endp) |
322 | 0 | goto invalid; |
323 | 0 | get_uleb128 (*return_uval, datap, endp); |
324 | 0 | break; |
325 | | |
326 | 0 | case DW_FORM_addrx1: |
327 | 0 | if (datap >= endp - 1) |
328 | 0 | goto invalid; |
329 | 0 | *return_uval = *datap; |
330 | 0 | break; |
331 | | |
332 | 0 | case DW_FORM_addrx2: |
333 | 0 | if (datap >= endp - 2) |
334 | 0 | goto invalid; |
335 | 0 | *return_uval = read_2ubyte_unaligned (attr->cu->dbg, datap); |
336 | 0 | break; |
337 | | |
338 | 0 | case DW_FORM_addrx3: |
339 | 0 | if (datap >= endp - 3) |
340 | 0 | goto invalid; |
341 | 0 | *return_uval = read_3ubyte_unaligned (attr->cu->dbg, datap); |
342 | 0 | break; |
343 | | |
344 | 0 | case DW_FORM_addrx4: |
345 | 0 | if (datap >= endp - 4) |
346 | 0 | goto invalid; |
347 | 0 | *return_uval = read_4ubyte_unaligned (attr->cu->dbg, datap); |
348 | 0 | break; |
349 | | |
350 | 0 | default: |
351 | 0 | __libdw_seterrno (DWARF_E_NO_CONSTANT); |
352 | 0 | return -1; |
353 | 0 | } |
354 | | |
355 | 0 | return 0; |
356 | 0 | } |
357 | | INTDEF(dwarf_formudata) |