xref: /aosp_15_r20/external/elfutils/libdw/dwarf_getscopes.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Return scope DIEs containing PC address.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2005, 2007, 2015 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2023 Mark J. Wielaard <[email protected]>
4*7304104dSAndroid Build Coastguard Worker    This file is part of elfutils.
5*7304104dSAndroid Build Coastguard Worker 
6*7304104dSAndroid Build Coastguard Worker    This file is free software; you can redistribute it and/or modify
7*7304104dSAndroid Build Coastguard Worker    it under the terms of either
8*7304104dSAndroid Build Coastguard Worker 
9*7304104dSAndroid Build Coastguard Worker      * the GNU Lesser General Public License as published by the Free
10*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 3 of the License, or (at
11*7304104dSAndroid Build Coastguard Worker        your option) any later version
12*7304104dSAndroid Build Coastguard Worker 
13*7304104dSAndroid Build Coastguard Worker    or
14*7304104dSAndroid Build Coastguard Worker 
15*7304104dSAndroid Build Coastguard Worker      * the GNU General Public License as published by the Free
16*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 2 of the License, or (at
17*7304104dSAndroid Build Coastguard Worker        your option) any later version
18*7304104dSAndroid Build Coastguard Worker 
19*7304104dSAndroid Build Coastguard Worker    or both in parallel, as here.
20*7304104dSAndroid Build Coastguard Worker 
21*7304104dSAndroid Build Coastguard Worker    elfutils is distributed in the hope that it will be useful, but
22*7304104dSAndroid Build Coastguard Worker    WITHOUT ANY WARRANTY; without even the implied warranty of
23*7304104dSAndroid Build Coastguard Worker    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24*7304104dSAndroid Build Coastguard Worker    General Public License for more details.
25*7304104dSAndroid Build Coastguard Worker 
26*7304104dSAndroid Build Coastguard Worker    You should have received copies of the GNU General Public License and
27*7304104dSAndroid Build Coastguard Worker    the GNU Lesser General Public License along with this program.  If
28*7304104dSAndroid Build Coastguard Worker    not, see <http://www.gnu.org/licenses/>.  */
29*7304104dSAndroid Build Coastguard Worker 
30*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
31*7304104dSAndroid Build Coastguard Worker # include <config.h>
32*7304104dSAndroid Build Coastguard Worker #endif
33*7304104dSAndroid Build Coastguard Worker 
34*7304104dSAndroid Build Coastguard Worker #include <assert.h>
35*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
36*7304104dSAndroid Build Coastguard Worker #include "libdwP.h"
37*7304104dSAndroid Build Coastguard Worker #include <dwarf.h>
38*7304104dSAndroid Build Coastguard Worker 
39*7304104dSAndroid Build Coastguard Worker 
40*7304104dSAndroid Build Coastguard Worker struct args
41*7304104dSAndroid Build Coastguard Worker {
42*7304104dSAndroid Build Coastguard Worker   Dwarf_Addr pc;
43*7304104dSAndroid Build Coastguard Worker   Dwarf_Die *scopes;
44*7304104dSAndroid Build Coastguard Worker   unsigned int inlined, nscopes;
45*7304104dSAndroid Build Coastguard Worker   Dwarf_Die inlined_origin;
46*7304104dSAndroid Build Coastguard Worker };
47*7304104dSAndroid Build Coastguard Worker 
48*7304104dSAndroid Build Coastguard Worker /* Preorder visitor: prune the traversal if this DIE does not contain PC.  */
49*7304104dSAndroid Build Coastguard Worker static int
pc_match(unsigned int depth,struct Dwarf_Die_Chain * die,void * arg)50*7304104dSAndroid Build Coastguard Worker pc_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
51*7304104dSAndroid Build Coastguard Worker {
52*7304104dSAndroid Build Coastguard Worker   struct args *a = arg;
53*7304104dSAndroid Build Coastguard Worker 
54*7304104dSAndroid Build Coastguard Worker   if (a->scopes != NULL)
55*7304104dSAndroid Build Coastguard Worker     die->prune = true;
56*7304104dSAndroid Build Coastguard Worker   else
57*7304104dSAndroid Build Coastguard Worker     {
58*7304104dSAndroid Build Coastguard Worker       /* dwarf_haspc returns an error if there are no appropriate attributes.
59*7304104dSAndroid Build Coastguard Worker 	 But we use it indiscriminantly instead of presuming which tags can
60*7304104dSAndroid Build Coastguard Worker 	 have PC attributes.  So when it fails for that reason, treat it just
61*7304104dSAndroid Build Coastguard Worker 	 as a nonmatching return.  */
62*7304104dSAndroid Build Coastguard Worker       int result = INTUSE(dwarf_haspc) (&die->die, a->pc);
63*7304104dSAndroid Build Coastguard Worker       if (result < 0)
64*7304104dSAndroid Build Coastguard Worker 	{
65*7304104dSAndroid Build Coastguard Worker 	  int error = INTUSE(dwarf_errno) ();
66*7304104dSAndroid Build Coastguard Worker 	  if (error != DWARF_E_NOERROR
67*7304104dSAndroid Build Coastguard Worker 	      && error != DWARF_E_NO_DEBUG_RANGES
68*7304104dSAndroid Build Coastguard Worker 	      && error != DWARF_E_NO_DEBUG_RNGLISTS)
69*7304104dSAndroid Build Coastguard Worker 	    {
70*7304104dSAndroid Build Coastguard Worker 	      __libdw_seterrno (error);
71*7304104dSAndroid Build Coastguard Worker 	      return -1;
72*7304104dSAndroid Build Coastguard Worker 	    }
73*7304104dSAndroid Build Coastguard Worker 	  result = 0;
74*7304104dSAndroid Build Coastguard Worker 	}
75*7304104dSAndroid Build Coastguard Worker       if (result == 0)
76*7304104dSAndroid Build Coastguard Worker     	die->prune = true;
77*7304104dSAndroid Build Coastguard Worker 
78*7304104dSAndroid Build Coastguard Worker       if (!die->prune
79*7304104dSAndroid Build Coastguard Worker 	  && INTUSE (dwarf_tag) (&die->die) == DW_TAG_inlined_subroutine)
80*7304104dSAndroid Build Coastguard Worker 	a->inlined = depth;
81*7304104dSAndroid Build Coastguard Worker     }
82*7304104dSAndroid Build Coastguard Worker 
83*7304104dSAndroid Build Coastguard Worker   return 0;
84*7304104dSAndroid Build Coastguard Worker }
85*7304104dSAndroid Build Coastguard Worker 
86*7304104dSAndroid Build Coastguard Worker /* Preorder visitor for second partial traversal after finding a
87*7304104dSAndroid Build Coastguard Worker    concrete inlined instance.  */
88*7304104dSAndroid Build Coastguard Worker static int
origin_match(unsigned int depth,struct Dwarf_Die_Chain * die,void * arg)89*7304104dSAndroid Build Coastguard Worker origin_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
90*7304104dSAndroid Build Coastguard Worker {
91*7304104dSAndroid Build Coastguard Worker   struct args *a = arg;
92*7304104dSAndroid Build Coastguard Worker 
93*7304104dSAndroid Build Coastguard Worker   if (die->die.addr != a->inlined_origin.addr)
94*7304104dSAndroid Build Coastguard Worker     return 0;
95*7304104dSAndroid Build Coastguard Worker 
96*7304104dSAndroid Build Coastguard Worker   /* We have a winner!  This is the abstract definition of the inline
97*7304104dSAndroid Build Coastguard Worker      function of which A->scopes[A->nscopes - 1] is a concrete instance.
98*7304104dSAndroid Build Coastguard Worker   */
99*7304104dSAndroid Build Coastguard Worker 
100*7304104dSAndroid Build Coastguard Worker   unsigned int nscopes = a->nscopes + depth;
101*7304104dSAndroid Build Coastguard Worker   Dwarf_Die *scopes = realloc (a->scopes, nscopes * sizeof scopes[0]);
102*7304104dSAndroid Build Coastguard Worker   if (scopes == NULL)
103*7304104dSAndroid Build Coastguard Worker     {
104*7304104dSAndroid Build Coastguard Worker       /* a->scopes will be freed by dwarf_getscopes on error.  */
105*7304104dSAndroid Build Coastguard Worker       __libdw_seterrno (DWARF_E_NOMEM);
106*7304104dSAndroid Build Coastguard Worker       return -1;
107*7304104dSAndroid Build Coastguard Worker     }
108*7304104dSAndroid Build Coastguard Worker 
109*7304104dSAndroid Build Coastguard Worker   a->scopes = scopes;
110*7304104dSAndroid Build Coastguard Worker   do
111*7304104dSAndroid Build Coastguard Worker     {
112*7304104dSAndroid Build Coastguard Worker       die = die->parent;
113*7304104dSAndroid Build Coastguard Worker       scopes[a->nscopes++] = die->die;
114*7304104dSAndroid Build Coastguard Worker     }
115*7304104dSAndroid Build Coastguard Worker   while (a->nscopes < nscopes);
116*7304104dSAndroid Build Coastguard Worker   assert (die->parent == NULL);
117*7304104dSAndroid Build Coastguard Worker   return a->nscopes;
118*7304104dSAndroid Build Coastguard Worker }
119*7304104dSAndroid Build Coastguard Worker 
120*7304104dSAndroid Build Coastguard Worker /* Postorder visitor: first (innermost) call wins.  */
121*7304104dSAndroid Build Coastguard Worker static int
pc_record(unsigned int depth,struct Dwarf_Die_Chain * die,void * arg)122*7304104dSAndroid Build Coastguard Worker pc_record (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
123*7304104dSAndroid Build Coastguard Worker {
124*7304104dSAndroid Build Coastguard Worker   struct args *a = arg;
125*7304104dSAndroid Build Coastguard Worker 
126*7304104dSAndroid Build Coastguard Worker   if (die->prune)
127*7304104dSAndroid Build Coastguard Worker     return 0;
128*7304104dSAndroid Build Coastguard Worker 
129*7304104dSAndroid Build Coastguard Worker   if (a->scopes == NULL)
130*7304104dSAndroid Build Coastguard Worker     {
131*7304104dSAndroid Build Coastguard Worker       /* We have hit the innermost DIE that contains the target PC.  */
132*7304104dSAndroid Build Coastguard Worker 
133*7304104dSAndroid Build Coastguard Worker       a->nscopes = depth + 1 - a->inlined;
134*7304104dSAndroid Build Coastguard Worker       a->scopes = malloc (a->nscopes * sizeof a->scopes[0]);
135*7304104dSAndroid Build Coastguard Worker       if (a->scopes == NULL)
136*7304104dSAndroid Build Coastguard Worker 	{
137*7304104dSAndroid Build Coastguard Worker 	  __libdw_seterrno (DWARF_E_NOMEM);
138*7304104dSAndroid Build Coastguard Worker 	  return -1;
139*7304104dSAndroid Build Coastguard Worker 	}
140*7304104dSAndroid Build Coastguard Worker 
141*7304104dSAndroid Build Coastguard Worker       for (unsigned int i = 0; i < a->nscopes; ++i)
142*7304104dSAndroid Build Coastguard Worker 	{
143*7304104dSAndroid Build Coastguard Worker 	  a->scopes[i] = die->die;
144*7304104dSAndroid Build Coastguard Worker 	  die = die->parent;
145*7304104dSAndroid Build Coastguard Worker 	}
146*7304104dSAndroid Build Coastguard Worker 
147*7304104dSAndroid Build Coastguard Worker       if (a->inlined == 0)
148*7304104dSAndroid Build Coastguard Worker 	{
149*7304104dSAndroid Build Coastguard Worker 	  assert (die == NULL);
150*7304104dSAndroid Build Coastguard Worker 	  return a->nscopes;
151*7304104dSAndroid Build Coastguard Worker 	}
152*7304104dSAndroid Build Coastguard Worker 
153*7304104dSAndroid Build Coastguard Worker       /* This is the concrete inlined instance itself.
154*7304104dSAndroid Build Coastguard Worker 	 Record its abstract_origin pointer.  */
155*7304104dSAndroid Build Coastguard Worker       Dwarf_Die *const inlinedie = &a->scopes[depth - a->inlined];
156*7304104dSAndroid Build Coastguard Worker 
157*7304104dSAndroid Build Coastguard Worker       assert (INTUSE (dwarf_tag) (inlinedie) == DW_TAG_inlined_subroutine);
158*7304104dSAndroid Build Coastguard Worker       Dwarf_Attribute attr_mem;
159*7304104dSAndroid Build Coastguard Worker       Dwarf_Attribute *attr = INTUSE (dwarf_attr) (inlinedie,
160*7304104dSAndroid Build Coastguard Worker 						   DW_AT_abstract_origin,
161*7304104dSAndroid Build Coastguard Worker 						   &attr_mem);
162*7304104dSAndroid Build Coastguard Worker       if (INTUSE (dwarf_formref_die) (attr, &a->inlined_origin) == NULL)
163*7304104dSAndroid Build Coastguard Worker 	return -1;
164*7304104dSAndroid Build Coastguard Worker       return 0;
165*7304104dSAndroid Build Coastguard Worker     }
166*7304104dSAndroid Build Coastguard Worker 
167*7304104dSAndroid Build Coastguard Worker 
168*7304104dSAndroid Build Coastguard Worker   /* We've recorded the scopes back to one that is a concrete inlined
169*7304104dSAndroid Build Coastguard Worker      instance.  Now return out of the traversal back to the scope
170*7304104dSAndroid Build Coastguard Worker      containing that instance.  */
171*7304104dSAndroid Build Coastguard Worker 
172*7304104dSAndroid Build Coastguard Worker   assert (a->inlined);
173*7304104dSAndroid Build Coastguard Worker   if (depth >= a->inlined)
174*7304104dSAndroid Build Coastguard Worker     /* Not there yet.  */
175*7304104dSAndroid Build Coastguard Worker     return 0;
176*7304104dSAndroid Build Coastguard Worker 
177*7304104dSAndroid Build Coastguard Worker   /* This is the innermost inline scope, we are done here.  */
178*7304104dSAndroid Build Coastguard Worker   return a->nscopes;
179*7304104dSAndroid Build Coastguard Worker }
180*7304104dSAndroid Build Coastguard Worker 
181*7304104dSAndroid Build Coastguard Worker 
182*7304104dSAndroid Build Coastguard Worker int
dwarf_getscopes(Dwarf_Die * cudie,Dwarf_Addr pc,Dwarf_Die ** scopes)183*7304104dSAndroid Build Coastguard Worker dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes)
184*7304104dSAndroid Build Coastguard Worker {
185*7304104dSAndroid Build Coastguard Worker   if (cudie == NULL)
186*7304104dSAndroid Build Coastguard Worker     return -1;
187*7304104dSAndroid Build Coastguard Worker 
188*7304104dSAndroid Build Coastguard Worker   struct Dwarf_Die_Chain cu = { .parent = NULL, .die = *cudie };
189*7304104dSAndroid Build Coastguard Worker   struct args a = { .pc = pc };
190*7304104dSAndroid Build Coastguard Worker 
191*7304104dSAndroid Build Coastguard Worker   int result = __libdw_visit_scopes (0, &cu, NULL, &pc_match, &pc_record, &a);
192*7304104dSAndroid Build Coastguard Worker 
193*7304104dSAndroid Build Coastguard Worker   if (result >= 0 && a.scopes != NULL && a.inlined > 0)
194*7304104dSAndroid Build Coastguard Worker     {
195*7304104dSAndroid Build Coastguard Worker       /* We like the find the inline function's abstract definition
196*7304104dSAndroid Build Coastguard Worker          scope, but that might be in a different CU.  */
197*7304104dSAndroid Build Coastguard Worker       cu.die = CUDIE (a.inlined_origin.cu);
198*7304104dSAndroid Build Coastguard Worker       result = __libdw_visit_scopes (0, &cu, NULL, &origin_match, NULL, &a);
199*7304104dSAndroid Build Coastguard Worker     }
200*7304104dSAndroid Build Coastguard Worker 
201*7304104dSAndroid Build Coastguard Worker   if (result > 0)
202*7304104dSAndroid Build Coastguard Worker     *scopes = a.scopes;
203*7304104dSAndroid Build Coastguard Worker   else if (result < 0)
204*7304104dSAndroid Build Coastguard Worker     free (a.scopes);
205*7304104dSAndroid Build Coastguard Worker 
206*7304104dSAndroid Build Coastguard Worker   return result;
207*7304104dSAndroid Build Coastguard Worker }
208