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 1124991 : tree_visitor (unsigned int depth __attribute__ ((unused)),
58 : struct Dwarf_Die_Chain *chain, void *arg)
59 : {
60 1124991 : struct visitor_info *const v = arg;
61 1124991 : Dwarf_Die *die = &chain->die;
62 1124991 : void *start_addr = v->start_addr;
63 1124991 : 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 1124991 : int tag = INTUSE(dwarf_tag) (die);
69 1124991 : if (v->c_cu
70 1117855 : && tag != DW_TAG_subprogram
71 1117855 : && tag != DW_TAG_lexical_block
72 1022588 : && tag != DW_TAG_inlined_subroutine)
73 : {
74 994335 : chain->prune = true;
75 994335 : return DWARF_CB_OK;
76 : }
77 :
78 : /* Skip all DIEs till we found the (re)start addr. */
79 130656 : if (start_addr != NULL)
80 : {
81 102 : if (die_addr == start_addr)
82 30 : v->start_addr = NULL;
83 : return DWARF_CB_OK;
84 : }
85 :
86 : /* If this isn't a (defining) subprogram entity, skip DIE. */
87 130554 : if (tag != DW_TAG_subprogram
88 50090 : || INTUSE(dwarf_hasattr) (die, DW_AT_declaration))
89 : return DWARF_CB_OK;
90 :
91 24204 : v->last_addr = die_addr;
92 24204 : return (*v->callback) (die, v->arg);
93 : }
94 :
95 : ptrdiff_t
96 6211 : dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *),
97 : void *arg, ptrdiff_t offset)
98 : {
99 6211 : if (unlikely (cudie == NULL
100 : || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit))
101 : return -1;
102 :
103 5529 : int lang = INTUSE(dwarf_srclang) (cudie);
104 5529 : bool c_cu = (lang == DW_LANG_C89
105 5529 : || lang == DW_LANG_C
106 5529 : || lang == DW_LANG_C99
107 5529 : || lang == DW_LANG_C11);
108 :
109 5529 : struct visitor_info v = { callback, arg, (void *) offset, NULL, c_cu };
110 11058 : struct Dwarf_Die_Chain chain = { .die = CUDIE (cudie->cu),
111 : .parent = NULL };
112 5529 : int res = __libdw_visit_scopes (0, &chain, NULL, &tree_visitor, NULL, &v);
113 :
114 5529 : if (res == DWARF_CB_ABORT)
115 30 : return (ptrdiff_t) v.last_addr;
116 : else
117 5499 : return res;
118 : }
|