Blame libdw/dwarf_formudata.c

Packit 032894
/* Return unsigned constant represented by attribute.
Packit 032894
   Copyright (C) 2003-2012, 2014, 2017 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include <dwarf.h>
Packit 032894
#include "libdwP.h"
Packit 032894
Packit 032894
internal_function const unsigned char *
Packit 032894
__libdw_formptr (Dwarf_Attribute *attr, int sec_index,
Packit 032894
		 int err_nodata, const unsigned char **endpp,
Packit 032894
		 Dwarf_Off *offsetp)
Packit 032894
{
Packit 032894
  if (attr == NULL)
Packit 032894
    return NULL;
Packit 032894
Packit 032894
  const Elf_Data *d = attr->cu->dbg->sectiondata[sec_index];
Packit 032894
  Dwarf_CU *skel = NULL; /* See below, needed for GNU DebugFission.  */
Packit 032894
  if (unlikely (d == NULL
Packit 032894
		&& sec_index == IDX_debug_ranges
Packit 032894
		&& attr->cu->version < 5
Packit 032894
		&& attr->cu->unit_type == DW_UT_split_compile))
Packit 032894
    {
Packit 032894
      skel = __libdw_find_split_unit (attr->cu);
Packit 032894
      if (skel != NULL)
Packit 032894
	d = skel->dbg->sectiondata[IDX_debug_ranges];
Packit 032894
    }
Packit 032894
Packit 032894
  if (unlikely (d == NULL))
Packit 032894
    {
Packit 032894
      __libdw_seterrno (err_nodata);
Packit 032894
      return NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  Dwarf_Word offset;
Packit 032894
  if (attr->form == DW_FORM_sec_offset)
Packit 032894
    {
Packit 032894
      /* GNU DebugFission is slightly odd.  It uses DW_FORM_sec_offset
Packit 032894
	 in split units, but they are really (unrelocated) offsets
Packit 032894
	 from the skeleton DW_AT_GNU_ranges_base (which is only used
Packit 032894
	 for the split unit, not the skeleton ranges itself, see also
Packit 032894
	 DW_AT_rnglists_base, which is used in DWARF5 for both, but
Packit 032894
	 points to the offsets index).  So it isn't really a formptr,
Packit 032894
	 but an offset + base calculation.  */
Packit 032894
      if (unlikely (skel != NULL))
Packit 032894
	{
Packit 032894
	  Elf_Data *data = attr->cu->dbg->sectiondata[cu_sec_idx (attr->cu)];
Packit 032894
	  const unsigned char *datap = attr->valp;
Packit 032894
	  size_t size = attr->cu->offset_size;
Packit 032894
	  if (unlikely (data == NULL
Packit 032894
			|| datap < (const unsigned char *) data->d_buf
Packit 032894
			|| data->d_size < size
Packit 032894
			|| ((size_t) (datap
Packit 032894
				      - (const unsigned char *) data->d_buf)
Packit 032894
			    > data->d_size - size)))
Packit 032894
	    goto invalid;
Packit 032894
Packit 032894
	  if (size == 4)
Packit 032894
	    offset = read_4ubyte_unaligned (attr->cu->dbg, datap);
Packit 032894
	  else
Packit 032894
	    offset = read_8ubyte_unaligned (attr->cu->dbg, datap);
Packit 032894
Packit 032894
	  offset += __libdw_cu_ranges_base (skel);
Packit 032894
	}
Packit 032894
      else
Packit 032894
	{
Packit 032894
	  if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
Packit 032894
				   cu_sec_idx (attr->cu), attr->valp,
Packit 032894
				   attr->cu->offset_size, &offset,
Packit 032894
				   sec_index, 0))
Packit 032894
	    return NULL;
Packit 032894
	}
Packit 032894
    }
Packit 032894
  else if (attr->cu->version > 3)
Packit 032894
    goto invalid;
Packit 032894
  else
Packit 032894
    switch (attr->form)
Packit 032894
      {
Packit 032894
      case DW_FORM_data4:
Packit 032894
      case DW_FORM_data8:
Packit 032894
	if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
Packit 032894
				 cu_sec_idx (attr->cu),
Packit 032894
				 attr->valp,
Packit 032894
				 attr->form == DW_FORM_data4 ? 4 : 8,
Packit 032894
				 &offset, sec_index, 0))
Packit 032894
	  return NULL;
Packit 032894
	break;
Packit 032894
Packit 032894
      default:
Packit 032894
	if (INTUSE(dwarf_formudata) (attr, &offset))
Packit 032894
	  return NULL;
Packit 032894
      };
Packit 032894
Packit 032894
  unsigned char *readp = d->d_buf + offset;
