Branch data Line data Source code
1 : : /* Get function information. 2 : : Copyright (C) 2005, 2013, 2015 Red Hat, Inc. 3 : : Copyright (C) 2024 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 : 3041330 : tree_visitor (unsigned int depth __attribute__ ((unused)), 59 : : struct Dwarf_Die_Chain *chain, void *arg) 60 : : { 61 : 3041330 : struct visitor_info *const v = arg; 62 : 3041330 : Dwarf_Die *die = &chain->die; 63 : 3041330 : void *start_addr = v->start_addr; 64 : 3041330 : 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 : 3041330 : int tag = INTUSE(dwarf_tag) (die); 70 [ + + ]: 3041330 : if (v->c_cu 71 : 3022320 : && tag != DW_TAG_subprogram 72 [ + + ]: 3022320 : && tag != DW_TAG_lexical_block 73 [ + + ]: 2812720 : && tag != DW_TAG_inlined_subroutine) 74 : : { 75 : 2754654 : chain->prune = true; 76 : 2754654 : return DWARF_CB_OK; 77 : : } 78 : : 79 : : /* Skip all DIEs till we found the (re)start addr. */ 80 [ + + ]: 286676 : 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 [ + + ]: 286444 : if (tag != DW_TAG_subprogram 89 [ + + ]: 125998 : || INTUSE(dwarf_hasattr) (die, DW_AT_declaration)) 90 : 228494 : return DWARF_CB_OK; 91 : : 92 : 57950 : v->last_addr = die_addr; 93 : 57950 : return (*v->callback) (die, v->arg); 94 : : } 95 : : 96 : : ptrdiff_t 97 : 14870 : dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *), 98 : : void *arg, ptrdiff_t offset) 99 : : { 100 [ + - + + ]: 14870 : if (unlikely (cudie == NULL 101 : : || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit)) 102 : 4 : return -1; 103 : : 104 : 14866 : int lang = INTUSE(dwarf_srclang) (cudie); 105 : 29732 : bool c_cu = (lang == DW_LANG_C89 106 : 14866 : || lang == DW_LANG_C 107 : 14866 : || lang == DW_LANG_C99 108 : 8744 : || lang == DW_LANG_C11 109 [ + + ]: 8744 : || lang == DW_LANG_C17 110 [ + + ]: 14866 : || lang == DW_LANG_C23); 111 : : 112 : 14866 : struct visitor_info v = { callback, arg, (void *) offset, NULL, c_cu }; 113 : 14866 : struct Dwarf_Die_Chain chain = { .die = CUDIE (cudie->cu), 114 : : .parent = NULL }; 115 : 14866 : int res = __libdw_visit_scopes (0, &chain, NULL, &tree_visitor, NULL, &v); 116 : : 117 [ + + ]: 14866 : if (res == DWARF_CB_ABORT) 118 : 82 : return (ptrdiff_t) v.last_addr; 119 : : else 120 : 14784 : return res; 121 : : }