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 <[email protected]>, 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 #define INVALID 0xffffe444
39
40
41 unsigned char *
42 internal_function
__libdw_find_attr(Dwarf_Die * die,unsigned int search_name,unsigned int * codep,unsigned int * formp)43 __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
44 unsigned int *codep, unsigned int *formp)
45 {
46 const unsigned char *readp = NULL;
47
48 /* Find the abbreviation entry. */
49 Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, &readp);
50 if (unlikely (abbrevp == DWARF_END_ABBREV))
51 {
52 __libdw_seterrno (DWARF_E_INVALID_DWARF);
53 return NULL;
54 }
55
56 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 const unsigned char *attrp = abbrevp->attrp;
61 while (1)
62 {
63 /* Get attribute name and form. */
64 unsigned int attr_name;
65 get_uleb128_unchecked (attr_name, attrp);
66
67 unsigned int attr_form;
68 get_uleb128_unchecked (attr_form, attrp);
69
70 /* We can stop if we found the attribute with value zero. */
71 if (attr_name == 0 && attr_form == 0)
72 break;
73
74 if (attr_form == DW_FORM_indirect)
75 {
76 if (readp >= endp)
77 goto invalid;
78 get_uleb128 (attr_form, readp, endp);
79 if (attr_form == DW_FORM_indirect ||
80 attr_form == DW_FORM_implicit_const)
81 {
82 invalid:
83 __libdw_seterrno (DWARF_E_INVALID_DWARF);
84 return NULL;
85 }
86 }
87
88 /* Is this the name attribute? */
89 if (attr_name == search_name && search_name != INVALID)
90 {
91 if (codep != NULL)
92 *codep = attr_name;
93 if (formp != NULL)
94 *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 if (attr_form == DW_FORM_implicit_const)
99 return (unsigned char *) attrp;
100 else
101 return (unsigned char *) readp;
102 }
103
104 /* Skip over the rest of this attribute (if there is any). */
105 if (attr_form != 0)
106 {
107 size_t len = __libdw_form_val_len (die->cu, attr_form, readp);
108 if (unlikely (len == (size_t) -1l))
109 {
110 readp = NULL;
111 break;
112 }
113
114 // __libdw_form_val_len will have done a bounds check.
115 readp += len;
116
117 // If the value is in the abbrev data, skip it.
118 if (attr_form == DW_FORM_implicit_const)
119 {
120 int64_t attr_value __attribute__((__unused__));
121 get_sleb128_unchecked (attr_value, attrp);
122 }
123 }
124 }
125
126 // XXX Do we need other values?
127 if (codep != NULL)
128 *codep = INVALID;
129 if (formp != NULL)
130 *formp = INVALID;
131
132 return (unsigned char *) readp;
133 }
134
135
136 int
dwarf_child(Dwarf_Die * die,Dwarf_Die * result)137 dwarf_child (Dwarf_Die *die, Dwarf_Die *result)
138 {
139 /* Ignore previous errors. */
140 if (die == NULL)
141 return -1;
142
143 /* Find the abbreviation entry. */
144 Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL);
145 if (unlikely (abbrevp == DWARF_END_ABBREV))
146 {
147 __libdw_seterrno (DWARF_E_INVALID_DWARF);
148 return -1;
149 }
150
151 /* If there are no children, do not search. */
152 if (! abbrevp->has_children)
153 return 1;
154
155 /* Skip past the last attribute. */
156 void *addr = __libdw_find_attr (die, INVALID, NULL, NULL);
157
158 if (addr == NULL)
159 return -1;
160
161 /* RESULT can be the same as DIE. So preserve what we need. */
162 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 const unsigned char *code = addr;
168 const unsigned char *endp = cu->endp;
169 while (1)
170 {
171 if (unlikely (code >= endp)) /* Truncated section. */
172 return 1;
173 if (unlikely (*code == 0x80))
174 ++code;
175 else
176 break;
177 }
178 if (unlikely (*code == '\0'))
179 return 1;
180
181 /* Clear the entire DIE structure. This signals we have not yet
182 determined any of the information. */
183 memset (result, '\0', sizeof (Dwarf_Die));
184
185 /* We have the address. */
186 result->addr = addr;
187
188 /* Same CU as the parent. */
189 result->cu = cu;
190
191 return 0;
192 }
193 INTDEF(dwarf_child)
194