Packit 032894
  unsigned char *endp = d->d_buf + d->d_size;
Packit 032894
  if (unlikely (readp >= endp))
Packit 032894
    {
Packit 032894
    invalid:
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
      return NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  if (endpp != NULL)
Packit 032894
    *endpp = endp;
Packit 032894
  if (offsetp != NULL)
Packit 032894
    *offsetp = offset;
Packit 032894
  return readp;
Packit 032894
}
Packit 032894
Packit 032894
int
Packit 032894
dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
Packit 032894
{
Packit 032894
  if (attr == NULL)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  const unsigned char *datap = attr->valp;
Packit 032894
  const unsigned char *endp = attr->cu->endp;
Packit 032894
Packit 032894
  switch (attr->form)
Packit 032894
    {
Packit 032894
    case DW_FORM_data1:
Packit 032894
      if (datap + 1 > endp)
Packit 032894
	{
Packit 032894
	invalid:
Packit 032894
	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
      *return_uval = *attr->valp;
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_FORM_data2:
Packit 032894
      if (datap + 2 > endp)
Packit 032894
	goto invalid;
Packit 032894
      *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_FORM_data4:
Packit 032894
    case DW_FORM_data8:
Packit 032894
    case DW_FORM_sec_offset:
Packit 032894
      /* Before DWARF4 data4 and data8 are pure constants unless the
Packit 032894
	 attribute also allows offsets (*ptr classes), since DWARF4
Packit 032894
	 they are always just constants (start_scope is special though,
Packit 032894
	 since it only could express a rangelist since DWARF4).  */
Packit 032894
      if (attr->form == DW_FORM_sec_offset
Packit 032894
	  || (attr->cu->version < 4 && attr->code != DW_AT_start_scope))
Packit 032894
	{
Packit 032894
	  switch (attr->code)
Packit 032894
	    {
Packit 032894
	    case DW_AT_data_member_location:
Packit 032894
	    case DW_AT_frame_base:
Packit 032894
	    case DW_AT_location:
Packit 032894
	    case DW_AT_return_addr:
Packit 032894
	    case DW_AT_segment:
Packit 032894
	    case DW_AT_static_link:
Packit 032894
	    case DW_AT_string_length:
Packit 032894
	    case DW_AT_use_location:
Packit 032894
	    case DW_AT_vtable_elem_location:
Packit 032894
	    case DW_AT_GNU_locviews:
Packit 032894
	    case DW_AT_loclists_base:
Packit 032894
	      if (attr->cu->version < 5)
Packit 032894
		{
Packit 032894
		  /* loclistptr */
Packit 032894
		  if (__libdw_formptr (attr, IDX_debug_loc,
Packit 032894
				       DWARF_E_NO_DEBUG_LOC, NULL,
Packit 032894
				       return_uval) == NULL)
Packit 032894
		    return -1;
Packit 032894
		}
Packit 032894
	      else
Packit 032894
		{
Packit 032894
		  /* loclist, loclistsptr */
Packit 032894
		  if (__libdw_formptr (attr, IDX_debug_loclists,
Packit 032894
				       DWARF_E_NO_DEBUG_LOCLISTS, NULL,
Packit 032894
				       return_uval) == NULL)
Packit 032894
		    return -1;
Packit 032894
		}
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_AT_macro_info:
Packit 032894
	      /* macptr into .debug_macinfo */
Packit 032894
	      if (__libdw_formptr (attr, IDX_debug_macinfo,
Packit 032894
				   DWARF_E_NO_ENTRY, NULL,
Packit 032894
				   return_uval) == NULL)
Packit 032894
		return -1;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_AT_GNU_macros:
Packit 032894
	    case DW_AT_macros:
Packit 032894
	      /* macptr into .debug_macro */
Packit 032894
	      if (__libdw_formptr (attr, IDX_debug_macro,
Packit 032894
				   DWARF_E_NO_ENTRY, NULL,
Packit 032894
				   return_uval) == NULL)
Packit 032894
		return -1;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_AT_ranges:
Packit 032894
	    case DW_AT_start_scope:
Packit 032894
	    case DW_AT_GNU_ranges_base:
Packit 032894
	    case DW_AT_rnglists_base:
Packit 032894
	      if (attr->cu->version < 5)
Packit 032894
		{
Packit 032894
		  /* rangelistptr */
Packit 032894
		  if (__libdw_formptr (attr, IDX_debug_ranges,
Packit 032894
				       DWARF_E_NO_DEBUG_RANGES, NULL,
Packit 032894
				       return_uval) == NULL)
Packit 032894
		    return -1;
Packit 032894
		}
Packit 032894
	      else
Packit 032894
		{
Packit 032894
		  /* rnglistsptr */
Packit 032894
		  if (__libdw_formptr (attr, IDX_debug_rnglists,
Packit 032894
				       DWARF_E_NO_DEBUG_RNGLISTS, NULL,
Packit 032894
				       return_uval) == NULL)
Packit 032894
		    return -1;
Packit 032894
		}
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_AT_stmt_list:
Packit 032894
	      /* lineptr */
Packit 032894
	      if (__libdw_formptr (attr, IDX_debug_line,
Packit 032894
				   DWARF_E_NO_DEBUG_LINE, NULL,
Packit 032894
				   return_uval) == NULL)
Packit 032894
		return -1;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_AT_addr_base:
Packit 032894
	    case DW_AT_GNU_addr_base:
Packit 032894
	      /* addrptr */
Packit 032894
	      if (__libdw_formptr (attr, IDX_debug_addr,
Packit 032894
				   DWARF_E_NO_DEBUG_ADDR, NULL,
Packit 032894
				   return_uval) == NULL)
Packit 032894
		return -1;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_AT_str_offsets_base:
Packit 032894
	      /* stroffsetsptr */
Packit 032894
	      if (__libdw_formptr (attr, IDX_debug_str_offsets,
Packit 032894
				   DWARF_E_NO_STR_OFFSETS, NULL,
Packit 032894
				   return_uval) == NULL)
Packit 032894
		return -1;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    default:
Packit 032894
	      /* sec_offset can only be used by one of the above attrs.  */
Packit 032894
	      if (attr->form == DW_FORM_sec_offset)
Packit 032894
		{
Packit 032894
		  __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
		  return -1;
Packit 032894
		}
Packit 032894
Packit 032894
	      /* Not one of the special attributes, just a constant.  */
Packit 032894
	      if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
Packit 032894
					attr->valp,
Packit 032894
					attr->form == DW_FORM_data4 ? 4 : 8,
Packit 032894
					return_uval))
Packit 032894
		return -1;
Packit 032894
	      break;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
      else
Packit 032894
	{
Packit 032894
	  /* We are dealing with a constant data4 or data8.  */
Packit 032894
	  if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
Packit 032894
				    attr->valp,
Packit 032894
				    attr->form == DW_FORM_data4 ? 4 : 8,
Packit 032894
				    return_uval))
Packit 032894
	    return -1;
Packit 032894
	}
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_FORM_sdata:
Packit 032894
      if (datap + 1 > endp)
Packit 032894
	goto invalid;
Packit 032894
      get_sleb128 (*return_uval, datap, endp);
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_FORM_udata:
Packit 032894
    case DW_FORM_rnglistx:
Packit 032894
    case DW_FORM_loclistx:
Packit 032894
      if (datap + 1 > endp)
Packit 032894
	goto invalid;
Packit 032894
      get_uleb128 (*return_uval, datap, endp);
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_FORM_implicit_const:
Packit 032894
      // The data comes from the abbrev, which has been bounds checked.
Packit 032894
      get_sleb128_unchecked (*return_uval, datap);
Packit 032894
      break;
Packit 032894
Packit 032894
    /* These are indexes into the .debug_addr section, normally resolved
Packit 032894
       with dwarf_formaddr.  Here treat as constants.  */
Packit 032894
    case DW_FORM_GNU_addr_index:
Packit 032894
    case DW_FORM_addrx:
Packit 032894
      if (datap >= endp)
Packit 032894
	goto invalid;
Packit 032894
      get_uleb128 (*return_uval, datap, endp);
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_FORM_addrx1:
Packit 032894
      if (datap >= endp - 1)
Packit 032894
	goto invalid;
Packit 032894
      *return_uval = *datap;
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_FORM_addrx2:
Packit 032894
      if (datap >= endp - 2)
Packit 032894
	goto invalid;
Packit 032894
      *return_uval = read_2ubyte_unaligned (attr->cu->dbg, datap);
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_FORM_addrx3:
Packit 032894
      if (datap >= endp - 3)
Packit 032894
	goto invalid;
Packit 032894
      *return_uval = read_3ubyte_unaligned (attr->cu->dbg, datap);
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_FORM_addrx4:
Packit 032894
      if (datap >= endp - 4)
Packit 032894
	goto invalid;
Packit 032894
      *return_uval = read_4ubyte_unaligned (attr->cu->dbg, datap);
Packit 032894
      break;
Packit 032894
Packit 032894
    default:
Packit 032894
      __libdw_seterrno (DWARF_E_NO_CONSTANT);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
INTDEF(dwarf_formudata)