1da0c48c4Sopenharmony_ci/* Return child of current DIE.
2da0c48c4Sopenharmony_ci   Copyright (C) 2003-2011, 2014, 2017 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 <string.h>
36da0c48c4Sopenharmony_ci
37da0c48c4Sopenharmony_ci/* Some arbitrary value not conflicting with any existing code.  */
38da0c48c4Sopenharmony_ci#define INVALID 0xffffe444
39da0c48c4Sopenharmony_ci
40da0c48c4Sopenharmony_ci
41da0c48c4Sopenharmony_ciunsigned char *
42da0c48c4Sopenharmony_ciinternal_function
43da0c48c4Sopenharmony_ci__libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
44da0c48c4Sopenharmony_ci		   unsigned int *codep, unsigned int *formp)
45da0c48c4Sopenharmony_ci{
46da0c48c4Sopenharmony_ci  const unsigned char *readp = NULL;
47da0c48c4Sopenharmony_ci
48da0c48c4Sopenharmony_ci  /* Find the abbreviation entry.  */
49da0c48c4Sopenharmony_ci  Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, &readp);
50da0c48c4Sopenharmony_ci  if (unlikely (abbrevp == DWARF_END_ABBREV))
51da0c48c4Sopenharmony_ci    {
52da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_INVALID_DWARF);
53da0c48c4Sopenharmony_ci      return NULL;
54da0c48c4Sopenharmony_ci    }
55da0c48c4Sopenharmony_ci
56da0c48c4Sopenharmony_ci  const unsigned char *endp = die->cu->endp;
57da0c48c4Sopenharmony_ci
58da0c48c4Sopenharmony_ci  /* Search the name attribute.  Attribute has been checked when
59da0c48c4Sopenharmony_ci     Dwarf_Abbrev was created, we can read unchecked.  */
60da0c48c4Sopenharmony_ci  const unsigned char *attrp = abbrevp->attrp;
61da0c48c4Sopenharmony_ci  while (1)
62da0c48c4Sopenharmony_ci    {
63da0c48c4Sopenharmony_ci      /* Get attribute name and form.  */
64da0c48c4Sopenharmony_ci      unsigned int attr_name;
65da0c48c4Sopenharmony_ci      get_uleb128_unchecked (attr_name, attrp);
66da0c48c4Sopenharmony_ci
67da0c48c4Sopenharmony_ci      unsigned int attr_form;
68da0c48c4Sopenharmony_ci      get_uleb128_unchecked (attr_form, attrp);
69da0c48c4Sopenharmony_ci
70da0c48c4Sopenharmony_ci      /* We can stop if we found the attribute with value zero.  */
71da0c48c4Sopenharmony_ci      if (attr_name == 0 && attr_form == 0)
72da0c48c4Sopenharmony_ci	break;
73da0c48c4Sopenharmony_ci
74da0c48c4Sopenharmony_ci      if (attr_form == DW_FORM_indirect)
75da0c48c4Sopenharmony_ci	{
76da0c48c4Sopenharmony_ci	  get_uleb128 (attr_form, readp, endp);
77da0c48c4Sopenharmony_ci	  if (attr_form == DW_FORM_indirect ||
78da0c48c4Sopenharmony_ci	      attr_form == DW_FORM_implicit_const)
79da0c48c4Sopenharmony_ci	    {
80da0c48c4Sopenharmony_ci	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
81da0c48c4Sopenharmony_ci	      return NULL;
82da0c48c4Sopenharmony_ci	    }
83da0c48c4Sopenharmony_ci	}
84da0c48c4Sopenharmony_ci
85da0c48c4Sopenharmony_ci      /* Is this the name attribute?  */
86da0c48c4Sopenharmony_ci      if (attr_name == search_name && search_name != INVALID)
87da0c48c4Sopenharmony_ci	{
88da0c48c4Sopenharmony_ci	  if (codep != NULL)
89da0c48c4Sopenharmony_ci	    *codep = attr_name;
90da0c48c4Sopenharmony_ci	  if (formp != NULL)
91da0c48c4Sopenharmony_ci	    *formp = attr_form;
92da0c48c4Sopenharmony_ci
93da0c48c4Sopenharmony_ci	  /* Normally the attribute data comes from the DIE/info,
94da0c48c4Sopenharmony_ci	     except for implicit_form, where it comes from the abbrev.  */
95da0c48c4Sopenharmony_ci	  if (attr_form == DW_FORM_implicit_const)
96da0c48c4Sopenharmony_ci	    return (unsigned char *) attrp;
97da0c48c4Sopenharmony_ci	  else
98da0c48c4Sopenharmony_ci	    return (unsigned char *) readp;
99da0c48c4Sopenharmony_ci	}
100da0c48c4Sopenharmony_ci
101da0c48c4Sopenharmony_ci      /* Skip over the rest of this attribute (if there is any).  */
102da0c48c4Sopenharmony_ci      if (attr_form != 0)
103da0c48c4Sopenharmony_ci	{
104da0c48c4Sopenharmony_ci	  size_t len = __libdw_form_val_len (die->cu, attr_form, readp);
105da0c48c4Sopenharmony_ci	  if (unlikely (len == (size_t) -1l))
106da0c48c4Sopenharmony_ci	    {
107da0c48c4Sopenharmony_ci	      readp = NULL;
108da0c48c4Sopenharmony_ci	      break;
109da0c48c4Sopenharmony_ci	    }
110da0c48c4Sopenharmony_ci
111da0c48c4Sopenharmony_ci	  // __libdw_form_val_len will have done a bounds check.
112da0c48c4Sopenharmony_ci	  readp += len;
113da0c48c4Sopenharmony_ci
114da0c48c4Sopenharmony_ci	  // If the value is in the abbrev data, skip it.
115da0c48c4Sopenharmony_ci	  if (attr_form == DW_FORM_implicit_const)
116da0c48c4Sopenharmony_ci	    {
117da0c48c4Sopenharmony_ci	      int64_t attr_value __attribute__((__unused__));
118da0c48c4Sopenharmony_ci	      get_sleb128_unchecked (attr_value, attrp);
119da0c48c4Sopenharmony_ci	    }
120da0c48c4Sopenharmony_ci	}
121da0c48c4Sopenharmony_ci    }
122da0c48c4Sopenharmony_ci
123da0c48c4Sopenharmony_ci  // XXX Do we need other values?
124da0c48c4Sopenharmony_ci  if (codep != NULL)
125da0c48c4Sopenharmony_ci    *codep = INVALID;
126da0c48c4Sopenharmony_ci  if (formp != NULL)
127da0c48c4Sopenharmony_ci    *formp = INVALID;
128da0c48c4Sopenharmony_ci
129da0c48c4Sopenharmony_ci  return (unsigned char *) readp;
130da0c48c4Sopenharmony_ci}
131da0c48c4Sopenharmony_ci
132da0c48c4Sopenharmony_ci
133da0c48c4Sopenharmony_ciint
134da0c48c4Sopenharmony_cidwarf_child (Dwarf_Die *die, Dwarf_Die *result)
135da0c48c4Sopenharmony_ci{
136da0c48c4Sopenharmony_ci  /* Ignore previous errors.  */
137da0c48c4Sopenharmony_ci  if (die == NULL)
138da0c48c4Sopenharmony_ci    return -1;
139da0c48c4Sopenharmony_ci
140da0c48c4Sopenharmony_ci  /* Find the abbreviation entry.  */
141da0c48c4Sopenharmony_ci  Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL);
142da0c48c4Sopenharmony_ci  if (unlikely (abbrevp == DWARF_END_ABBREV))
143da0c48c4Sopenharmony_ci    {
144da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_INVALID_DWARF);
145da0c48c4Sopenharmony_ci      return -1;
146da0c48c4Sopenharmony_ci    }
147da0c48c4Sopenharmony_ci
148da0c48c4Sopenharmony_ci  /* If there are no children, do not search.  */
149da0c48c4Sopenharmony_ci  if (! abbrevp->has_children)
150da0c48c4Sopenharmony_ci    return 1;
151da0c48c4Sopenharmony_ci
152da0c48c4Sopenharmony_ci  /* Skip past the last attribute.  */
153da0c48c4Sopenharmony_ci  void *addr = __libdw_find_attr (die, INVALID, NULL, NULL);
154da0c48c4Sopenharmony_ci
155da0c48c4Sopenharmony_ci  if (addr == NULL)
156da0c48c4Sopenharmony_ci    return -1;
157da0c48c4Sopenharmony_ci
158da0c48c4Sopenharmony_ci  /* RESULT can be the same as DIE.  So preserve what we need.  */
159da0c48c4Sopenharmony_ci  struct Dwarf_CU *cu = die->cu;
160da0c48c4Sopenharmony_ci
161da0c48c4Sopenharmony_ci  /* It's kosher (just suboptimal) to have a null entry first thing (7.5.3).
162da0c48c4Sopenharmony_ci     So if this starts with ULEB128 of 0 (even with silly encoding of 0),
163da0c48c4Sopenharmony_ci     it is a kosher null entry and we do not really have any children.  */
164da0c48c4Sopenharmony_ci  const unsigned char *code = addr;
165da0c48c4Sopenharmony_ci  const unsigned char *endp = cu->endp;
166da0c48c4Sopenharmony_ci  while (1)
167da0c48c4Sopenharmony_ci    {
168da0c48c4Sopenharmony_ci      if (unlikely (code >= endp)) /* Truncated section.  */
169da0c48c4Sopenharmony_ci	return 1;
170da0c48c4Sopenharmony_ci      if (unlikely (*code == 0x80))
171da0c48c4Sopenharmony_ci	++code;
172da0c48c4Sopenharmony_ci      else
173da0c48c4Sopenharmony_ci	break;
174da0c48c4Sopenharmony_ci    }
175da0c48c4Sopenharmony_ci  if (unlikely (*code == '\0'))
176da0c48c4Sopenharmony_ci    return 1;
177da0c48c4Sopenharmony_ci
178da0c48c4Sopenharmony_ci  /* Clear the entire DIE structure.  This signals we have not yet
179da0c48c4Sopenharmony_ci     determined any of the information.  */
180da0c48c4Sopenharmony_ci  memset (result, '\0', sizeof (Dwarf_Die));
181da0c48c4Sopenharmony_ci
182da0c48c4Sopenharmony_ci  /* We have the address.  */
183da0c48c4Sopenharmony_ci  result->addr = addr;
184da0c48c4Sopenharmony_ci
185da0c48c4Sopenharmony_ci  /* Same CU as the parent.  */
186da0c48c4Sopenharmony_ci  result->cu = cu;
187da0c48c4Sopenharmony_ci
188da0c48c4Sopenharmony_ci  return 0;
189da0c48c4Sopenharmony_ci}
190da0c48c4Sopenharmony_ciINTDEF(dwarf_child)
191