Home | History | Annotate | Download | only in libdw
      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