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 (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
98{
99  if (attr == NULL)
100    return -1;
101
102  const unsigned char *datap = attr->valp;
103  const unsigned char *endp = attr->cu->endp;
104
105  switch (attr->form)
106    {
107    case DW_FORM_data1:
108      if (datap + 1 > endp)
109	{
110	invalid:
111	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
112	  return -1;
113	}
114      *return_uval = *attr->valp;
115      break;
116
117    case DW_FORM_data2:
118      if (datap + 2 > endp)
119	goto invalid;
120      *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
121      break;
122
123    case DW_FORM_data4:
124    case DW_FORM_data8:
125    case DW_FORM_sec_offset:
126      /* Before DWARF4 data4 and data8 are pure constants unless the
127	 attribute also allows offsets (*ptr classes), since DWARF4
128	 they are always just constants (start_scope is special though,
129	 since it only could express a rangelist since DWARF4).  */
130      if (attr->form == DW_FORM_sec_offset
131	  || (attr->cu->version < 4 && attr->code != DW_AT_start_scope))
132	{
133	  switch (attr->code)
134	    {
135	    case DW_AT_data_member_location:
136	    case DW_AT_frame_base:
137	    case DW_AT_location:
138	    case DW_AT_return_addr:
139	    case DW_AT_segment:
140	    case DW_AT_static_link:
141	    case DW_AT_string_length:
142	    case DW_AT_use_location:
143	    case DW_AT_vtable_elem_location:
144	      /* loclistptr */
145	      if (__libdw_formptr (attr, IDX_debug_loc,
146				   DWARF_E_NO_LOCLIST, NULL,
147				   return_uval) == NULL)
148		return -1;
149	      break;
150
151	    case DW_AT_macro_info:
152	      /* macptr into .debug_macinfo */
153	      if (__libdw_formptr (attr, IDX_debug_macinfo,
154				   DWARF_E_NO_ENTRY, NULL,
155				   return_uval) == NULL)
156		return -1;
157	      break;
158
159	    case DW_AT_GNU_macros:
160	      /* macptr into .debug_macro */
161	      if (__libdw_formptr (attr, IDX_debug_macro,
162				   DWARF_E_NO_ENTRY, NULL,
163				   return_uval) == NULL)
164		return -1;
165	      break;
166
167	    case DW_AT_ranges:
168	    case DW_AT_start_scope:
169	      /* rangelistptr */
170	      if (__libdw_formptr (attr, IDX_debug_ranges,
171				   DWARF_E_NO_DEBUG_RANGES, NULL,
172				   return_uval) == NULL)
173		return -1;
174	      break;
175
176	    case DW_AT_stmt_list:
177	      /* lineptr */
178	      if (__libdw_formptr (attr, IDX_debug_line,
179				   DWARF_E_NO_DEBUG_LINE, NULL,
180				   return_uval) == NULL)
181		return -1;
182	      break;
183
184	    default:
185	      /* sec_offset can only be used by one of the above attrs.  */
186	      if (attr->form == DW_FORM_sec_offset)
187		{
188		  __libdw_seterrno (DWARF_E_INVALID_DWARF);
189		  return -1;
190		}
191
192	      /* Not one of the special attributes, just a constant.  */
193	      if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
194					attr->valp,
195					attr->form == DW_FORM_data4 ? 4 : 8,
196					return_uval))
197		return -1;
198	      break;
199	    }
200	}
201      else
202	{
203	  /* We are dealing with a constant data4 or data8.  */
204	  if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
205				    attr->valp,
206				    attr->form == DW_FORM_data4 ? 4 : 8,
207				    return_uval))
208	    return -1;
209	}
210      break;
211
212    case DW_FORM_sdata:
213      if (datap + 1 > endp)
214	goto invalid;
215      get_sleb128 (*return_uval, datap, endp);
216      break;
217
218    case DW_FORM_udata:
219      if (datap + 1 > endp)
220	goto invalid;
221      get_uleb128 (*return_uval, datap, endp);
222      break;
223
224    default:
225      __libdw_seterrno (DWARF_E_NO_CONSTANT);
226      return -1;
227    }
228
229  return 0;
230}
231INTDEF(dwarf_formudata)
232