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
37 internal_function unsigned char *
__libdw_formptr(Dwarf_Attribute * attr,int sec_index,int err_nodata,unsigned char ** endpp,Dwarf_Off * offsetp)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
96 int
dwarf_formudata(Dwarf_Attribute * attr,Dwarf_Word * return_uval)97 dwarf_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 }
231 INTDEF(dwarf_formudata)
232