1/* Return unsigned constant represented by attribute.
2   Copyright (C) 2003-2012, 2014 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 unsigned char *
38__libdw_formptr (Dwarf_Attribute *attr, int sec_index,
39		 int err_nodata, 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  if (unlikely (d == NULL))
47    {
48      __libdw_seterrno (err_nodata);
49      return NULL;
50    }
51
52  Dwarf_Word offset;
53  if (attr->form == DW_FORM_sec_offset)
54    {
55      if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
56			       cu_sec_idx (attr->cu), attr->valp,
57			       attr->cu->offset_size, &offset, sec_index, 0))
58	return NULL;
59    }
60  else if (attr->cu->version > 3)
61    goto invalid;
62  else
63    switch (attr->form)
64      {
65      case DW_FORM_data4:
66      case DW_FORM_data8:
67	if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
68				 cu_sec_idx (attr->cu),
69				 attr->valp,
70				 attr->form == DW_FORM_data4 ? 4 : 8,
71				 &offset, sec_index, 0))
72	  return NULL;
73	break;
74
75      default:
76	if (INTUSE(dwarf_formudata) (attr, &offset))
77	  return NULL;
78      };
79
80  unsigned char *readp = d->d_buf + offset;
81  unsigned char *endp = d->d_buf + d->d_size;
82  if (unlikely (readp >= endp))
83    {
84    invalid:
85      __libdw_seterrno (DWARF_E_INVALID_DWARF);
86      return NULL;
87    }
88
89  if (endpp != NULL)
90    *endpp = endp;
91  if (offsetp != NULL)
92    *offsetp = offset;
93  return readp;
94}
95
96int
97dwarf_formudata (attr, return_uval)
98     Dwarf_Attribute *attr;
99     Dwarf_Word *return_uval;
100{
101  if (attr == NULL)
102    return -1;
103
104  const unsigned char *datap = attr->valp;
105  const unsigned char *endp = attr->cu->endp;
106
107  switch (attr->form)
108    {
109    case DW_FORM_data1:
110      if (datap + 1 > endp)
111	{
112	invalid:
113	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
114	  return -1;
115	}
116      *return_uval = *attr->valp;
117      break;
118
119    case DW_FORM_data2:
120      if (datap + 2 > endp)
121	goto invalid;
122      *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
123      break;
124
125    case DW_FORM_data4:
126    case DW_FORM_data8:
127    case DW_FORM_sec_offset:
128      /* Before DWARF4 data4 and data8 are pure constants unless the
129	 attribute also allows offsets (*ptr classes), since DWARF4
130	 they are always just constants (start_scope is special though,
131	 since it only could express a rangelist since DWARF4).  */
132      if (attr->form == DW_FORM_sec_offset
133	  || (attr->cu->version < 4 && attr->code != DW_AT_start_scope))
134	{
135	  switch (attr->code)
136	    {
137	    case DW_AT_data_member_location:
138	    case DW_AT_frame_base:
139	    case DW_AT_location:
140	    case DW_AT_return_addr:
141	    case DW_AT_segment:
142	    case DW_AT_static_link:
143	    case DW_AT_string_length:
144	    case DW_AT_use_location:
145	    case DW_AT_vtable_elem_location:
146	      /* loclistptr */
147	      if (__libdw_formptr (attr, IDX_debug_loc,
148				   DWARF_E_NO_LOCLIST, NULL,
149				   return_uval) == NULL)
150		return -1;
151	      break;
152
153	    case DW_AT_macro_info:
154	      /* macptr into .debug_macinfo */
155	      if (__libdw_formptr (attr, IDX_debug_macinfo,
156				   DWARF_E_NO_ENTRY, NULL,
157				   return_uval) == NULL)
158		return -1;
159	      break;
160
161	    case DW_AT_GNU_macros:
162	      /* macptr into .debug_macro */
163	      if (__libdw_formptr (attr, IDX_debug_macro,
164				   DWARF_E_NO_ENTRY, NULL,
165				   return_uval) == NULL)
166		return -1;
167	      break;
168
169	    case DW_AT_ranges:
170	    case DW_AT_start_scope:
171	      /* rangelistptr */
172	      if (__libdw_formptr (attr, IDX_debug_ranges,
173				   DWARF_E_NO_DEBUG_RANGES, NULL,
174				   return_uval) == NULL)
175		return -1;
176	      break;
177
178	    case DW_AT_stmt_list:
179	      /* lineptr */
180	      if (__libdw_formptr (attr, IDX_debug_line,
181				   DWARF_E_NO_DEBUG_LINE, NULL,
182				   return_uval) == NULL)
183		return -1;
184	      break;
185
186	    default:
187	      /* sec_offset can only be used by one of the above attrs.  */
188	      if (attr->form == DW_FORM_sec_offset)
189		{
190		  __libdw_seterrno (DWARF_E_INVALID_DWARF);
191		  return -1;
192		}
193
194	      /* Not one of the special attributes, just a constant.  */
195	      if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
196					attr->valp,
197					attr->form == DW_FORM_data4 ? 4 : 8,
198					return_uval))
199		return -1;
200	      break;
201	    }
202	}
203      else
204	{
205	  /* We are dealing with a constant data4 or data8.  */
206	  if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
207				    attr->valp,
208				    attr->form == DW_FORM_data4 ? 4 : 8,
209				    return_uval))
210	    return -1;
211	}
212      break;
213
214    case DW_FORM_sdata:
215      if (datap + 1 > endp)
216	goto invalid;
217      get_sleb128 (*return_uval, datap, endp);
218      break;
219
220    case DW_FORM_udata:
221      if (datap + 1 > endp)
222	goto invalid;
223      get_uleb128 (*return_uval, datap, endp);
224      break;
225
226    default:
227      __libdw_seterrno (DWARF_E_NO_CONSTANT);
228      return -1;
229    }
230
231  return 0;
232}
233INTDEF(dwarf_formudata)
234