Blame libdw/dwarf_getabbrev.c

Packit 032894
/* Get abbreviation at given offset.
Packit 032894
   Copyright (C) 2003, 2004, 2005, 2006, 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
Packit 032894
Dwarf_Abbrev *
Packit 032894
internal_function
Packit 032894
__libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset,
Packit 032894
		   size_t *lengthp, Dwarf_Abbrev *result)
Packit 032894
{
Packit 032894
  /* Don't fail if there is not .debug_abbrev section.  */
Packit 032894
  if (dbg->sectiondata[IDX_debug_abbrev] == NULL)
Packit 032894
    return NULL;
Packit 032894
Packit 032894
  if (offset >= dbg->sectiondata[IDX_debug_abbrev]->d_size)
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_OFFSET);
Packit 032894
      return NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  const unsigned char *abbrevp
Packit 032894
    = (unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + offset;
Packit 032894
Packit 032894
  if (*abbrevp == '\0')
Packit 032894
    /* We are past the last entry.  */
Packit 032894
    return DWARF_END_ABBREV;
Packit 032894
Packit 032894
  /* 7.5.3 Abbreviations Tables
Packit 032894
Packit 032894
     [...] Each declaration begins with an unsigned LEB128 number
Packit 032894
     representing the abbreviation code itself.  [...]  The
Packit 032894
     abbreviation code is followed by another unsigned LEB128
Packit 032894
     number that encodes the entry's tag.  [...]
Packit 032894
Packit 032894
     [...] Following the tag encoding is a 1-byte value that
Packit 032894
     determines whether a debugging information entry using this
Packit 032894
     abbreviation has child entries or not. [...]
Packit 032894
Packit 032894
     [...] Finally, the child encoding is followed by a series of
Packit 032894
     attribute specifications. Each attribute specification
Packit 032894
     consists of two parts. The first part is an unsigned LEB128
Packit 032894
     number representing the attribute's name. The second part is
Packit 032894
     an unsigned LEB128 number representing the attribute's form.  */
Packit 032894
  const unsigned char *end = (dbg->sectiondata[IDX_debug_abbrev]->d_buf
Packit 032894
			      + dbg->sectiondata[IDX_debug_abbrev]->d_size);
Packit 032894
  const unsigned char *start_abbrevp = abbrevp;
Packit 032894
  unsigned int code;
Packit 032894
  get_uleb128 (code, abbrevp, end);
Packit 032894
Packit 032894
  /* Check whether this code is already in the hash table.  */
Packit 032894
  bool foundit = false;
Packit 032894
  Dwarf_Abbrev *abb = NULL;
Packit 032894
  if (cu == NULL
Packit 032894
      || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code)) == NULL)
Packit 032894
    {
Packit 032894
      if (result == NULL)
Packit 032894
	abb = libdw_typed_alloc (dbg, Dwarf_Abbrev);
Packit 032894
      else
Packit 032894
	abb = result;
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      foundit = true;
Packit 032894
Packit 032894
      if (unlikely (abb->offset != offset))
Packit 032894
	{
Packit 032894
	  /* A duplicate abbrev code at a different offset,
Packit 032894
	     that should never happen.  */
Packit 032894
	invalid:
Packit 032894
	  if (! foundit)
Packit 032894
	    libdw_typed_unalloc (dbg, Dwarf_Abbrev);
Packit 032894
	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
	  return NULL;
Packit 032894
	}
Packit 032894
Packit 032894
      /* If the caller doesn't need the length we are done.  */
Packit 032894
      if (lengthp == NULL)
Packit 032894
	goto out;
Packit 032894
    }
Packit 032894
Packit 032894
  /* If there is already a value in the hash table we are going to
Packit 032894
     overwrite its content.  This must not be a problem, since the
Packit 032894
     content better be the same.  */
Packit 032894
  abb->code = code;
Packit 032894
  if (abbrevp >= end)
Packit 032894
    goto invalid;
Packit 032894
  get_uleb128 (abb->tag, abbrevp, end);
Packit 032894
  if (abbrevp + 1 >= end)
Packit 032894
    goto invalid;
Packit 032894
  abb->has_children = *abbrevp++ == DW_CHILDREN_yes;
Packit 032894
  abb->attrp = (unsigned char *) abbrevp;
Packit 032894
  abb->offset = offset;
Packit 032894
Packit 032894
  /* Skip over all the attributes and check rest of the abbrev is valid.  */
Packit 032894
  unsigned int attrname;
Packit 032894
  unsigned int attrform;
Packit 032894
  do
Packit 032894
    {
Packit 032894
      if (abbrevp >= end)
Packit 032894
	goto invalid;
Packit 032894
      get_uleb128 (attrname, abbrevp, end);
Packit 032894
      if (abbrevp >= end)
Packit 032894
	goto invalid;
Packit 032894
      get_uleb128 (attrform, abbrevp, end);
Packit 032894
      if (attrform == DW_FORM_implicit_const)
Packit 032894
	{
Packit 032894
	  int64_t formval __attribute__((__unused__));
Packit 032894
	  if (abbrevp >= end)
Packit 032894
	    goto invalid;
Packit 032894
	  get_sleb128 (formval, abbrevp, end);
Packit 032894
	}
Packit 032894
    }
Packit 032894
  while (attrname != 0 || attrform != 0);
Packit 032894
Packit 032894
  /* Return the length to the caller if she asked for it.  */
Packit 032894
  if (lengthp != NULL)
Packit 032894
    *lengthp = abbrevp - start_abbrevp;
Packit 032894
Packit 032894
  /* Add the entry to the hash table.  */
Packit 032894
  if (cu != NULL && ! foundit)
Packit 032894
    if (Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, abb->code, abb) == -1)
Packit 032894
      {
Packit 032894
	/* The entry was already in the table, remove the one we just
Packit 032894
	   created and get the one already inserted.  */
Packit 032894
	libdw_typed_unalloc (dbg, Dwarf_Abbrev);
Packit 032894
	abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code);
Packit 032894
      }
Packit 032894
Packit 032894
 out:
Packit 032894
  return abb;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
Dwarf_Abbrev *
Packit 032894
dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, size_t *lengthp)
Packit 032894
{
Packit 032894
  if (die == NULL || die->cu == NULL)
Packit 032894
    return NULL;
Packit 032894
Packit 032894
  Dwarf_CU *cu = die->cu;
Packit 032894
  Dwarf *dbg = cu->dbg;
Packit 032894
  Dwarf_Off abbrev_offset = cu->orig_abbrev_offset;
Packit 032894
  Elf_Data *data = dbg->sectiondata[IDX_debug_abbrev];
Packit 032894
  if (data == NULL)
Packit 032894
    return NULL;
Packit 032894
Packit 032894
  if (offset >= data->d_size - abbrev_offset)
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_OFFSET);
Packit 032894
      return NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  return __libdw_getabbrev (dbg, cu, abbrev_offset + offset, lengthp, NULL);
Packit 032894
}