xref: /aosp_15_r20/external/elfutils/libdw/dwarf_getfuncs.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Get function information.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2005, 2013, 2015 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker    This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker    Written by Ulrich Drepper <[email protected]>, 2005.
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 <dwarf.h>
35*7304104dSAndroid Build Coastguard Worker #include "libdwP.h"
36*7304104dSAndroid Build Coastguard Worker 
37*7304104dSAndroid Build Coastguard Worker 
38*7304104dSAndroid Build Coastguard Worker struct visitor_info
39*7304104dSAndroid Build Coastguard Worker {
40*7304104dSAndroid Build Coastguard Worker   /* The user callback of dwarf_getfuncs.  */
41*7304104dSAndroid Build Coastguard Worker   int (*callback) (Dwarf_Die *, void *);
42*7304104dSAndroid Build Coastguard Worker 
43*7304104dSAndroid Build Coastguard Worker   /* The user arg value to dwarf_getfuncs.  */
44*7304104dSAndroid Build Coastguard Worker   void *arg;
45*7304104dSAndroid Build Coastguard Worker 
46*7304104dSAndroid Build Coastguard Worker   /* Addr of the DIE offset where to (re)start the search.  Zero for all.  */
47*7304104dSAndroid Build Coastguard Worker   void *start_addr;
48*7304104dSAndroid Build Coastguard Worker 
49*7304104dSAndroid Build Coastguard Worker   /* Last subprogram DIE addr seen.  */
50*7304104dSAndroid Build Coastguard Worker   void *last_addr;
51*7304104dSAndroid Build Coastguard Worker 
52*7304104dSAndroid Build Coastguard Worker   /* The CU only contains C functions.  Allows pruning of most subtrees.  */
53*7304104dSAndroid Build Coastguard Worker   bool c_cu;
54*7304104dSAndroid Build Coastguard Worker };
55*7304104dSAndroid Build Coastguard Worker 
56*7304104dSAndroid Build Coastguard Worker static int
tree_visitor(unsigned int depth,struct Dwarf_Die_Chain * chain,void * arg)57*7304104dSAndroid Build Coastguard Worker tree_visitor (unsigned int depth __attribute__ ((unused)),
58*7304104dSAndroid Build Coastguard Worker 	      struct Dwarf_Die_Chain *chain, void *arg)
59*7304104dSAndroid Build Coastguard Worker {
60*7304104dSAndroid Build Coastguard Worker   struct visitor_info *const v = arg;
61*7304104dSAndroid Build Coastguard Worker   Dwarf_Die *die = &chain->die;
62*7304104dSAndroid Build Coastguard Worker   void *start_addr = v->start_addr;
63*7304104dSAndroid Build Coastguard Worker   void *die_addr = die->addr;
64*7304104dSAndroid Build Coastguard Worker 
65*7304104dSAndroid Build Coastguard Worker   /* Pure C CUs can only contain defining subprogram DIEs as direct
66*7304104dSAndroid Build Coastguard Worker      children of the CU DIE or as nested function inside a normal C
67*7304104dSAndroid Build Coastguard Worker      code constructs.  */
68*7304104dSAndroid Build Coastguard Worker   int tag = INTUSE(dwarf_tag) (die);
69*7304104dSAndroid Build Coastguard Worker   if (v->c_cu
70*7304104dSAndroid Build Coastguard Worker       && tag != DW_TAG_subprogram
71*7304104dSAndroid Build Coastguard Worker       && tag != DW_TAG_lexical_block
72*7304104dSAndroid Build Coastguard Worker       && tag != DW_TAG_inlined_subroutine)
73*7304104dSAndroid Build Coastguard Worker     {
74*7304104dSAndroid Build Coastguard Worker       chain->prune = true;
75*7304104dSAndroid Build Coastguard Worker       return DWARF_CB_OK;
76*7304104dSAndroid Build Coastguard Worker     }
77*7304104dSAndroid Build Coastguard Worker 
78*7304104dSAndroid Build Coastguard Worker   /* Skip all DIEs till we found the (re)start addr.  */
79*7304104dSAndroid Build Coastguard Worker   if (start_addr != NULL)
80*7304104dSAndroid Build Coastguard Worker     {
81*7304104dSAndroid Build Coastguard Worker       if (die_addr == start_addr)
82*7304104dSAndroid Build Coastguard Worker 	v->start_addr = NULL;
83*7304104dSAndroid Build Coastguard Worker       return DWARF_CB_OK;
84*7304104dSAndroid Build Coastguard Worker     }
85*7304104dSAndroid Build Coastguard Worker 
86*7304104dSAndroid Build Coastguard Worker   /* If this isn't a (defining) subprogram entity, skip DIE.  */
87*7304104dSAndroid Build Coastguard Worker   if (tag != DW_TAG_subprogram
88*7304104dSAndroid Build Coastguard Worker       || INTUSE(dwarf_hasattr) (die, DW_AT_declaration))
89*7304104dSAndroid Build Coastguard Worker     return DWARF_CB_OK;
90*7304104dSAndroid Build Coastguard Worker 
91*7304104dSAndroid Build Coastguard Worker   v->last_addr = die_addr;
92*7304104dSAndroid Build Coastguard Worker   return (*v->callback) (die, v->arg);
93*7304104dSAndroid Build Coastguard Worker }
94*7304104dSAndroid Build Coastguard Worker 
95*7304104dSAndroid Build Coastguard Worker ptrdiff_t
dwarf_getfuncs(Dwarf_Die * cudie,int (* callback)(Dwarf_Die *,void *),void * arg,ptrdiff_t offset)96*7304104dSAndroid Build Coastguard Worker dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *),
97*7304104dSAndroid Build Coastguard Worker 		void *arg, ptrdiff_t offset)
98*7304104dSAndroid Build Coastguard Worker {
99*7304104dSAndroid Build Coastguard Worker   if (unlikely (cudie == NULL
100*7304104dSAndroid Build Coastguard Worker 		|| INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit))
101*7304104dSAndroid Build Coastguard Worker     return -1;
102*7304104dSAndroid Build Coastguard Worker 
103*7304104dSAndroid Build Coastguard Worker   int lang = INTUSE(dwarf_srclang) (cudie);
104*7304104dSAndroid Build Coastguard Worker   bool c_cu = (lang == DW_LANG_C89
105*7304104dSAndroid Build Coastguard Worker 	       || lang == DW_LANG_C
106*7304104dSAndroid Build Coastguard Worker 	       || lang == DW_LANG_C99
107*7304104dSAndroid Build Coastguard Worker 	       || lang == DW_LANG_C11);
108*7304104dSAndroid Build Coastguard Worker 
109*7304104dSAndroid Build Coastguard Worker   struct visitor_info v = { callback, arg, (void *) offset, NULL, c_cu };
110*7304104dSAndroid Build Coastguard Worker   struct Dwarf_Die_Chain chain = { .die = CUDIE (cudie->cu),
111*7304104dSAndroid Build Coastguard Worker 				   .parent = NULL };
112*7304104dSAndroid Build Coastguard Worker   int res = __libdw_visit_scopes (0, &chain, NULL, &tree_visitor, NULL, &v);
113*7304104dSAndroid Build Coastguard Worker 
114*7304104dSAndroid Build Coastguard Worker   if (res == DWARF_CB_ABORT)
115*7304104dSAndroid Build Coastguard Worker     return (ptrdiff_t) v.last_addr;
116*7304104dSAndroid Build Coastguard Worker   else
117*7304104dSAndroid Build Coastguard Worker     return res;
118*7304104dSAndroid Build Coastguard Worker }
119