|
Packit |
032894 |
/* Return sibling of given DIE.
|
|
Packit |
032894 |
Copyright (C) 2003-2010, 2014, 2015 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 "libdwP.h"
|
|
Packit |
032894 |
#include <dwarf.h>
|
|
Packit |
032894 |
#include <string.h>
|
|
Packit |
032894 |
|
|
Packit |
032894 |
|
|
Packit |
032894 |
int
|
|
Packit |
032894 |
dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
/* Ignore previous errors. */
|
|
Packit |
032894 |
if (die == NULL)
|
|
Packit |
032894 |
return -1;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* result is declared NN */
|
|
Packit |
032894 |
|
|
Packit |
032894 |
if (result != die)
|
|
Packit |
032894 |
result->addr = NULL;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
unsigned int level = 0;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Copy of the current DIE. */
|
|
Packit |
032894 |
Dwarf_Die this_die = *die;
|
|
Packit |
032894 |
/* Temporary attributes we create. */
|
|
Packit |
032894 |
Dwarf_Attribute sibattr;
|
|
Packit |
032894 |
/* Copy of the CU in the request. */
|
|
Packit |
032894 |
sibattr.cu = this_die.cu;
|
|
Packit |
032894 |
/* That's the address we start looking. */
|
|
Packit |
032894 |
unsigned char *addr;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Search for the beginning of the next die on this level. We
|
|
Packit |
032894 |
must not return the dies for children of the given die. */
|
|
Packit |
032894 |
do
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
/* Find the end of the DIE or the sibling attribute. */
|
|
Packit |
032894 |
addr = __libdw_find_attr (&this_die, DW_AT_sibling, &sibattr.code,
|
|
Packit |
032894 |
&sibattr.form);
|
|
Packit |
032894 |
if (addr != NULL && sibattr.code == DW_AT_sibling)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
Dwarf_Off offset;
|
|
Packit |
032894 |
sibattr.valp = addr;
|
|
Packit |
032894 |
if (unlikely (__libdw_formref (&sibattr, &offset) != 0))
|
|
Packit |
032894 |
/* Something went wrong. */
|
|
Packit |
032894 |
return -1;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* The sibling attribute should point after this DIE in the CU.
|
|
Packit |
032894 |
But not after the end of the CU. */
|
|
Packit |
032894 |
size_t size = sibattr.cu->endp - sibattr.cu->startp;
|
|
Packit |
032894 |
size_t die_off = this_die.addr - this_die.cu->startp;
|
|
Packit |
032894 |
if (unlikely (offset >= size || offset <= die_off))
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
__libdw_seterrno (DWARF_E_INVALID_DWARF);
|
|
Packit |
032894 |
return -1;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Compute the next address. */
|
|
Packit |
032894 |
addr = sibattr.cu->startp + offset;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
else if (unlikely (addr == NULL)
|
|
Packit |
032894 |
|| unlikely (this_die.abbrev == DWARF_END_ABBREV))
|
|
Packit |
032894 |
return -1;
|
|
Packit |
032894 |
else if (this_die.abbrev->has_children)
|
|
Packit |
032894 |
/* This abbreviation has children. */
|
|
Packit |
032894 |
++level;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* End of the buffer. */
|
|
Packit |
032894 |
unsigned char *endp = sibattr.cu->endp;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
while (1)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
/* Make sure we are still in range. Some producers might skip
|
|
Packit |
032894 |
the trailing NUL bytes. */
|
|
Packit |
032894 |
if (addr >= endp)
|
|
Packit |
032894 |
return 1;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
if (*addr != '\0')
|
|
Packit |
032894 |
break;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
if (level-- == 0)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
if (result != die)
|
|
Packit |
032894 |
result->addr = addr;
|
|
Packit |
032894 |
/* No more sibling at all. */
|
|
Packit |
032894 |
return 1;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
++addr;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Initialize the 'current DIE'. */
|
|
Packit |
032894 |
this_die.addr = addr;
|
|
Packit |
032894 |
this_die.abbrev = NULL;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
while (level > 0);
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Maybe we reached the end of the CU. */
|
|
Packit |
032894 |
unsigned char *endp = sibattr.cu->endp;
|
|
Packit |
032894 |
if (addr >= endp)
|
|
Packit |
032894 |
return 1;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Clear the entire DIE structure. This signals we have not yet
|
|
Packit |
032894 |
determined any of the information. */
|
|
Packit |
032894 |
memset (result, '\0', sizeof (Dwarf_Die));
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* We have the address. */
|
|
Packit |
032894 |
result->addr = addr;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Same CU as the parent. */
|
|
Packit |
032894 |
result->cu = sibattr.cu;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
return 0;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
INTDEF(dwarf_siblingof)
|