Branch data 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 : 16432642 : may_have_scopes (Dwarf_Die *die)
39 : : {
40 [ + + ]: 16432642 : 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 : 13417004 : break;
63 : : }
64 : 13417004 : 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 : 2968222 : __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 : 2968222 : struct walk_children_state state =
95 : : {
96 : : .depth = depth,
97 : : .imports = imports,
98 : : .previsit = previsit,
99 : : .postvisit = postvisit,
100 : : .arg = arg
101 : : };
102 : :
103 : 2968222 : state.child.parent = root;
104 : 2968222 : int ret;
105 [ + + ]: 2968222 : if ((ret = INTUSE(dwarf_child) (&root->die, &state.child.die)) != 0)
106 [ + - ]: 4 : return ret < 0 ? -1 : 0; // Having zero children is legal.
107 : :
108 : 2968218 : return walk_children (&state);
109 : : }
110 : :
111 : : static inline int
112 : 2968250 : walk_children (struct walk_children_state *state)
113 : : {
114 : 19206380 : int ret;
115 : 19206380 : 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 [ + + ]: 19206424 : while (INTUSE(dwarf_tag) (&state->child.die) == DW_TAG_imported_unit)
122 : : {
123 : 52 : Dwarf_Die orig_child_die = state->child.die;
124 : 52 : Dwarf_Attribute attr_mem;
125 : 52 : Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&state->child.die,
126 : : DW_AT_import,
127 : : &attr_mem);
128 : : /* Some gcc -flto versions imported other top-level compile units,
129 : : skip those. */
130 [ + - ]: 52 : if (INTUSE(dwarf_formref_die) (attr, &state->child.die) != NULL
131 [ + + ]: 52 : && INTUSE(dwarf_tag) (&state->child.die) != DW_TAG_compile_unit
132 [ + - ]: 32 : && (INTUSE(dwarf_child) (&state->child.die, &state->child.die)
133 : : == 0))
134 : : {
135 : : /* Checks the given DIE hasn't been imported yet
136 : : to prevent cycles. */
137 : 32 : bool imported = false;
138 [ - + ]: 32 : for (struct Dwarf_Die_Chain *import = state->imports; import != NULL;
139 : 0 : import = import->parent)
140 [ # # ]: 0 : if (import->die.addr == orig_child_die.addr)
141 : : {
142 : : imported = true;
143 : : break;
144 : : }
145 [ - + ]: 32 : if (imported)
146 : : {
147 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
148 : 8 : return -1;
149 : : }
150 : 32 : struct Dwarf_Die_Chain *orig_imports = state->imports;
151 : 32 : struct Dwarf_Die_Chain import = { .die = orig_child_die,
152 : : .parent = orig_imports };
153 : 32 : state->imports = &import;
154 : 32 : int result = walk_children (state);
155 : 32 : state->imports = orig_imports;
156 [ + + ]: 32 : if (result != DWARF_CB_OK)
157 : 8 : return result;
158 : : }
159 : :
160 : : /* Any "real" children left? */
161 [ - + ]: 44 : if ((ret = INTUSE(dwarf_siblingof) (&orig_child_die,
162 : : &state->child.die)) != 0)
163 [ # # ]: 0 : return ret < 0 ? -1 : 0;
164 : 19206372 : };
165 : :
166 : 19206372 : state->child.prune = false;
167 : :
168 : : /* previsit is declared NN */
169 : 19206372 : int result = (*state->previsit) (state->depth + 1, &state->child, state->arg);
170 [ + + ]: 19206372 : if (result != DWARF_CB_OK)
171 : 15794 : return result;
172 : :
173 [ + + + + ]: 19190578 : if (!state->child.prune && may_have_scopes (&state->child.die)
174 [ + + ]: 3015638 : && INTUSE(dwarf_haschildren) (&state->child.die))
175 : : {
176 : 2931986 : result = __libdw_visit_scopes (state->depth + 1, &state->child, state->imports,
177 : : state->previsit, state->postvisit, state->arg);
178 [ + + ]: 2931986 : if (result != DWARF_CB_OK)
179 : 42426 : return result;
180 : : }
181 : :
182 [ + + ]: 19148152 : if (state->postvisit != NULL)
183 : : {
184 : 3870 : result = (*state->postvisit) (state->depth + 1, &state->child, state->arg);
185 [ + + ]: 3870 : if (result != DWARF_CB_OK)
186 : 504 : return result;
187 : : }
188 : : }
189 [ + + ]: 19147648 : while ((ret = INTUSE(dwarf_siblingof) (&state->child.die, &state->child.die)) == 0);
190 : :
191 [ + - ]: 2909518 : return ret < 0 ? -1 : 0;
192 : : }
|