1 /* Return scope DIEs containing PC address.
2 Copyright (C) 2005, 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 <assert.h>
34 #include <stdlib.h>
35 #include "libdwP.h"
36 #include <dwarf.h>
37
38
39 struct args
40 {
41 Dwarf_Addr pc;
42 Dwarf_Die *scopes;
43 unsigned int inlined, nscopes;
44 Dwarf_Die inlined_origin;
45 };
46
47 /* Preorder visitor: prune the traversal if this DIE does not contain PC. */
48 static int
pc_match(unsigned int depth,struct Dwarf_Die_Chain * die,void * arg)49 pc_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
50 {
51 struct args *a = arg;
52
53 if (a->scopes != NULL)
54 die->prune = true;
55 else
56 {
57 /* dwarf_haspc returns an error if there are no appropriate attributes.
58 But we use it indiscriminantly instead of presuming which tags can
59 have PC attributes. So when it fails for that reason, treat it just
60 as a nonmatching return. */
61 int result = INTUSE(dwarf_haspc) (&die->die, a->pc);
62 if (result < 0)
63 {
64 int error = INTUSE(dwarf_errno) ();
65 if (error != DWARF_E_NOERROR
66 && error != DWARF_E_NO_DEBUG_RANGES
67 && error != DWARF_E_NO_DEBUG_RNGLISTS)
68 {
69 __libdw_seterrno (error);
70 return -1;
71 }
72 result = 0;
73 }
74 if (result == 0)
75 die->prune = true;
76
77 if (!die->prune
78 && INTUSE (dwarf_tag) (&die->die) == DW_TAG_inlined_subroutine)
79 a->inlined = depth;
80 }
81
82 return 0;
83 }
84
85 /* Preorder visitor for second partial traversal after finding a
86 concrete inlined instance. */
87 static int
origin_match(unsigned int depth,struct Dwarf_Die_Chain * die,void * arg)88 origin_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
89 {
90 struct args *a = arg;
91
92 if (die->die.addr != a->inlined_origin.addr)
93 return 0;
94
95 /* We have a winner! This is the abstract definition of the inline
96 function of which A->scopes[A->nscopes - 1] is a concrete instance.
97 */
98
99 unsigned int nscopes = a->nscopes + depth;
100 Dwarf_Die *scopes = realloc (a->scopes, nscopes * sizeof scopes[0]);
101 if (scopes == NULL)
102 {
103 free (a->scopes);
104 __libdw_seterrno (DWARF_E_NOMEM);
105 return -1;
106 }
107
108 a->scopes = scopes;
109 do
110 {
111 die = die->parent;
112 scopes[a->nscopes++] = die->die;
113 }
114 while (a->nscopes < nscopes);
115 assert (die->parent == NULL);
116 return a->nscopes;
117 }
118
119 /* Postorder visitor: first (innermost) call wins. */
120 static int
pc_record(unsigned int depth,struct Dwarf_Die_Chain * die,void * arg)121 pc_record (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
122 {
123 struct args *a = arg;
124
125 if (die->prune)
126 return 0;
127
128 if (a->scopes == NULL)
129 {
130 /* We have hit the innermost DIE that contains the target PC. */
131
132 a->nscopes = depth + 1 - a->inlined;
133 a->scopes = malloc (a->nscopes * sizeof a->scopes[0]);
134 if (a->scopes == NULL)
135 {
136 __libdw_seterrno (DWARF_E_NOMEM);
137 return -1;
138 }
139
140 for (unsigned int i = 0; i < a->nscopes; ++i)
141 {
142 a->scopes[i] = die->die;
143 die = die->parent;
144 }
145
146 if (a->inlined == 0)
147 {
148 assert (die == NULL);
149 return a->nscopes;
150 }
151
152 /* This is the concrete inlined instance itself.
153 Record its abstract_origin pointer. */
154 Dwarf_Die *const inlinedie = &a->scopes[depth - a->inlined];
155
156 assert (INTUSE (dwarf_tag) (inlinedie) == DW_TAG_inlined_subroutine);
157 Dwarf_Attribute attr_mem;
158 Dwarf_Attribute *attr = INTUSE (dwarf_attr) (inlinedie,
159 DW_AT_abstract_origin,
160 &attr_mem);
161 if (INTUSE (dwarf_formref_die) (attr, &a->inlined_origin) == NULL)
162 return -1;
163 return 0;
164 }
165
166
167 /* We've recorded the scopes back to one that is a concrete inlined
168 instance. Now return out of the traversal back to the scope
169 containing that instance. */
170
171 assert (a->inlined);
172 if (depth >= a->inlined)
173 /* Not there yet. */
174 return 0;
175
176 /* Now we are in a scope that contains the concrete inlined instance.
177 Search it for the inline function's abstract definition.
178 If we don't find it, return to search the containing scope.
179 If we do find it, the nonzero return value will bail us out
180 of the postorder traversal. */
181 return __libdw_visit_scopes (depth, die, NULL, &origin_match, NULL, a);
182 }
183
184
185 int
dwarf_getscopes(Dwarf_Die * cudie,Dwarf_Addr pc,Dwarf_Die ** scopes)186 dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes)
187 {
188 if (cudie == NULL)
189 return -1;
190
191 struct Dwarf_Die_Chain cu = { .parent = NULL, .die = *cudie };
192 struct args a = { .pc = pc };
193
194 int result = __libdw_visit_scopes (0, &cu, NULL, &pc_match, &pc_record, &a);
195
196 if (result == 0 && a.scopes != NULL)
197 result = __libdw_visit_scopes (0, &cu, NULL, &origin_match, NULL, &a);
198
199 if (result > 0)
200 *scopes = a.scopes;
201
202 return result;
203 }
204