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