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