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
37internal_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
138int
139dwarf_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}
357INTDEF(dwarf_formudata)
358