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