1 /* Return unsigned constant represented by attribute. 2 Copyright (C) 2003-2012, 2014, 2017 Red Hat, Inc. 3 This file is part of elfutils. 4 Written by Ulrich Drepper <drepper (at) 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 const unsigned char * 38 __libdw_formptr (Dwarf_Attribute *attr, int sec_index, 39 int err_nodata, const 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 Dwarf_CU *skel = NULL; /* See below, needed for GNU DebugFission. */ 47 if (unlikely (d == NULL 48 && sec_index == IDX_debug_ranges 49 && attr->cu->version < 5 50 && attr->cu->unit_type == DW_UT_split_compile)) 51 { 52 skel = __libdw_find_split_unit (attr->cu); 53 if (skel != NULL) 54 d = skel->dbg->sectiondata[IDX_debug_ranges]; 55 } 56 57 if (unlikely (d == NULL)) 58 { 59 __libdw_seterrno (err_nodata); 60 return NULL; 61 } 62 63 Dwarf_Word offset; 64 if (attr->form == DW_FORM_sec_offset) 65 { 66 /* GNU DebugFission is slightly odd. It uses DW_FORM_sec_offset 67 in split units, but they are really (unrelocated) offsets 68 from the skeleton DW_AT_GNU_ranges_base (which is only used 69 for the split unit, not the skeleton ranges itself, see also 70 DW_AT_rnglists_base, which is used in DWARF5 for both, but 71 points to the offsets index). So it isn't really a formptr, 72 but an offset + base calculation. */ 73 if (unlikely (skel != NULL)) 74 { 75 Elf_Data *data = attr->cu->dbg->sectiondata[cu_sec_idx (attr->cu)]; 76 const unsigned char *datap = attr->valp; 77 size_t size = attr->cu->offset_size; 78 if (unlikely (data == NULL 79 || datap < (const unsigned char *) data->d_buf 80 || data->d_size < size 81 || ((size_t) (datap 82 - (const unsigned char *) data->d_buf) 83 > data->d_size - size))) 84 goto invalid; 85 86 if (size == 4) 87 offset = read_4ubyte_unaligned (attr->cu->dbg, datap); 88 else 89 offset = read_8ubyte_unaligned (attr->cu->dbg, datap); 90 91 offset += __libdw_cu_ranges_base (skel); 92 } 93 else 94 { 95 if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg, 96 cu_sec_idx (attr->cu), attr->valp, 97 attr->cu->offset_size, &offset, 98 sec_index, 0)) 99 return NULL; 100 } 101 } 102 else if (attr->cu->version > 3) 103 goto invalid; 104 else 105 switch (attr->form) 106 { 107 case DW_FORM_data4: 108 case DW_FORM_data8: 109 if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg, 110 cu_sec_idx (attr->cu), 111 attr->valp, 112 attr->form == DW_FORM_data4 ? 4 : 8, 113 &offset, sec_index, 0)) 114 return NULL; 115 break; 116 117 default: 118 if (INTUSE(dwarf_formudata) (attr, &offset)) 119 return NULL; 120 }; 121 122 unsigned char *readp = d->d_buf + offset; 123 unsigned char *endp = d->d_buf + d->d_size; 124 if (unlikely (readp >= endp)) 125 { 126 invalid: 127 __libdw_seterrno (DWARF_E_INVALID_DWARF); 128 return NULL; 129 } 130 131 if (endpp != NULL) 132 *endpp = endp; 133 if (offsetp != NULL) 134 *offsetp = offset; 135 return readp; 136 } 137 138 int 139 dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) 140 { 141 if (attr == NULL) 142 return -1; 143 144 const unsigned char *datap = attr->valp; 145 const unsigned char *endp = attr->cu->endp; 146 147 switch (attr->form) 148 { 149 case DW_FORM_data1: 150 if (datap + 1 > endp) 151 { 152 invalid: 153 __libdw_seterrno (DWARF_E_INVALID_DWARF); 154 return -1; 155 } 156 *return_uval = *attr->valp; 157 break; 158 159 case DW_FORM_data2: 160 if (datap + 2 > endp) 161 goto invalid; 162 *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); 163 break; 164 165 case DW_FORM_data4: 166 case DW_FORM_data8: 167 case DW_FORM_sec_offset: 168 /* Before DWARF4 data4 and data8 are pure constants unless the 169 attribute also allows offsets (*ptr classes), since DWARF4 170 they are always just constants (start_scope is special though, 171 since it only could express a rangelist since DWARF4). */ 172 if (attr->form == DW_FORM_sec_offset 173 || (attr->cu->version < 4 && attr->code != DW_AT_start_scope)) 174 { 175 switch (attr->code) 176 { 177 case DW_AT_data_member_location: 178 case DW_AT_frame_base: 179 case DW_AT_location: 180 case DW_AT_return_addr: 181 case DW_AT_segment: 182 case DW_AT_static_link: 183 case DW_AT_string_length: 184 case DW_AT_use_location: 185 case DW_AT_vtable_elem_location: 186 case DW_AT_GNU_locviews: 187 case DW_AT_loclists_base: 188 if (attr->cu->version < 5) 189 { 190 /* loclistptr */ 191 if (__libdw_formptr (attr, IDX_debug_loc, 192 DWARF_E_NO_DEBUG_LOC, NULL, 193 return_uval) == NULL) 194 return -1; 195 } 196 else 197 { 198 /* loclist, loclistsptr */ 199 if (__libdw_formptr (attr, IDX_debug_loclists, 200 DWARF_E_NO_DEBUG_LOCLISTS, NULL, 201 return_uval) == NULL) 202 return -1; 203 } 204 break; 205 206 case DW_AT_macro_info: 207 /* macptr into .debug_macinfo */ 208 if (__libdw_formptr (attr, IDX_debug_macinfo, 209 DWARF_E_NO_ENTRY, NULL, 210 return_uval) == NULL) 211 return -1; 212 break; 213 214 case DW_AT_GNU_macros: 215 case DW_AT_macros: 216 /* macptr into .debug_macro */ 217 if (__libdw_formptr (attr, IDX_debug_macro, 218 DWARF_E_NO_ENTRY, NULL, 219 return_uval) == NULL) 220 return -1; 221 break; 222 223 case DW_AT_ranges: 224 case DW_AT_start_scope: 225 case DW_AT_GNU_ranges_base: 226 case DW_AT_rnglists_base: 227 if (attr->cu->version < 5) 228 { 229 /* rangelistptr */ 230 if (__libdw_formptr (attr, IDX_debug_ranges, 231 DWARF_E_NO_DEBUG_RANGES, NULL, 232 return_uval) == NULL) 233 return -1; 234 } 235 else 236 { 237 /* rnglistsptr */ 238 if (__libdw_formptr (attr, IDX_debug_rnglists, 239 DWARF_E_NO_DEBUG_RNGLISTS, NULL, 240 return_uval) == NULL) 241 return -1; 242 } 243 break; 244 245 case DW_AT_stmt_list: 246 /* lineptr */ 247 if (__libdw_formptr (attr, IDX_debug_line, 248 DWARF_E_NO_DEBUG_LINE, NULL, 249 return_uval) == NULL) 250 return -1; 251 break; 252 253 case DW_AT_addr_base: 254 case DW_AT_GNU_addr_base: 255 /* addrptr */ 256 if (__libdw_formptr (attr, IDX_debug_addr, 257 DWARF_E_NO_DEBUG_ADDR, NULL, 258 return_uval) == NULL) 259 return -1; 260 break; 261 262 case DW_AT_str_offsets_base: 263 /* stroffsetsptr */ 264 if (__libdw_formptr (attr, IDX_debug_str_offsets, 265 DWARF_E_NO_STR_OFFSETS, NULL, 266 return_uval) == NULL) 267 return -1; 268 break; 269 270 default: 271 /* sec_offset can only be used by one of the above attrs. */ 272 if (attr->form == DW_FORM_sec_offset) 273 { 274 __libdw_seterrno (DWARF_E_INVALID_DWARF); 275 return -1; 276 } 277 278 /* Not one of the special attributes, just a constant. */ 279 if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu), 280 attr->valp, 281 attr->form == DW_FORM_data4 ? 4 : 8, 282 return_uval)) 283 return -1; 284 break; 285 } 286 } 287 else 288 { 289 /* We are dealing with a constant data4 or data8. */ 290 if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu), 291 attr->valp, 292 attr->form == DW_FORM_data4 ? 4 : 8, 293 return_uval)) 294 return -1; 295 } 296 break; 297 298 case DW_FORM_sdata: 299 if (datap + 1 > endp) 300 goto invalid; 301 get_sleb128 (*return_uval, datap, endp); 302 break; 303 304 case DW_FORM_udata: 305 case DW_FORM_rnglistx: 306 case DW_FORM_loclistx: 307 if (datap + 1 > endp) 308 goto invalid; 309 get_uleb128 (*return_uval, datap, endp); 310 break; 311 312 case DW_FORM_implicit_const: 313 // The data comes from the abbrev, which has been bounds checked. 314 get_sleb128_unchecked (*return_uval, datap); 315 break; 316 317 /* These are indexes into the .debug_addr section, normally resolved 318 with dwarf_formaddr. Here treat as constants. */ 319 case DW_FORM_GNU_addr_index: 320 case DW_FORM_addrx: 321 if (datap >= endp) 322 goto invalid; 323 get_uleb128 (*return_uval, datap, endp); 324 break; 325 326 case DW_FORM_addrx1: 327 if (datap >= endp - 1) 328 goto invalid; 329 *return_uval = *datap; 330 break; 331 332 case DW_FORM_addrx2: 333 if (datap >= endp - 2) 334 goto invalid; 335 *return_uval = read_2ubyte_unaligned (attr->cu->dbg, datap); 336 break; 337 338 case DW_FORM_addrx3: 339 if (datap >= endp - 3) 340 goto invalid; 341 *return_uval = read_3ubyte_unaligned (attr->cu->dbg, datap); 342 break; 343 344 case DW_FORM_addrx4: 345 if (datap >= endp - 4) 346 goto invalid; 347 *return_uval = read_4ubyte_unaligned (attr->cu->dbg, datap); 348 break; 349 350 default: 351 __libdw_seterrno (DWARF_E_NO_CONSTANT); 352 return -1; 353 } 354 355 return 0; 356 } 357 INTDEF(dwarf_formudata) 358