blob: 0ca6da0b409017965c1605edd6bc537fbe8ef3ae [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Return scope DIEs containing PC address.
Roland McGrathd1a48172007-08-07 19:51:01 +00002 Copyright (C) 2005, 2007 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004
Mark Wielaardde2ed972012-06-05 17:15:16 +02005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00007
Mark Wielaardde2ed972012-06-05 17:15:16 +02008 * 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
Ulrich Drepper361df7d2006-04-04 21:38:57 +000021 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
Mark Wielaardde2ed972012-06-05 17:15:16 +020025 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/>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000028
29#ifdef HAVE_CONFIG_H
30# include <config.h>
31#endif
32
Roland McGrath71e15a02005-08-27 10:33:26 +000033#include <assert.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000034#include <stdlib.h>
35#include "libdwP.h"
36#include <dwarf.h>
37
38
Roland McGrath71e15a02005-08-27 10:33:26 +000039struct args
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000040{
Roland McGrath71e15a02005-08-27 10:33:26 +000041 Dwarf_Addr pc;
42 Dwarf_Die *scopes;
43 unsigned int inlined, nscopes;
44 Dwarf_Die inlined_origin;
45};
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000046
Roland McGrath71e15a02005-08-27 10:33:26 +000047/* Preorder visitor: prune the traversal if this DIE does not contain PC. */
48static int
49pc_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
50{
51 struct args *a = arg;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000052
Roland McGrathd1a48172007-08-07 19:51:01 +000053 if (a->scopes != NULL)
Roland McGrath71e15a02005-08-27 10:33:26 +000054 die->prune = true;
Roland McGrathd1a48172007-08-07 19:51:01 +000055 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 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000079
Roland McGrath71e15a02005-08-27 10:33:26 +000080 return 0;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000081}
82
Roland McGrath71e15a02005-08-27 10:33:26 +000083/* Preorder visitor for second partial traversal after finding a
84 concrete inlined instance. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000085static int
Roland McGrath71e15a02005-08-27 10:33:26 +000086origin_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000087{
Roland McGrath71e15a02005-08-27 10:33:26 +000088 struct args *a = arg;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000089
Roland McGrath71e15a02005-08-27 10:33:26 +000090 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)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000100 {
Roland McGrath71e15a02005-08-27 10:33:26 +0000101 free (a->scopes);
102 __libdw_seterrno (DWARF_E_NOMEM);
103 return -1;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000104 }
105
Roland McGrath71e15a02005-08-27 10:33:26 +0000106 a->scopes = scopes;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000107 do
108 {
Roland McGrath71e15a02005-08-27 10:33:26 +0000109 die = die->parent;
110 scopes[a->nscopes++] = die->die;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000111 }
Roland McGrath71e15a02005-08-27 10:33:26 +0000112 while (a->nscopes < nscopes);
113 assert (die->parent == NULL);
114 return a->nscopes;
115}
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000116
Roland McGrath71e15a02005-08-27 10:33:26 +0000117/* Postorder visitor: first (innermost) call wins. */
118static int
119pc_record (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
120{
121 struct args *a = arg;
122
Roland McGrathd1a48172007-08-07 19:51:01 +0000123 if (die->prune)
124 return 0;
125
Roland McGrath71e15a02005-08-27 10:33:26 +0000126 if (a->scopes == NULL)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000127 {
Roland McGrath71e15a02005-08-27 10:33:26 +0000128 /* 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)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000133 {
134 __libdw_seterrno (DWARF_E_NOMEM);
135 return -1;
136 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000137
Roland McGrath71e15a02005-08-27 10:33:26 +0000138 for (unsigned int i = 0; i < a->nscopes; ++i)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000139 {
Roland McGrath71e15a02005-08-27 10:33:26 +0000140 a->scopes[i] = die->die;
141 die = die->parent;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000142 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000143
Roland McGrath71e15a02005-08-27 10:33:26 +0000144 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. */
Roland McGrathd1a48172007-08-07 19:51:01 +0000179 return __libdw_visit_scopes (depth, die, &origin_match, NULL, a);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000180}
181
182
183int
184dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes)
185{
186 if (cudie == NULL)
187 return -1;
188
Roland McGrath71e15a02005-08-27 10:33:26 +0000189 struct Dwarf_Die_Chain cu = { .parent = NULL, .die = *cudie };
190 struct args a = { .pc = pc };
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000191
Roland McGrath71e15a02005-08-27 10:33:26 +0000192 int result = __libdw_visit_scopes (0, &cu, &pc_match, &pc_record, &a);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000193
Roland McGrath71e15a02005-08-27 10:33:26 +0000194 if (result == 0 && a.scopes != NULL)
195 result = __libdw_visit_scopes (0, &cu, &origin_match, NULL, &a);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000196
Roland McGrath71e15a02005-08-27 10:33:26 +0000197 if (result > 0)
198 *scopes = a.scopes;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000199
Roland McGrath71e15a02005-08-27 10:33:26 +0000200 return result;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000201}