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 #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 get_uleb128 (attr_form, readp, endp);
77 if (attr_form == DW_FORM_indirect ||
78 attr_form == DW_FORM_implicit_const)
79 {
80 __libdw_seterrno (DWARF_E_INVALID_DWARF);
81 return NULL;
82 }
83 }
84
85 /* Is this the name attribute? */
86 if (attr_name == search_name && search_name != INVALID)
87 {
88 if (codep != NULL)
89 *codep = attr_name;
90 if (formp != NULL)
91 *formp = attr_form;
92
93 /* Normally the attribute data comes from the DIE/info,
94 except for implicit_form, where it comes from the abbrev. */
95 if (attr_form == DW_FORM_implicit_const)
96 return (unsigned char *) attrp;
97 else
98 return (unsigned char *) readp;
99 }
100
101 /* Skip over the rest of this attribute (if there is any). */
102 if (attr_form != 0)
103 {
104 size_t len = __libdw_form_val_len (die->cu, attr_form, readp);
105 if (unlikely (len == (size_t) -1l))
106 {
107 readp = NULL;
108 break;
109 }
110
111 // __libdw_form_val_len will have done a bounds check.
112 readp += len;
113
114 // If the value is in the abbrev data, skip it.
115 if (attr_form == DW_FORM_implicit_const)
116 {
117 int64_t attr_value __attribute__((__unused__));
118 get_sleb128_unchecked (attr_value, attrp);
119 }
120 }
121 }
122
123 // XXX Do we need other values?
124 if (codep != NULL)
125 *codep = INVALID;
126 if (formp != NULL)
127 *formp = INVALID;
128
129 return (unsigned char *) readp;
130 }
131
132
133 int
dwarf_child(Dwarf_Die * die,Dwarf_Die * result)134 dwarf_child (Dwarf_Die *die, Dwarf_Die *result)
135 {
136 /* Ignore previous errors. */
137 if (die == NULL)
138 return -1;
139
140 /* Find the abbreviation entry. */
141 Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL);
142 if (unlikely (abbrevp == DWARF_END_ABBREV))
143 {
144 __libdw_seterrno (DWARF_E_INVALID_DWARF);
145 return -1;
146 }
147
148 /* If there are no children, do not search. */
149 if (! abbrevp->has_children)
150 return 1;
151
152 /* Skip past the last attribute. */
153 void *addr = __libdw_find_attr (die, INVALID, NULL, NULL);
154
155 if (addr == NULL)
156 return -1;
157
158 /* RESULT can be the same as DIE. So preserve what we need. */
159 struct Dwarf_CU *cu = die->cu;
160
161 /* It's kosher (just suboptimal) to have a null entry first thing (7.5.3).
162 So if this starts with ULEB128 of 0 (even with silly encoding of 0),
163 it is a kosher null entry and we do not really have any children. */
164 const unsigned char *code = addr;
165 const unsigned char *endp = cu->endp;
166 while (1)
167 {
168 if (unlikely (code >= endp)) /* Truncated section. */
169 return 1;
170 if (unlikely (*code == 0x80))
171 ++code;
172 else
173 break;
174 }
175 if (unlikely (*code == '\0'))
176 return 1;
177
178 /* Clear the entire DIE structure. This signals we have not yet
179 determined any of the information. */
180 memset (result, '\0', sizeof (Dwarf_Die));
181
182 /* We have the address. */
183 result->addr = addr;
184
185 /* Same CU as the parent. */
186 result->cu = cu;
187
188 return 0;
189 }
190 INTDEF(dwarf_child)
191