Coverage Report

Created: 2025-08-24 06:28

/src/elfutils/libdw/dwarf_child.c
Line
Count
Source (jump to first uncovered line)
1
/* Return child of current DIE.
2
   Copyright (C) 2003-2011, 2014, 2017 Red Hat, Inc.
3
   This file is part of elfutils.
4
   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
5
6
   This file is free software; you can redistribute it and/or modify
7
   it under the terms of either
8
9
     * the GNU Lesser General Public License as published by the Free
10
       Software Foundation; either version 3 of the License, or (at
11
       your option) any later version
12
13
   or
14
15
     * the GNU General Public License as published by the Free
16
       Software Foundation; either version 2 of the License, or (at
17
       your option) any later version
18
19
   or both in parallel, as here.
20
21
   elfutils is distributed in the hope that it will be useful, but
22
   WITHOUT ANY WARRANTY; without even the implied warranty of
23
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24
   General Public License for more details.
25
26
   You should have received copies of the GNU General Public License and
27
   the GNU Lesser General Public License along with this program.  If
28
   not, see <http://www.gnu.org/licenses/>.  */
29
30
#ifdef HAVE_CONFIG_H
31
# include <config.h>
32
#endif
33
34
#include "libdwP.h"
35
#include <string.h>
36
37
/* Some arbitrary value not conflicting with any existing code.  */
38
0
#define INVALID 0xffffe444
39
40
41
unsigned char *
42
internal_function
43
__libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
44
       unsigned int *codep, unsigned int *formp)
45
0
{
46
0
  const unsigned char *readp = NULL;
47
48
  /* Find the abbreviation entry.  */
49
0
  Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, &readp);
50
0
  if (unlikely (abbrevp == DWARF_END_ABBREV))
51
0
    {
52
0
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
53
0
      return NULL;
54
0
    }
55
56
0
  const unsigned char *endp = die->cu->endp;
57
58
  /* Search the name attribute.  Attribute has been checked when
59
     Dwarf_Abbrev was created, we can read unchecked.  */
60
0
  const unsigned char *attrp = abbrevp->attrp;
61
0
  while (1)
62
0
    {
63
      /* Get attribute name and form.  */
64
0
      unsigned int attr_name;
65
0
      get_uleb128_unchecked (attr_name, attrp);
66
67
0
      unsigned int attr_form;
68
0
      get_uleb128_unchecked (attr_form, attrp);
69
70
      /* We can stop if we found the attribute with value zero.  */
71
0
      if (attr_name == 0 && attr_form == 0)
72
0
  break;
73
74
0
      if (attr_form == DW_FORM_indirect)
75
0
  {
76
0
    if (readp >= endp)
77
0
      goto invalid;
78
0
    get_uleb128 (attr_form, readp, endp);
79
0
    if (attr_form == DW_FORM_indirect ||
80
0
        attr_form == DW_FORM_implicit_const)
81
0
      {
82
0
      invalid:
83
0
        __libdw_seterrno (DWARF_E_INVALID_DWARF);
84
0
        return NULL;
85
0
      }
86
0
  }
87
88
      /* Is this the name attribute?  */
89
0
      if (attr_name == search_name && search_name != INVALID)
90
0
  {
91
0
    if (codep != NULL)
92
0
      *codep = attr_name;
93
0
    if (formp != NULL)
94
0
      *formp = attr_form;
95
96
    /* Normally the attribute data comes from the DIE/info,
97
       except for implicit_form, where it comes from the abbrev.  */
98
0
    if (attr_form == DW_FORM_implicit_const)
99
0
      return (unsigned char *) attrp;
100
0
    else
101
0
      return (unsigned char *) readp;
102
0
  }
103
104
      /* Skip over the rest of this attribute (if there is any).  */
105
0
      if (attr_form != 0)
106
0
  {
107
0
    size_t len = __libdw_form_val_len (die->cu, attr_form, readp);
108
0
    if (unlikely (len == (size_t) -1l))
109
0
      {
110
0
        readp = NULL;
111
0
        break;
112
0
      }
113
114
    // __libdw_form_val_len will have done a bounds check.
115
0
    readp += len;
116
117
    // If the value is in the abbrev data, skip it.
118
0
    if (attr_form == DW_FORM_implicit_const)
119
0
      {
120
0
        int64_t attr_value __attribute__((__unused__));
121
0
        get_sleb128_unchecked (attr_value, attrp);
122
0
      }
123
0
  }
124
0
    }
125
126
  // XXX Do we need other values?
127
0
  if (codep != NULL)
128
0
    *codep = INVALID;
129
0
  if (formp != NULL)
130
0
    *formp = INVALID;
131
132
0
  return (unsigned char *) readp;
133
0
}
134
135
136
int
137
dwarf_child (Dwarf_Die *die, Dwarf_Die *result)
138
0
{
139
  /* Ignore previous errors.  */
140
0
  if (die == NULL)
141
0
    return -1;
142
143
  /* Find the abbreviation entry.  */
144
0
  Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL);
145
0
  if (unlikely (abbrevp == DWARF_END_ABBREV))
146
0
    {
147
0
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
148
0
      return -1;
149
0
    }
150
151
  /* If there are no children, do not search.  */
152
0
  if (! abbrevp->has_children)
153
0
    return 1;
154
155
  /* Skip past the last attribute.  */
156
0
  void *addr = __libdw_find_attr (die, INVALID, NULL, NULL);
157
158
0
  if (addr == NULL)
159
0
    return -1;
160
161
  /* RESULT can be the same as DIE.  So preserve what we need.  */
162
0
  struct Dwarf_CU *cu = die->cu;
163
164
  /* It's kosher (just suboptimal) to have a null entry first thing (7.5.3).
165
     So if this starts with ULEB128 of 0 (even with silly encoding of 0),
166
     it is a kosher null entry and we do not really have any children.  */
167
0
  const unsigned char *code = addr;
168
0
  const unsigned char *endp = cu->endp;
169
0
  while (1)
170
0
    {
171
0
      if (unlikely (code >= endp)) /* Truncated section.  */
172
0
  return 1;
173
0
      if (unlikely (*code == 0x80))
174
0
  ++code;
175
0
      else
176
0
  break;
177
0
    }
178
0
  if (unlikely (*code == '\0'))
179
0
    return 1;
180
181
  /* Clear the entire DIE structure.  This signals we have not yet
182
     determined any of the information.  */
183
0
  memset (result, '\0', sizeof (Dwarf_Die));
184
185
  /* We have the address.  */
186
0
  result->addr = addr;
187
188
  /* Same CU as the parent.  */
189
0
  result->cu = cu;
190
191
0
  return 0;
192
0
}
193
INTDEF(dwarf_child)