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 *
__libdw_formptr(Dwarf_Attribute * attr,int sec_index,int err_nodata,const unsigned char ** endpp,Dwarf_Off * offsetp)38 __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
39 int err_nodata, const unsigned char **endpp,
40 Dwarf_Off *offsetp)
41 {
42 if (attr == NULL)
43 return NULL;
44
45 const Elf_Data *d = attr->cu->dbg->sectiondata[sec_index];
46 Dwarf_CU *skel = NULL; /* See below, needed for GNU DebugFission. */
47 if (unlikely (d == NULL
48 && sec_index == IDX_debug_ranges
49 && attr->cu->version < 5
50 && attr->cu->unit_type == DW_UT_split_compile))
51 {
52 skel = __libdw_find_split_unit (attr->cu);
53 if (skel != NULL)
54 d = skel->dbg->sectiondata[IDX_debug_ranges];
55 }
56
57 if (unlikely (d == NULL))
58 {
59 __libdw_seterrno (err_nodata);
60 return NULL;
61 }
62
63 Dwarf_Word offset;
64 if (attr->form == DW_FORM_sec_offset)
65 {
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 if (unlikely (skel != NULL))
74 {
75 Elf_Data *data = attr->cu->dbg->sectiondata[cu_sec_idx (attr->cu)];
76 const unsigned char *datap = attr->valp;
77 size_t size = attr->cu->offset_size;
78 if (unlikely (data == NULL
79 || datap < (const unsigned char *) data->d_buf
80 || data->d_size < size
81 || ((size_t) (datap
82 - (const unsigned char *) data->d_buf)
83 > data->d_size - size)))
84 goto invalid;
85
86 if (size == 4)
87 offset = read_4ubyte_unaligned (attr->cu->dbg, datap);
88 else
89 offset = read_8ubyte_unaligned (attr->cu->dbg, datap);
90
91 offset += __libdw_cu_ranges_base (skel);
92 }
93 else
94 {
95 if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
96 cu_sec_idx (attr->cu), attr->valp,
97 attr->cu->offset_size, &offset,
98 sec_index, 0))
99 return NULL;
100 }
101 }
102 else if (attr->cu->version > 3)
103 goto invalid;
104 else
105 switch (attr->form)
106 {
107 case DW_FORM_data4:
108 case DW_FORM_data8:
109 if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
110 cu_sec_idx (attr->cu),
111 attr->valp,
112 attr->form == DW_FORM_data4 ? 4 : 8,
113 &offset, sec_index, 0))
114 return NULL;
115 break;
116
117 default:
118 if (INTUSE(dwarf_formudata) (attr, &offset))
119 return NULL;
120 };
121
122 unsigned char *readp = d->d_buf + offset;
123 unsigned char *endp = d->d_buf + d->d_size;
124 if (unlikely (readp >= endp))
125 {
126 invalid:
127 __libdw_seterrno (DWARF_E_INVALID_DWARF);
128 return NULL;
129 }
130
131 if (endpp != NULL)
132 *endpp = endp;
133 if (offsetp != NULL)
134 *offsetp = offset;
135 return readp;
136 }
137
138 int
dwarf_formudata(Dwarf_Attribute * attr,Dwarf_Word * return_uval)139 dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
140 {
141 if (attr == NULL)
142 return -1;
143
144 const unsigned char *datap = attr->valp;
145 const unsigned char *endp = attr->cu->endp;
146
147 switch (attr->form)
148 {
149 case DW_FORM_data1:
150 if (datap + 1 > endp)
151 {
152 invalid:
153 __libdw_seterrno (DWARF_E_INVALID_DWARF);
154 return -1;
155 }
156 *return_uval = *attr->valp;
157 break;
158
159 case DW_FORM_data2:
160 if (datap + 2 > endp)
161 goto invalid;
162 *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
163 break;
164
165 case DW_FORM_data4:
166 case DW_FORM_data8:
167 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 if (attr->form == DW_FORM_sec_offset
173 || (attr->cu->version < 4 && attr->code != DW_AT_start_scope))
174 {
175 switch (attr->code)
176 {
177 case DW_AT_data_member_location:
178 case DW_AT_frame_base:
179 case DW_AT_location:
180 case DW_AT_return_addr:
181 case DW_AT_segment:
182 case DW_AT_static_link:
183 case DW_AT_string_length:
184 case DW_AT_use_location:
185 case DW_AT_vtable_elem_location:
186 case DW_AT_GNU_locviews:
187 case DW_AT_loclists_base:
188 if (attr->cu->version < 5)
189 {
190 /* loclistptr */
191 if (__libdw_formptr (attr, IDX_debug_loc,
192 DWARF_E_NO_DEBUG_LOC, NULL,
193 return_uval) == NULL)
194 return -1;
195 }
196 else
197 {
198 /* loclist, loclistsptr */
199 if (__libdw_formptr (attr, IDX_debug_loclists,
200 DWARF_E_NO_DEBUG_LOCLISTS, NULL,
201 return_uval) == NULL)
202 return -1;
203 }
204 break;
205
206 case DW_AT_macro_info:
207 /* macptr into .debug_macinfo */
208 if (__libdw_formptr (attr, IDX_debug_macinfo,
209 DWARF_E_NO_ENTRY, NULL,
210 return_uval) == NULL)
211 return -1;
212 break;
213
214 case DW_AT_GNU_macros:
215 case DW_AT_macros:
216 /* macptr into .debug_macro */
217 if (__libdw_formptr (attr, IDX_debug_macro,
218 DWARF_E_NO_ENTRY, NULL,
219 return_uval) == NULL)
220 return -1;
221 break;
222
223 case DW_AT_ranges:
224 case DW_AT_start_scope:
225 case DW_AT_GNU_ranges_base:
226 case DW_AT_rnglists_base:
227 if (attr->cu->version < 5)
228 {
229 /* rangelistptr */
230 if (__libdw_formptr (attr, IDX_debug_ranges,
231 DWARF_E_NO_DEBUG_RANGES, NULL,
232 return_uval) == NULL)
233 return -1;
234 }
235 else
236 {
237 /* rnglistsptr */
238 if (__libdw_formptr (attr, IDX_debug_rnglists,
239 DWARF_E_NO_DEBUG_RNGLISTS, NULL,
240 return_uval) == NULL)
241 return -1;
242 }
243 break;
244
245 case DW_AT_stmt_list:
246 /* lineptr */
247 if (__libdw_formptr (attr, IDX_debug_line,
248 DWARF_E_NO_DEBUG_LINE, NULL,
249 return_uval) == NULL)
250 return -1;
251 break;
252
253 case DW_AT_addr_base:
254 case DW_AT_GNU_addr_base:
255 /* addrptr */
256 if (__libdw_formptr (attr, IDX_debug_addr,
257 DWARF_E_NO_DEBUG_ADDR, NULL,
258 return_uval) == NULL)
259 return -1;
260 break;
261
262 case DW_AT_str_offsets_base:
263 /* stroffsetsptr */
264 if (__libdw_formptr (attr, IDX_debug_str_offsets,
265 DWARF_E_NO_STR_OFFSETS, NULL,
266 return_uval) == NULL)
267 return -1;
268 break;
269
270 default:
271 /* sec_offset can only be used by one of the above attrs. */
272 if (attr->form == DW_FORM_sec_offset)
273 {
274 __libdw_seterrno (DWARF_E_INVALID_DWARF);
275 return -1;
276 }
277
278 /* Not one of the special attributes, just a constant. */
279 if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
280 attr->valp,
281 attr->form == DW_FORM_data4 ? 4 : 8,
282 return_uval))
283 return -1;
284 break;
285 }
286 }
287 else
288 {
289 /* We are dealing with a constant data4 or data8. */
290 if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
291 attr->valp,
292 attr->form == DW_FORM_data4 ? 4 : 8,
293 return_uval))
294 return -1;
295 }
296 break;
297
298 case DW_FORM_sdata:
299 if (datap + 1 > endp)
300 goto invalid;
301 get_sleb128 (*return_uval, datap, endp);
302 break;
303
304 case DW_FORM_udata:
305 case DW_FORM_rnglistx:
306 case DW_FORM_loclistx:
307 if (datap + 1 > endp)
308 goto invalid;
309 get_uleb128 (*return_uval, datap, endp);
310 break;
311
312 case DW_FORM_implicit_const:
313 // The data comes from the abbrev, which has been bounds checked.
314 get_sleb128_unchecked (*return_uval, datap);
315 break;
316
317 /* These are indexes into the .debug_addr section, normally resolved
318 with dwarf_formaddr. Here treat as constants. */
319 case DW_FORM_GNU_addr_index:
320 case DW_FORM_addrx:
321 if (datap >= endp)
322 goto invalid;
323 get_uleb128 (*return_uval, datap, endp);
324 break;
325
326 case DW_FORM_addrx1:
327 if (datap >= endp - 1)
328 goto invalid;
329 *return_uval = *datap;
330 break;
331
332 case DW_FORM_addrx2:
333 if (datap >= endp - 2)
334 goto invalid;
335 *return_uval = read_2ubyte_unaligned (attr->cu->dbg, datap);
336 break;
337
338 case DW_FORM_addrx3:
339 if (datap >= endp - 3)
340 goto invalid;
341 *return_uval = read_3ubyte_unaligned (attr->cu->dbg, datap);
342 break;
343
344 case DW_FORM_addrx4:
345 if (datap >= endp - 4)
346 goto invalid;
347 *return_uval = read_4ubyte_unaligned (attr->cu->dbg, datap);
348 break;
349
350 default:
351 __libdw_seterrno (DWARF_E_NO_CONSTANT);
352 return -1;
353 }
354
355 return 0;
356 }
357 INTDEF(dwarf_formudata)
358