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