Branch data Line data Source code
1 : : /* Maintenance of module list in libdwfl. 2 : : Copyright (C) 2005, 2006, 2007, 2008, 2014, 2015 Red Hat, Inc. 3 : : This file is part of elfutils. 4 : : 5 : : This file is free software; you can redistribute it and/or modify 6 : : it under the terms of either 7 : : 8 : : * the GNU Lesser General Public License as published by the Free 9 : : Software Foundation; either version 3 of the License, or (at 10 : : your option) any later version 11 : : 12 : : or 13 : : 14 : : * the GNU General Public License as published by the Free 15 : : Software Foundation; either version 2 of the License, or (at 16 : : your option) any later version 17 : : 18 : : or both in parallel, as here. 19 : : 20 : : elfutils is distributed in the hope that it will be useful, but 21 : : WITHOUT ANY WARRANTY; without even the implied warranty of 22 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 : : General Public License for more details. 24 : : 25 : : You should have received copies of the GNU General Public License and 26 : : the GNU Lesser General Public License along with this program. If 27 : : not, see <http://www.gnu.org/licenses/>. */ 28 : : 29 : : #ifdef HAVE_CONFIG_H 30 : : # include <config.h> 31 : : #endif 32 : : 33 : : #include "libdwflP.h" 34 : : #include "cfi.h" 35 : : #include <search.h> 36 : : 37 : : static void 38 : 19640 : free_cu (struct dwfl_cu *cu) 39 : : { 40 [ + + ]: 19640 : if (cu->lines != NULL) 41 : 2508 : free (cu->lines); 42 : 19640 : free (cu); 43 : 19640 : } 44 : : 45 : : static void 46 : 19640 : nofree (void *arg __attribute__ ((unused))) 47 : : { 48 : 19640 : } 49 : : 50 : : static void 51 : 164760 : free_file (struct dwfl_file *file) 52 : : { 53 : 164760 : free (file->name); 54 : : 55 : : /* Close the fd only on the last reference. */ 56 [ + + + - : 164760 : if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1) + + ] 57 : 10262 : close (file->fd); 58 : 164760 : } 59 : : 60 : : void 61 : : internal_function 62 : 81918 : __libdwfl_module_free (Dwfl_Module *mod) 63 : : { 64 : 81918 : eu_search_tree_fini (&mod->lazy_cu_tree, nofree); 65 : : 66 [ + + ]: 81918 : if (mod->aranges != NULL) 67 : 126 : free (mod->aranges); 68 : : 69 [ + + ]: 81918 : if (mod->cu != NULL) 70 : : { 71 [ + + ]: 19946 : for (size_t i = 0; i < mod->ncu; ++i) 72 : 19640 : free_cu (mod->cu[i]); 73 : 306 : free (mod->cu); 74 : : } 75 : : 76 : : /* We might have primed the Dwarf_CFI ebl cache with our own ebl 77 : : in __libdwfl_set_cfi. Make sure we don't free it twice. */ 78 [ + + ]: 81918 : if (mod->eh_cfi != NULL) 79 : : { 80 [ + - + - ]: 148 : if (mod->eh_cfi->ebl != NULL && mod->eh_cfi->ebl == mod->ebl) 81 : 148 : mod->eh_cfi->ebl = NULL; 82 : 148 : dwarf_cfi_end (mod->eh_cfi); 83 : : } 84 : : 85 [ + + ]: 81918 : if (mod->dwarf_cfi != NULL) 86 : : { 87 [ + - + - ]: 24 : if (mod->dwarf_cfi->ebl != NULL && mod->dwarf_cfi->ebl == mod->ebl) 88 : 24 : mod->dwarf_cfi->ebl = NULL; 89 : : /* We don't need to explicitly destroy the dwarf_cfi. 90 : : That will be done by dwarf_end. */ 91 : : } 92 : : 93 [ + + ]: 81918 : if (mod->dw != NULL) 94 : : { 95 : 10852 : INTUSE(dwarf_end) (mod->dw); 96 [ + + ]: 10852 : if (mod->alt != NULL) 97 : : { 98 : 70 : INTUSE(dwarf_end) (mod->alt); 99 [ + - ]: 70 : if (mod->alt_elf != NULL) 100 : 70 : elf_end (mod->alt_elf); 101 [ + - ]: 70 : if (mod->alt_fd != -1) 102 : 70 : close (mod->alt_fd); 103 : : } 104 : : } 105 : : 106 [ + + ]: 81918 : if (mod->ebl != NULL) 107 : 892 : ebl_closebackend (mod->ebl); 108 : : 109 [ + + ]: 81918 : if (mod->debug.elf != mod->main.elf) 110 : 924 : free_file (&mod->debug); 111 : 81918 : free_file (&mod->main); 112 : 81918 : free_file (&mod->aux_sym); 113 : : 114 [ + + ]: 81918 : if (mod->build_id_bits != NULL) 115 : 526 : free (mod->build_id_bits); 116 : : 117 [ + + ]: 81918 : if (mod->reloc_info != NULL) 118 : 350 : free (mod->reloc_info); 119 : : 120 : 81918 : free (mod->name); 121 : 81918 : free (mod->elfpath); 122 : 81918 : free (mod); 123 : 81918 : } 124 : : 125 : : void 126 : 0 : dwfl_report_begin_add (Dwfl *dwfl __attribute__ ((unused))) 127 : : { 128 : : /* The lookup table will be cleared on demand, there is nothing we need 129 : : to do here. */ 130 : 0 : } 131 : : INTDEF (dwfl_report_begin_add) 132 : : 133 : : void 134 : 22 : dwfl_report_begin (Dwfl *dwfl) 135 : : { 136 : : /* Clear the segment lookup table. */ 137 : 22 : dwfl->lookup_elts = 0; 138 : : 139 [ + + ]: 30 : for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next) 140 : 8 : m->gc = true; 141 : : 142 : 22 : dwfl->offline_next_address = OFFLINE_REDZONE; 143 : 22 : } 144 : : INTDEF (dwfl_report_begin) 145 : : 146 : : static inline Dwfl_Module * 147 : 81972 : use (Dwfl_Module *mod, Dwfl_Module **tailp, Dwfl *dwfl) 148 : : { 149 : 81972 : mod->next = *tailp; 150 : 81972 : *tailp = mod; 151 : : 152 : 81972 : if (unlikely (dwfl->lookup_module != NULL)) 153 : : { 154 : 2 : free (dwfl->lookup_module); 155 : 2 : dwfl->lookup_module = NULL; 156 : : } 157 : : 158 : 38 : return mod; 159 : : } 160 : : 161 : : /* Report that a module called NAME spans addresses [START, END). 162 : : Returns the module handle, either existing or newly allocated, 163 : : or returns a null pointer for an allocation error. */ 164 : : Dwfl_Module * 165 : 81972 : dwfl_report_module (Dwfl *dwfl, const char *name, 166 : : GElf_Addr start, GElf_Addr end) 167 : : { 168 : 81972 : Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp; 169 : : 170 [ + + ]: 363144 : for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next)) 171 : : { 172 [ + + + - ]: 281210 : if (m->low_addr == start && m->high_addr == end 173 [ + - ]: 38 : && !strcmp (m->name, name)) 174 : : { 175 : : /* This module is still here. Move it to the place in the list 176 : : after the last module already reported. */ 177 : 38 : *prevp = m->next; 178 : 38 : m->gc = false; 179 [ - + ]: 38 : return use (m, tailp, dwfl); 180 : : } 181 : : 182 [ + - ]: 281172 : if (! m->gc) 183 : 281172 : tailp = &m->next; 184 : : } 185 : : 186 : 81934 : Dwfl_Module *mod = calloc (1, sizeof *mod); 187 [ - + ]: 81934 : if (mod == NULL) 188 : 0 : goto nomem; 189 : : 190 : 81934 : mod->name = strdup (name); 191 [ - + ]: 81934 : if (mod->name == NULL) 192 : : { 193 : 0 : free (mod); 194 : 0 : nomem: 195 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM); 196 : 0 : return NULL; 197 : : } 198 : : 199 : 81934 : mod->low_addr = start; 200 : 81934 : mod->high_addr = end; 201 : 81934 : mod->dwfl = dwfl; 202 : 81934 : eu_search_tree_init (&mod->lazy_cu_tree); 203 : : 204 [ + + ]: 81934 : return use (mod, tailp, dwfl); 205 : : } 206 : : INTDEF (dwfl_report_module) 207 : : 208 : : 209 : : /* Finish reporting the current set of modules to the library. 210 : : If REMOVED is not null, it's called for each module that 211 : : existed before but was not included in the current report. 212 : : Returns a nonzero return value from the callback. 213 : : DWFL cannot be used until this function has returned zero. */ 214 : : int 215 : 11528 : dwfl_report_end (Dwfl *dwfl, 216 : : int (*removed) (Dwfl_Module *, void *, 217 : : const char *, Dwarf_Addr, 218 : : void *arg), 219 : : void *arg) 220 : : { 221 : 11528 : Dwfl_Module **tailp = &dwfl->modulelist; 222 [ + + ]: 93432 : while (*tailp != NULL) 223 : : { 224 : 81904 : Dwfl_Module *m = *tailp; 225 [ - + - - ]: 81904 : if (m->gc && removed != NULL) 226 : : { 227 : 0 : int result = (*removed) (MODCB_ARGS (m), arg); 228 [ # # ]: 0 : if (result != 0) 229 : 0 : return result; 230 : : } 231 [ - + ]: 81904 : if (m->gc) 232 : : { 233 : 0 : *tailp = m->next; 234 : 0 : __libdwfl_module_free (m); 235 : : } 236 : : else 237 : 81904 : tailp = &m->next; 238 : : } 239 : : 240 : : return 0; 241 : : } 242 : : INTDEF (dwfl_report_end)