ea0c6b473eb5abb293ed1d849ff5c499054aa8dd
[platform/upstream/elfutils.git] / libdw / libdw_visit_scopes.c
1 /* Helper functions to descend DWARF scope trees.
2    Copyright (C) 2005,2006,2007 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 enum die_class { ignore, match, match_inline, walk, imported };
37
38 static enum die_class
39 classify_die (Dwarf_Die *die)
40 {
41   switch (INTUSE(dwarf_tag) (die))
42     {
43       /* DIEs with addresses we can try to match.  */
44     case DW_TAG_compile_unit:
45     case DW_TAG_module:
46     case DW_TAG_lexical_block:
47     case DW_TAG_with_stmt:
48     case DW_TAG_catch_block:
49     case DW_TAG_try_block:
50     case DW_TAG_entry_point:
51       return match;
52     case DW_TAG_inlined_subroutine:
53       return match_inline;
54     case DW_TAG_subprogram:
55       /* This might be a concrete out-of-line instance of an inline, in
56          which case it is not guaranteed to be owned by the right scope and
57          we will search for its origin as for DW_TAG_inlined_subroutine.  */
58       return (INTUSE(dwarf_hasattr) (die, DW_AT_abstract_origin)
59               ? match_inline : match);
60
61       /* DIEs without addresses that can own DIEs with addresses.  */
62     case DW_TAG_namespace:
63     case DW_TAG_class_type:
64     case DW_TAG_structure_type:
65       return walk;
66
67       /* Special indirection required.  */
68     case DW_TAG_imported_unit:
69       return imported;
70
71       /* Other DIEs we have no reason to descend.  */
72     default:
73       break;
74     }
75   return ignore;
76 }
77
78 int
79 __libdw_visit_scopes (depth, root, previsit, postvisit, arg)
80      unsigned int depth;
81      struct Dwarf_Die_Chain *root;
82      int (*previsit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
83      int (*postvisit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
84      void *arg;
85 {
86   struct Dwarf_Die_Chain child;
87
88   child.parent = root;
89   if (INTUSE(dwarf_child) (&root->die, &child.die) != 0)
90     return -1;
91
92   inline int recurse (void)
93     {
94       return __libdw_visit_scopes (depth + 1, &child,
95                                    previsit, postvisit, arg);
96     }
97
98   do
99     {
100       child.prune = false;
101
102       if (previsit != NULL)
103         {
104           int result = (*previsit) (depth + 1, &child, arg);
105           if (result != DWARF_CB_OK)
106             return result;
107         }
108
109       if (!child.prune)
110         switch (classify_die (&child.die))
111           {
112           case match:
113           case match_inline:
114           case walk:
115             if (INTUSE(dwarf_haschildren) (&child.die))
116               {
117                 int result = recurse ();
118                 if (result != DWARF_CB_OK)
119                   return result;
120               }
121             break;
122
123           case imported:
124             {
125               /* This imports another compilation unit to appear
126                  as part of this one, inside the current scope.
127                  Recurse to search the referenced unit, but without
128                  recording it as an inner scoping level.  */
129
130               Dwarf_Attribute attr_mem;
131               Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child.die,
132                                                           DW_AT_import,
133                                                           &attr_mem);
134               if (INTUSE(dwarf_formref_die) (attr, &child.die) != NULL)
135                 {
136                   int result = recurse ();
137                   if (result != DWARF_CB_OK)
138                     return result;
139                 }
140             }
141             break;
142
143           default:
144             break;
145           }
146
147       if (postvisit != NULL)
148         {
149           int result = (*postvisit) (depth + 1, &child, arg);
150           if (result != DWARF_CB_OK)
151             return result;
152         }
153     }
154   while (INTUSE(dwarf_siblingof) (&child.die, &child.die) == 0);
155
156   return 0;
157 }