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 && error != DWARF_E_NO_DEBUG_RANGES)
66 {
67 __libdw_seterrno (error);
68 return -1;
69 }
70 result = 0;
71 }
72 if (result == 0)
73 die->prune = true;
74
75 if (!die->prune
76 && INTUSE (dwarf_tag) (&die->die) == DW_TAG_inlined_subroutine)
77 a->inlined = depth;
78 }
79
80 return 0;
81 }
82
83 /* Preorder visitor for second partial traversal after finding a
84 concrete inlined instance. */
85 static int
origin_match(unsigned int depth,struct Dwarf_Die_Chain * die,void * arg)86 origin_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
87 {
88 struct args *a = arg;
89
90 if (die->die.addr != a->inlined_origin.addr)
91 return 0;
92
93 /* We have a winner! This is the abstract definition of the inline
94 function of which A->scopes[A->nscopes - 1] is a concrete instance.
95 */
96
97 unsigned int nscopes = a->nscopes + depth;
98 Dwarf_Die *scopes = realloc (a->scopes, nscopes * sizeof scopes[0]);
99 if (scopes == NULL)
100 {
101 free (a->scopes);
102 __libdw_seterrno (DWARF_E_NOMEM);
103 return -1;
104 }
105
106 a->scopes = scopes;
107 do
108 {
109 die = die->parent;
110 scopes[a->nscopes++] = die->die;
111 }
112 while (a->nscopes < nscopes);
113 assert (die->parent == NULL);
114 return a->nscopes;
115 }
116
117 /* Postorder visitor: first (innermost) call wins. */
118 static int
pc_record(unsigned int depth,struct Dwarf_Die_Chain * die,void * arg)119 pc_record (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
120 {
121 struct args *a = arg;
122
123 if (die->prune)
124 return 0;
125
126 if (a->scopes == NULL)
127 {
128 /* We have hit the innermost DIE that contains the target PC. */
129
130 a->nscopes = depth + 1 - a->inlined;
131 a->scopes = malloc (a->nscopes * sizeof a->scopes[0]);
132 if (a->scopes == NULL)
133 {
134 __libdw_seterrno (DWARF_E_NOMEM);
135 return -1;
136 }
137
138 for (unsigned int i = 0; i < a->nscopes; ++i)
139 {
140 a->scopes[i] = die->die;
141 die = die->parent;
142 }
143
144 if (a->inlined == 0)
145 {
146 assert (die == NULL);
147 return a->nscopes;
148 }
149
150 /* This is the concrete inlined instance itself.
151 Record its abstract_origin pointer. */
152 Dwarf_Die *const inlinedie = &a->scopes[depth - a->inlined];
153
154 assert (INTUSE (dwarf_tag) (inlinedie) == DW_TAG_inlined_subroutine);
155 Dwarf_Attribute attr_mem;
156 Dwarf_Attribute *attr = INTUSE (dwarf_attr) (inlinedie,
157 DW_AT_abstract_origin,
158 &attr_mem);
159 if (INTUSE (dwarf_formref_die) (attr, &a->inlined_origin) == NULL)
160 return -1;
161 return 0;
162 }
163
164
165 /* We've recorded the scopes back to one that is a concrete inlined
166 instance. Now return out of the traversal back to the scope
167 containing that instance. */
168
169 assert (a->inlined);
170 if (depth >= a->inlined)
171 /* Not there yet. */
172 return 0;
173
174 /* Now we are in a scope that contains the concrete inlined instance.
175 Search it for the inline function's abstract definition.
176 If we don't find it, return to search the containing scope.
177 If we do find it, the nonzero return value will bail us out
178 of the postorder traversal. */
179 return __libdw_visit_scopes (depth, die, NULL, &origin_match, NULL, a);
180 }
181
182
183 int
dwarf_getscopes(Dwarf_Die * cudie,Dwarf_Addr pc,Dwarf_Die ** scopes)184 dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes)
185 {
186 if (cudie == NULL)
187 return -1;
188
189 struct Dwarf_Die_Chain cu = { .parent = NULL, .die = *cudie };
190 struct args a = { .pc = pc };
191
192 int result = __libdw_visit_scopes (0, &cu, NULL, &pc_match, &pc_record, &a);
193
194 if (result == 0 && a.scopes != NULL)
195 result = __libdw_visit_scopes (0, &cu, NULL, &origin_match, NULL, &a);
196
197 if (result > 0)
198 *scopes = a.scopes;
199
200 return result;
201 }
202