• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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