Line data Source code
1 : /* Helper functions to descend DWARF scope trees.
2 : Copyright (C) 2005,2006,2007,2015 Red Hat, Inc.
3 : This file is part of elfutils.
4 :
5 : This file is free software; you can redistribute it and/or modify
6 : it under the terms of either
7 :
8 : * the GNU Lesser General Public License as published by the Free
9 : Software Foundation; either version 3 of the License, or (at
10 : your option) any later version
11 :
12 : or
13 :
14 : * the GNU General Public License as published by the Free
15 : Software Foundation; either version 2 of the License, or (at
16 : your option) any later version
17 :
18 : or both in parallel, as here.
19 :
20 : elfutils is distributed in the hope that it will be useful, but
21 : WITHOUT ANY WARRANTY; without even the implied warranty of
22 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 : General Public License for more details.
24 :
25 : You should have received copies of the GNU General Public License and
26 : the GNU Lesser General Public License along with this program. If
27 : not, see <http://www.gnu.org/licenses/>. */
28 :
29 : #ifdef HAVE_CONFIG_H
30 : # include <config.h>
31 : #endif
32 :
33 : #include "libdwP.h"
34 : #include <dwarf.h>
35 :
36 :
37 : static bool
38 19486782 : may_have_scopes (Dwarf_Die *die)
39 : {
40 19486782 : switch (INTUSE(dwarf_tag) (die))
41 : {
42 : /* DIEs with addresses we can try to match. */
43 : case DW_TAG_compile_unit:
44 : case DW_TAG_module:
45 : case DW_TAG_lexical_block:
46 : case DW_TAG_with_stmt:
47 : case DW_TAG_catch_block:
48 : case DW_TAG_try_block:
49 : case DW_TAG_entry_point:
50 : case DW_TAG_inlined_subroutine:
51 : case DW_TAG_subprogram:
52 : return true;
53 :
54 : /* DIEs without addresses that can own DIEs with addresses. */
55 : case DW_TAG_namespace:
56 : case DW_TAG_class_type:
57 : case DW_TAG_structure_type:
58 : return true;
59 :
60 : /* Other DIEs we have no reason to descend. */
61 : default:
62 : break;
63 : }
64 15279809 : return false;
65 : }
66 :
67 : struct walk_children_state
68 : {
69 : /* Parameters of __libdw_visit_scopes. */
70 : unsigned int depth;
71 : struct Dwarf_Die_Chain *imports;
72 : int (*previsit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
73 : int (*postvisit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
74 : void *arg;
75 : /* Extra local variables for the walker. */
76 : struct Dwarf_Die_Chain child;
77 : };
78 :
79 : static inline int
80 : walk_children (struct walk_children_state *state);
81 :
82 : int
83 : internal_function
84 4112378 : __libdw_visit_scopes (unsigned int depth, struct Dwarf_Die_Chain *root,
85 : struct Dwarf_Die_Chain *imports,
86 : int (*previsit) (unsigned int,
87 : struct Dwarf_Die_Chain *,
88 : void *),
89 : int (*postvisit) (unsigned int,
90 : struct Dwarf_Die_Chain *,
91 : void *),
92 : void *arg)
93 : {
94 4112378 : struct walk_children_state state =
95 : {
96 : .depth = depth,
97 : .imports = imports,
98 : .previsit = previsit,
99 : .postvisit = postvisit,
100 : .arg = arg
101 : };
102 :
103 4112378 : state.child.parent = root;
104 : int ret;
105 4112378 : if ((ret = INTUSE(dwarf_child) (&root->die, &state.child.die)) != 0)
106 582 : return ret < 0 ? -1 : 0; // Having zero children is legal.
107 :
108 4111796 : return walk_children (&state);
109 : }
110 :
111 : static inline int
112 4111812 : walk_children (struct walk_children_state *state)
113 : {
114 : int ret;
115 : do
116 : {
117 : /* For an imported unit, it is logically as if the children of
118 : that unit are siblings of the other children. So don't do
119 : a full recursion into the imported unit, but just walk the
120 : children in place before moving to the next real child. */
121 42063502 : while (INTUSE(dwarf_tag) (&state->child.die) == DW_TAG_imported_unit)
122 : {
123 16 : Dwarf_Die orig_child_die = state->child.die;
124 : Dwarf_Attribute attr_mem;
125 16 : Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&state->child.die,
126 : DW_AT_import,
127 : &attr_mem);
128 16 : if (INTUSE(dwarf_formref_die) (attr, &state->child.die) != NULL
129 16 : && INTUSE(dwarf_child) (&state->child.die, &state->child.die) == 0)
130 : {
131 : /* Checks the given DIE hasn't been imported yet
132 : to prevent cycles. */
133 16 : bool imported = false;
134 32 : for (struct Dwarf_Die_Chain *import = state->imports; import != NULL;
135 0 : import = import->parent)
136 0 : if (import->die.addr == orig_child_die.addr)
137 : {
138 : imported = true;
139 : break;
140 : }
141 16 : if (imported)
142 : {
143 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
144 0 : return -1;
145 : }
146 16 : struct Dwarf_Die_Chain *orig_imports = state->imports;
147 16 : struct Dwarf_Die_Chain import = { .die = orig_child_die,
148 : .parent = orig_imports };
149 16 : state->imports = &import;
150 16 : int result = walk_children (state);
151 16 : state->imports = orig_imports;
152 16 : if (result != DWARF_CB_OK)
153 : return result;
154 : }
155 :
156 : /* Any "real" children left? */
157 12 : if ((ret = INTUSE(dwarf_siblingof) (&orig_child_die,
158 : &state->child.die)) != 0)
159 0 : return ret < 0 ? -1 : 0;
160 : };
161 :
162 21031741 : state->child.prune = false;
163 :
164 : /* previsit is declared NN */
165 21031741 : int result = (*state->previsit) (state->depth + 1, &state->child, state->arg);
166 21031741 : if (result != DWARF_CB_OK)
167 : return result;
168 :
169 21023141 : if (!state->child.prune && may_have_scopes (&state->child.die)
170 4206973 : && INTUSE(dwarf_haschildren) (&state->child.die))
171 : {
172 4095534 : result = __libdw_visit_scopes (state->depth + 1, &state->child, state->imports,
173 : state->previsit, state->postvisit, state->arg);
174 4095534 : if (result != DWARF_CB_OK)
175 : return result;
176 : }
177 :
178 20996327 : if (state->postvisit != NULL)
179 : {
180 1520 : result = (*state->postvisit) (state->depth + 1, &state->child, state->arg);
181 1520 : if (result != DWARF_CB_OK)
182 : return result;
183 : }
184 : }
185 20996224 : while ((ret = INTUSE(dwarf_siblingof) (&state->child.die, &state->child.die)) == 0);
186 :
187 4076291 : return ret < 0 ? -1 : 0;
188 : }
|