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 : 1264179 : tree_visitor (unsigned int depth __attribute__ ((unused)), 58 : : struct Dwarf_Die_Chain *chain, void *arg) 59 : : { 60 : 1264179 : struct visitor_info *const v = arg; 61 : 1264179 : Dwarf_Die *die = &chain->die; 62 : 1264179 : void *start_addr = v->start_addr; 63 : 1264179 : 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 : 1264179 : int tag = INTUSE(dwarf_tag) (die); 69 [ + + ]: 1264179 : if (v->c_cu 70 : 1257007 : && tag != DW_TAG_subprogram 71 [ + + ]: 1257007 : && tag != DW_TAG_lexical_block 72 [ + + ]: 1164482 : && tag != DW_TAG_inlined_subroutine) 73 : : { 74 : 1138722 : chain->prune = true; 75 : 1138722 : return DWARF_CB_OK; 76 : : } 77 : : 78 : : /* Skip all DIEs till we found the (re)start addr. */ 79 [ + + ]: 125457 : 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 [ + + ]: 125342 : if (tag != DW_TAG_subprogram 88 [ + + ]: 49256 : || INTUSE(dwarf_hasattr) (die, DW_AT_declaration)) 89 : 101252 : return DWARF_CB_OK; 90 : : 91 : 24090 : v->last_addr = die_addr; 92 : 24090 : return (*v->callback) (die, v->arg); 93 : : } 94 : : 95 : : ptrdiff_t 96 : 6535 : dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *), 97 : : void *arg, ptrdiff_t offset) 98 : : { 99 [ + - + + ]: 6535 : if (unlikely (cudie == NULL 100 : : || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit)) 101 : 2 : return -1; 102 : : 103 : 6533 : int lang = INTUSE(dwarf_srclang) (cudie); 104 : 13066 : bool c_cu = (lang == DW_LANG_C89 105 : 6533 : || lang == DW_LANG_C 106 : 6533 : || lang == DW_LANG_C99 107 [ + + + + ]: 6533 : || lang == DW_LANG_C11); 108 : : 109 : 6533 : struct visitor_info v = { callback, arg, (void *) offset, NULL, c_cu }; 110 : 6533 : struct Dwarf_Die_Chain chain = { .die = CUDIE (cudie->cu), 111 : : .parent = NULL }; 112 : 6533 : int res = __libdw_visit_scopes (0, &chain, NULL, &tree_visitor, NULL, &v); 113 : : 114 [ + + ]: 6533 : if (res == DWARF_CB_ABORT) 115 : 40 : return (ptrdiff_t) v.last_addr; 116 : : else 117 : 6493 : return res; 118 : : }