1da0c48c4Sopenharmony_ci/* Return sibling of given DIE.
2da0c48c4Sopenharmony_ci   Copyright (C) 2003-2010, 2014, 2015 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
5da0c48c4Sopenharmony_ci
6da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
7da0c48c4Sopenharmony_ci   it under the terms of either
8da0c48c4Sopenharmony_ci
9da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
10da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
11da0c48c4Sopenharmony_ci       your option) any later version
12da0c48c4Sopenharmony_ci
13da0c48c4Sopenharmony_ci   or
14da0c48c4Sopenharmony_ci
15da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
16da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
17da0c48c4Sopenharmony_ci       your option) any later version
18da0c48c4Sopenharmony_ci
19da0c48c4Sopenharmony_ci   or both in parallel, as here.
20da0c48c4Sopenharmony_ci
21da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
22da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
23da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24da0c48c4Sopenharmony_ci   General Public License for more details.
25da0c48c4Sopenharmony_ci
26da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
27da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
28da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
29da0c48c4Sopenharmony_ci
30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
31da0c48c4Sopenharmony_ci# include <config.h>
32da0c48c4Sopenharmony_ci#endif
33da0c48c4Sopenharmony_ci
34da0c48c4Sopenharmony_ci#include "libdwP.h"
35da0c48c4Sopenharmony_ci#include <dwarf.h>
36da0c48c4Sopenharmony_ci#include <string.h>
37da0c48c4Sopenharmony_ci
38da0c48c4Sopenharmony_ci
39da0c48c4Sopenharmony_ciint
40da0c48c4Sopenharmony_cidwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result)
41da0c48c4Sopenharmony_ci{
42da0c48c4Sopenharmony_ci  /* Ignore previous errors.  */
43da0c48c4Sopenharmony_ci  if (die == NULL)
44da0c48c4Sopenharmony_ci    return -1;
45da0c48c4Sopenharmony_ci
46da0c48c4Sopenharmony_ci  /* result is declared NN */
47da0c48c4Sopenharmony_ci
48da0c48c4Sopenharmony_ci  if (result != die)
49da0c48c4Sopenharmony_ci    result->addr = NULL;
50da0c48c4Sopenharmony_ci
51da0c48c4Sopenharmony_ci  unsigned int level = 0;
52da0c48c4Sopenharmony_ci
53da0c48c4Sopenharmony_ci  /* Copy of the current DIE.  */
54da0c48c4Sopenharmony_ci  Dwarf_Die this_die = *die;
55da0c48c4Sopenharmony_ci  /* Temporary attributes we create.  */
56da0c48c4Sopenharmony_ci  Dwarf_Attribute sibattr;
57da0c48c4Sopenharmony_ci  /* Copy of the CU in the request.  */
58da0c48c4Sopenharmony_ci  sibattr.cu = this_die.cu;
59da0c48c4Sopenharmony_ci  /* That's the address we start looking.  */
60da0c48c4Sopenharmony_ci  unsigned char *addr;
61da0c48c4Sopenharmony_ci
62da0c48c4Sopenharmony_ci  /* Search for the beginning of the next die on this level.  We
63da0c48c4Sopenharmony_ci     must not return the dies for children of the given die.  */
64da0c48c4Sopenharmony_ci  do
65da0c48c4Sopenharmony_ci    {
66da0c48c4Sopenharmony_ci      /* Find the end of the DIE or the sibling attribute.  */
67da0c48c4Sopenharmony_ci      addr = __libdw_find_attr (&this_die, DW_AT_sibling, &sibattr.code,
68da0c48c4Sopenharmony_ci				&sibattr.form);
69da0c48c4Sopenharmony_ci      if (addr != NULL && sibattr.code == DW_AT_sibling)
70da0c48c4Sopenharmony_ci	{
71da0c48c4Sopenharmony_ci	  Dwarf_Off offset;
72da0c48c4Sopenharmony_ci	  sibattr.valp = addr;
73da0c48c4Sopenharmony_ci	  if (unlikely (__libdw_formref (&sibattr, &offset) != 0))
74da0c48c4Sopenharmony_ci	    /* Something went wrong.  */
75da0c48c4Sopenharmony_ci	    return -1;
76da0c48c4Sopenharmony_ci
77da0c48c4Sopenharmony_ci	  /* The sibling attribute should point after this DIE in the CU.
78da0c48c4Sopenharmony_ci	     But not after the end of the CU.  */
79da0c48c4Sopenharmony_ci	  size_t size = sibattr.cu->endp - sibattr.cu->startp;
80da0c48c4Sopenharmony_ci	  size_t die_off = this_die.addr - this_die.cu->startp;
81da0c48c4Sopenharmony_ci	  if (unlikely (offset >= size || offset <= die_off))
82da0c48c4Sopenharmony_ci	    {
83da0c48c4Sopenharmony_ci	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
84da0c48c4Sopenharmony_ci	      return -1;
85da0c48c4Sopenharmony_ci	    }
86da0c48c4Sopenharmony_ci
87da0c48c4Sopenharmony_ci	  /* Compute the next address.  */
88da0c48c4Sopenharmony_ci	  addr = sibattr.cu->startp + offset;
89da0c48c4Sopenharmony_ci	}
90da0c48c4Sopenharmony_ci      else if (unlikely (addr == NULL)
91da0c48c4Sopenharmony_ci	       || unlikely (this_die.abbrev == DWARF_END_ABBREV))
92da0c48c4Sopenharmony_ci	return -1;
93da0c48c4Sopenharmony_ci      else if (this_die.abbrev->has_children)
94da0c48c4Sopenharmony_ci	/* This abbreviation has children.  */
95da0c48c4Sopenharmony_ci	++level;
96da0c48c4Sopenharmony_ci
97da0c48c4Sopenharmony_ci      /* End of the buffer.  */
98da0c48c4Sopenharmony_ci      unsigned char *endp = sibattr.cu->endp;
99da0c48c4Sopenharmony_ci
100da0c48c4Sopenharmony_ci      while (1)
101da0c48c4Sopenharmony_ci	{
102da0c48c4Sopenharmony_ci	  /* Make sure we are still in range.  Some producers might skip
103da0c48c4Sopenharmony_ci	     the trailing NUL bytes.  */
104da0c48c4Sopenharmony_ci	  if (addr >= endp)
105da0c48c4Sopenharmony_ci	    return 1;
106da0c48c4Sopenharmony_ci
107da0c48c4Sopenharmony_ci	  if (*addr != '\0')
108da0c48c4Sopenharmony_ci	    break;
109da0c48c4Sopenharmony_ci
110da0c48c4Sopenharmony_ci	  if (level-- == 0)
111da0c48c4Sopenharmony_ci	    {
112da0c48c4Sopenharmony_ci	      if (result != die)
113da0c48c4Sopenharmony_ci		result->addr = addr;
114da0c48c4Sopenharmony_ci	      /* No more sibling at all.  */
115da0c48c4Sopenharmony_ci	      return 1;
116da0c48c4Sopenharmony_ci	    }
117da0c48c4Sopenharmony_ci
118da0c48c4Sopenharmony_ci	  ++addr;
119da0c48c4Sopenharmony_ci	}
120da0c48c4Sopenharmony_ci
121da0c48c4Sopenharmony_ci      /* Initialize the 'current DIE'.  */
122da0c48c4Sopenharmony_ci      this_die.addr = addr;
123da0c48c4Sopenharmony_ci      this_die.abbrev = NULL;
124da0c48c4Sopenharmony_ci    }
125da0c48c4Sopenharmony_ci  while (level > 0);
126da0c48c4Sopenharmony_ci
127da0c48c4Sopenharmony_ci  /* Maybe we reached the end of the CU.  */
128da0c48c4Sopenharmony_ci  unsigned char *endp = sibattr.cu->endp;
129da0c48c4Sopenharmony_ci  if (addr >= endp)
130da0c48c4Sopenharmony_ci    return 1;
131da0c48c4Sopenharmony_ci
132da0c48c4Sopenharmony_ci  /* Clear the entire DIE structure.  This signals we have not yet
133da0c48c4Sopenharmony_ci     determined any of the information.  */
134da0c48c4Sopenharmony_ci  memset (result, '\0', sizeof (Dwarf_Die));
135da0c48c4Sopenharmony_ci
136da0c48c4Sopenharmony_ci  /* We have the address.  */
137da0c48c4Sopenharmony_ci  result->addr = addr;
138da0c48c4Sopenharmony_ci
139da0c48c4Sopenharmony_ci  /* Same CU as the parent.  */
140da0c48c4Sopenharmony_ci  result->cu = sibattr.cu;
141da0c48c4Sopenharmony_ci
142da0c48c4Sopenharmony_ci  return 0;
143da0c48c4Sopenharmony_ci}
144da0c48c4Sopenharmony_ciINTDEF(dwarf_siblingof)
145