Branch data Line data Source code
1 : : /* Get function information.
2 : : Copyright (C) 2005, 2013, 2015 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : : Written by Ulrich Drepper <drepper@redhat.com>, 2005.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of either
8 : :
9 : : * the GNU Lesser General Public License as published by the Free
10 : : Software Foundation; either version 3 of the License, or (at
11 : : your option) any later version
12 : :
13 : : or
14 : :
15 : : * the GNU General Public License as published by the Free
16 : : Software Foundation; either version 2 of the License, or (at
17 : : your option) any later version
18 : :
19 : : or both in parallel, as here.
20 : :
21 : : elfutils is distributed in the hope that it will be useful, but
22 : : WITHOUT ANY WARRANTY; without even the implied warranty of
23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : : General Public License for more details.
25 : :
26 : : You should have received copies of the GNU General Public License and
27 : : the GNU Lesser General Public License along with this program. If
28 : : not, see <http://www.gnu.org/licenses/>. */
29 : :
30 : : #ifdef HAVE_CONFIG_H
31 : : # include <config.h>
32 : : #endif
33 : :
34 : : #include <dwarf.h>
35 : : #include "libdwP.h"
36 : :
37 : :
38 : : struct visitor_info
39 : : {
40 : : /* The user callback of dwarf_getfuncs. */
41 : : int (*callback) (Dwarf_Die *, void *);
42 : :
43 : : /* The user arg value to dwarf_getfuncs. */
44 : : void *arg;
45 : :
46 : : /* Addr of the DIE offset where to (re)start the search. Zero for all. */
47 : : void *start_addr;
48 : :
49 : : /* Last subprogram DIE addr seen. */
50 : : void *last_addr;
51 : :
52 : : /* The CU only contains C functions. Allows pruning of most subtrees. */
53 : : bool c_cu;
54 : : };
55 : :
56 : : static int
57 : 1831448 : tree_visitor (unsigned int depth __attribute__ ((unused)),
58 : : struct Dwarf_Die_Chain *chain, void *arg)
59 : : {
60 : 1831448 : struct visitor_info *const v = arg;
61 : 1831448 : Dwarf_Die *die = &chain->die;
62 : 1831448 : void *start_addr = v->start_addr;
63 : 1831448 : void *die_addr = die->addr;
64 : :
65 : : /* Pure C CUs can only contain defining subprogram DIEs as direct
66 : : children of the CU DIE or as nested function inside a normal C
67 : : code constructs. */
68 : 1831448 : int tag = INTUSE(dwarf_tag) (die);
69 [ + + ]: 1831448 : if (v->c_cu
70 : 1824312 : && tag != DW_TAG_subprogram
71 [ + + ]: 1824312 : && tag != DW_TAG_lexical_block
72 [ + + ]: 1734357 : && tag != DW_TAG_inlined_subroutine)
73 : : {
74 : 1708769 : chain->prune = true;
75 : 1708769 : return DWARF_CB_OK;
76 : : }
77 : :
78 : : /* Skip all DIEs till we found the (re)start addr. */
79 [ + + ]: 122679 : if (start_addr != NULL)
80 : : {
81 [ + + ]: 115 : if (die_addr == start_addr)
82 : 40 : v->start_addr = NULL;
83 : 115 : return DWARF_CB_OK;
84 : : }
85 : :
86 : : /* If this isn't a (defining) subprogram entity, skip DIE. */
87 [ + + ]: 122564 : if (tag != DW_TAG_subprogram
88 [ + + ]: 47630 : || INTUSE(dwarf_hasattr) (die, DW_AT_declaration))
89 : 99360 : return DWARF_CB_OK;
90 : :
91 : 23204 : v->last_addr = die_addr;
92 : 23204 : return (*v->callback) (die, v->arg);
93 : : }
94 : :
95 : : ptrdiff_t
96 : 6335 : dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *),
97 : : void *arg, ptrdiff_t offset)
98 : : {
99 [ + - ][ + + ]: 6335 : if (unlikely (cudie == NULL
100 : : || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit))
101 : 2 : return -1;
102 : :
103 : 6333 : int lang = INTUSE(dwarf_srclang) (cudie);
104 : 12666 : bool c_cu = (lang == DW_LANG_C89
105 : 6333 : || lang == DW_LANG_C
106 : 6333 : || lang == DW_LANG_C99
107 [ + + ][ + + ]: 6333 : || lang == DW_LANG_C11);
108 : :
109 : 6333 : struct visitor_info v = { callback, arg, (void *) offset, NULL, c_cu };
110 : 12666 : struct Dwarf_Die_Chain chain = { .die = CUDIE (cudie->cu),
111 : : .parent = NULL };
112 : 6333 : int res = __libdw_visit_scopes (0, &chain, NULL, &tree_visitor, NULL, &v);
113 : :
114 [ + + ]: 6333 : if (res == DWARF_CB_ABORT)
115 : 40 : return (ptrdiff_t) v.last_addr;
116 : : else
117 : 6293 : return res;
118 : : }
|