blob: 21d6f20a6322454f17b7d86e68b98262802f9a20 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Return scope DIEs containing PC address.
2 Copyright (C) 2005 Red Hat, Inc.
3
4 This program is Open Source software; you can redistribute it and/or
5 modify it under the terms of the Open Software License version 1.0 as
6 published by the Open Source Initiative.
7
8 You should have received a copy of the Open Software License along
9 with this program; if not, you may obtain a copy of the Open Software
10 License version 1.0 from http://www.opensource.org/licenses/osl.php or
11 by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
12 3001 King Ranch Road, Ukiah, CA 95482. */
13
14#ifdef HAVE_CONFIG_H
15# include <config.h>
16#endif
17
18#include <stdlib.h>
19#include "libdwP.h"
20#include <dwarf.h>
21
22
23enum die_class { ignore, match, match_inline, walk, imported };
24
25static enum die_class
26classify_die (Dwarf_Die *die)
27{
28 switch (INTUSE(dwarf_tag) (die))
29 {
30 /* DIEs with addresses we can try to match. */
31 case DW_TAG_compile_unit:
32 case DW_TAG_module:
33 case DW_TAG_lexical_block:
34 case DW_TAG_with_stmt:
35 case DW_TAG_catch_block:
36 case DW_TAG_try_block:
37 case DW_TAG_entry_point:
38 return match;
39 case DW_TAG_inlined_subroutine:
40 return match_inline;
41 case DW_TAG_subprogram:
42 /* This might be a concrete out-of-line instance of an inline, in
43 which case it is not guaranteed to be owned by the right scope and
44 we will search for its origin as for DW_TAG_inlined_subroutine. */
45 return (INTUSE(dwarf_hasattr) (die, DW_AT_abstract_origin)
46 ? match_inline : match);
47
48 /* DIEs without addresses that can own DIEs with addresses. */
49 case DW_TAG_namespace:
50 return walk;
51
52 /* Special indirection required. */
53 case DW_TAG_imported_unit:
54 return imported;
55
56 /* Other DIEs we have no reason to descend. */
57 default:
58 break;
59 }
60 return ignore;
61}
62
63/* DIE contains PC. Find its child that contains PC. Returns -1 for
64 errors, 0 for no matches. On success, *SCOPES gets the malloc'd array
65 of containing scopes. A positive return value is the number of those
66 scopes. A return value < -1 is -1 - number of those scopes, when the
67 outermost scope is a concrete instance of an inline subroutine. */
68static int
69find_pc (unsigned int depth, Dwarf_Die *die, Dwarf_Addr pc, Dwarf_Die **scopes)
70{
71 Dwarf_Die child;
72 if (INTUSE(dwarf_child) (die, &child) != 0)
73 return -1;
74
75 /* Recurse on this DIE to search within its children.
76 Return nonzero if this gets an error or a final result. */
77 inline int search_child (void)
78 {
79 int n = find_pc (depth + 1, &child, pc, scopes);
80 if (n > 0)
81 /* That stored the N innermost scopes. Now store ours. */
82 (*scopes)[n++] = child;
83 return n;
84 }
85
86 /* Check each of our child DIEs. */
87 enum die_class got = ignore;
88 do
89 {
90 enum die_class child_class = classify_die (&child);
91 switch (child_class)
92 {
93 case match:
94 case match_inline:
95 if (INTUSE(dwarf_haspc) (&child, pc) > 0)
96 break;
97 continue;
98
99 case walk:
100 if (INTUSE(dwarf_haschildren) (&child))
101 got = walk;
102 continue;
103
104 case imported:
105 got = walk;
106 continue;
107
108 default:
109 case ignore:
110 continue;
111 }
112
113 /* We get here only when the PC has matched. */
114 got = child_class;
115 break;
116 }
117 while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
118
119 switch (got)
120 {
121 case match:
122 case match_inline:
123 /* We have a DIE that matched the PC. */
124 if (INTUSE(dwarf_haschildren) (&child))
125 {
126 /* Recurse on this DIE to narrow within its children.
127 Return now if this gets an error or a final result. */
128 int result = search_child ();
129 if (result < 0 || (got == match && result > 0))
130 return result;
131 if (result > 0) /* got == match_inline */
132 /* We have a winner, but CHILD is a concrete inline instance
133 so DIE and its containing scopes do not actually apply.
134 DIE is the scope that inlined the function. Our root
135 caller must find the abstract scope that defines us. */
136 return -1 - result;
137 }
138
139 /* This DIE has no children containing the PC, so this is it. */
140 *scopes = malloc (depth * sizeof (*scopes)[0]);
141 if (*scopes == NULL)
142 {
143 __libdw_seterrno (DWARF_E_NOMEM);
144 return -1;
145 }
146 (*scopes)[0] = child;
147 return got == match ? 1 : -2;
148
149 case walk:
150 /* We don't have anything matching the PC, but we have some things
151 we might descend to find one. Recurse on each of those. */
152 if (INTUSE(dwarf_child) (die, &child) != 0)
153 return -1;
154 do
155 switch (classify_die (&child))
156 {
157 case walk:
158 if (INTUSE(dwarf_haschildren) (&child))
159 {
160 /* Recurse on this DIE to look for the PC within its children.
161 Return now if this gets an error or a final result. */
162 int result = search_child ();
163 if (result != 0)
164 return result;
165 }
166 break;
167
168 case imported:
169 {
170 /* This imports another compilation unit to appear
171 as part of this one, inside the current scope.
172 Recurse to search the referenced unit, but without
173 recording it as an inner scoping level. */
174
175 Dwarf_Attribute attr_mem;
176 Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child, DW_AT_import,
177 &attr_mem);
178 if (INTUSE(dwarf_formref_die) (attr, &child) != NULL)
179 {
180 int result = find_pc (depth, &child, pc, scopes);
181 if (result != 0)
182 return result;
183 }
184 }
185 break;
186
187 default:
188 break;
189 }
190 while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
191 break;
192
193 default:
194 case ignore:
195 /* Nothing to see here. */
196 break;
197 }
198
199 /* No matches. */
200 return 0;
201}
202
203
204/* OWNER owns OWNED. Find intermediate scopes. *SCOPES was allocated by
205 find_pc and has SKIP elements. We realloc it, append more containing
206 scopes, and return 1 + the number appended. Returns -1 on errors,
207 or 0 when OWNED was not found within OWNER. */
208static int
209find_die (unsigned int depth, Dwarf_Die *owner, Dwarf_Die *owned,
210 Dwarf_Die **scopes, unsigned int skip)
211{
212 Dwarf_Die child;
213 if (INTUSE(dwarf_child) (owner, &child) != 0)
214 return -1;
215
216 do
217 {
218 if (child.addr == owned->addr)
219 /* This is the one. OWNER is the innermost owner. */
220 return 1;
221
222 /* Unfortunately we cannot short-circuit the dead-end paths just by
223 checking the physical layout to see if OWNED falls within CHILD.
224 If it doesn't, there may still be a DW_TAG_imported_unit that
225 refers to its true owner indirectly. */
226
227 switch (classify_die (&child))
228 {
229 case match:
230 case match_inline:
231 case walk:
232 if (INTUSE(dwarf_haschildren) (&child))
233 {
234 /* Recurse on this DIE to look for OWNED within its children.
235 Return now if this gets an error or a final result. */
236 int n = find_die (depth + 1, &child, owned, scopes, skip);
237 if (n < 0)
238 return n;
239 if (n > 1)
240 {
241 /* We have a winner. CHILD owns the owner of OWNED. */
242 (*scopes)[skip + n - 1] = child;
243 return n + 1;
244 }
245 if (n > 0) /* n == 1 */
246 {
247 /* CHILD is the direct owner of OWNED. */
248 Dwarf_Die *nscopes = realloc (*scopes,
249 (skip + depth)
250 * sizeof nscopes[0]);
251 if (nscopes == NULL)
252 {
253 free (*scopes);
254 *scopes = NULL;
255 __libdw_seterrno (DWARF_E_NOMEM);
256 return -1;
257 }
258 nscopes[skip] = child;
259 *scopes = nscopes;
260 return 2;
261 }
262 }
263 break;
264
265 case imported:
266 {
267 /* This is imports another compilation unit to appear
268 as part of this one, inside the current scope.
269 Recurse to search the referenced unit, but without
270 recording it as an inner scoping level. */
271
272 Dwarf_Attribute attr_mem;
273 Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child, DW_AT_import,
274 &attr_mem);
275 if (INTUSE(dwarf_formref_die) (attr, &child) != NULL)
276 {
277 int result = find_die (depth, &child, owner, scopes, skip);
278 if (result != 0)
279 return result;
280 }
281 }
282 break;
283
284 default:
285 break;
286 }
287 }
288 while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
289
290 return 0;
291}
292
293
294int
295dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes)
296{
297 if (cudie == NULL)
298 return -1;
299
300 int n = find_pc (1, cudie, pc, scopes);
301 if (likely (n >= -1))
302 /* We have an error or a final result. */
303 return n;
304
305 /* We have the scopes out to one that is a concrete instance of an
306 inlined subroutine (usually DW_TAG_inlined_subroutine, but can
307 be DW_TAG_subprogram for a concrete out-of-line instance).
308 Now we must find the lexical scopes that contain the
309 corresponding abstract inline subroutine definition. */
310
311 n = -n - 1;
312
313 Dwarf_Attribute attr_mem;
314 Dwarf_Die die_mem;
315 Dwarf_Die *origin = INTUSE(dwarf_formref_die)
316 (INTUSE(dwarf_attr) (&(*scopes)[n - 1], DW_AT_abstract_origin, &attr_mem),
317 &die_mem);
318 if (unlikely (origin == NULL))
319 goto invalid;
320
321 int result = find_die (0, cudie, origin, scopes, n);
322 if (likely (result > 0))
323 return n + result - 1;
324
325 if (result == 0) /* No match, shouldn't happen. */
326 {
327 invalid:
328 __libdw_seterrno (DWARF_E_INVALID_DWARF);
329 }
330
331 free (*scopes);
332 *scopes = NULL;
333 return -1;
334}