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