libdwfl: Sanity check partial core file dyn data read.
[platform/upstream/elfutils.git] / libdw / dwarf_formudata.c
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 {
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
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)