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