Blame libdw/dwarf_formudata.c

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