Blame libdw/dwarf_child.c

Packit Service 97d2fb
/* Return child of current DIE.
Packit Service 97d2fb
   Copyright (C) 2003-2011, 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 "libdwP.h"
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
Packit Service 97d2fb
/* Some arbitrary value not conflicting with any existing code.  */
Packit Service 97d2fb
#define INVALID 0xffffe444
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
unsigned char *
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
Packit Service 97d2fb
		   unsigned int *codep, unsigned int *formp)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const unsigned char *readp = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Find the abbreviation entry.  */
Packit Service 97d2fb
  Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, &readp);
Packit Service 97d2fb
  if (unlikely (abbrevp == DWARF_END_ABBREV))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Search the name attribute.  Attribute has been checked when
Packit Service 97d2fb
     Dwarf_Abbrev was created, we can read unchecked.  */
Packit Service 97d2fb
  const unsigned char *attrp = abbrevp->attrp;
Packit Service 97d2fb
  while (1)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Get attribute name and form.  */
Packit Service 97d2fb
      unsigned int attr_name;
Packit Service 97d2fb
      get_uleb128_unchecked (attr_name, attrp);
Packit Service 97d2fb
Packit Service 97d2fb
      unsigned int attr_form;
Packit Service 97d2fb
      get_uleb128_unchecked (attr_form, attrp);
Packit Service 97d2fb
Packit Service 97d2fb
      /* We can stop if we found the attribute with value zero.  */
Packit Service 97d2fb
      if (attr_name == 0 && attr_form == 0)
Packit Service 97d2fb
	break;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Is this the name attribute?  */
Packit Service 97d2fb
      if (attr_name == search_name && search_name != INVALID)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (codep != NULL)
Packit Service 97d2fb
	    *codep = attr_name;
Packit Service 97d2fb
	  if (formp != NULL)
Packit Service 97d2fb
	    *formp = attr_form;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Normally the attribute data comes from the DIE/info,
Packit Service 97d2fb
	     except for implicit_form, where it comes from the abbrev.  */
Packit Service 97d2fb
	  if (attr_form == DW_FORM_implicit_const)
Packit Service 97d2fb
	    return (unsigned char *) attrp;
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    return (unsigned char *) readp;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Skip over the rest of this attribute (if there is any).  */
Packit Service 97d2fb
      if (attr_form != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  size_t len = __libdw_form_val_len (die->cu, attr_form, readp);
Packit Service 97d2fb
	  if (unlikely (len == (size_t) -1l))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      readp = NULL;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  // __libdw_form_val_len will have done a bounds check.
Packit Service 97d2fb
	  readp += len;
Packit Service 97d2fb
Packit Service 97d2fb
	  // If the value is in the abbrev data, skip it.
Packit Service 97d2fb
	  if (attr_form == DW_FORM_implicit_const)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      int64_t attr_value __attribute__((__unused__));
Packit Service 97d2fb
	      get_sleb128_unchecked (attr_value, attrp);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  // XXX Do we need other values?
Packit Service 97d2fb
  if (codep != NULL)
Packit Service 97d2fb
    *codep = INVALID;
Packit Service 97d2fb
  if (formp != NULL)
Packit Service 97d2fb
    *formp = INVALID;
Packit Service 97d2fb
Packit Service 97d2fb
  return (unsigned char *) readp;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwarf_child (Dwarf_Die *die, Dwarf_Die *result)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Ignore previous errors.  */
Packit Service 97d2fb
  if (die == NULL)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Find the abbreviation entry.  */
Packit Service 97d2fb
  Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL);
Packit Service 97d2fb
  if (unlikely (abbrevp == DWARF_END_ABBREV))
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
  /* If there are no children, do not search.  */
Packit Service 97d2fb
  if (! abbrevp->has_children)
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Skip past the last attribute.  */
Packit Service 97d2fb
  void *addr = __libdw_find_attr (die, INVALID, NULL, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  if (addr == NULL)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* RESULT can be the same as DIE.  So preserve what we need.  */
Packit Service 97d2fb
  struct Dwarf_CU *cu = die->cu;
Packit Service 97d2fb
Packit Service 97d2fb
  /* It's kosher (just suboptimal) to have a null entry first thing (7.5.3).
Packit Service 97d2fb
     So if this starts with ULEB128 of 0 (even with silly encoding of 0),
Packit Service 97d2fb
     it is a kosher null entry and we do not really have any children.  */
Packit Service 97d2fb
  const unsigned char *code = addr;
Packit Service 97d2fb
  const unsigned char *endp = cu->endp;
Packit Service 97d2fb
  while (1)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (unlikely (code >= endp)) /* Truncated section.  */
Packit Service 97d2fb
	return 1;
Packit Service 97d2fb
      if (unlikely (*code == 0x80))
Packit Service 97d2fb
	++code;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	break;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (unlikely (*code == '\0'))
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Clear the entire DIE structure.  This signals we have not yet
Packit Service 97d2fb
     determined any of the information.  */
Packit Service 97d2fb
  memset (result, '\0', sizeof (Dwarf_Die));
Packit Service 97d2fb
Packit Service 97d2fb
  /* We have the address.  */
Packit Service 97d2fb
  result->addr = addr;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Same CU as the parent.  */
Packit Service 97d2fb
  result->cu = cu;
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(dwarf_child)