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 "../libdw/cfi.h" 35 : : #include <search.h> 36 : : #include <unistd.h> 37 : : 38 : : static void 39 : 8552 : free_cu (struct dwfl_cu *cu) 40 : : { 41 [ + + ]: 8552 : if (cu->lines != NULL) 42 : 1175 : free (cu->lines); 43 : 8552 : free (cu); 44 : 8552 : } 45 : : 46 : : static void 47 : 8552 : nofree (void *arg __attribute__ ((unused))) 48 : : { 49 : 8552 : } 50 : : 51 : : static void 52 : 391928 : free_file (struct dwfl_file *file) 53 : : { 54 : 391928 : free (file->name); 55 : : 56 : : /* Close the fd only on the last reference. */ 57 [ + + + - : 391928 : if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1) + + ] 58 : 5103 : close (file->fd); 59 : 391928 : } 60 : : 61 : : void 62 : : internal_function 63 : 195789 : __libdwfl_module_free (Dwfl_Module *mod) 64 : : { 65 [ + + ]: 195789 : if (mod->lazy_cu_root != NULL) 66 : 135 : tdestroy (mod->lazy_cu_root, nofree); 67 : : 68 [ + + ]: 195789 : if (mod->aranges != NULL) 69 : 54 : free (mod->aranges); 70 : : 71 [ + + ]: 195789 : if (mod->cu != NULL) 72 : : { 73 [ + + ]: 8687 : for (size_t i = 0; i < mod->ncu; ++i) 74 : 8552 : free_cu (mod->cu[i]); 75 : 135 : free (mod->cu); 76 : : } 77 : : 78 : : /* We might have primed the Dwarf_CFI ebl cache with our own ebl 79 : : in __libdwfl_set_cfi. Make sure we don't free it twice. */ 80 [ + + ]: 195789 : if (mod->eh_cfi != NULL) 81 : : { 82 [ + - + - ]: 71 : if (mod->eh_cfi->ebl != NULL && mod->eh_cfi->ebl == mod->ebl) 83 : 71 : mod->eh_cfi->ebl = NULL; 84 : 71 : dwarf_cfi_end (mod->eh_cfi); 85 : : } 86 : : 87 [ + + ]: 195789 : if (mod->dwarf_cfi != NULL) 88 : : { 89 [ + - + - ]: 12 : if (mod->dwarf_cfi->ebl != NULL && mod->dwarf_cfi->ebl == mod->ebl) 90 : 12 : mod->dwarf_cfi->ebl = NULL; 91 : : /* We don't need to explicitly destroy the dwarf_cfi. 92 : : That will be done by dwarf_end. */ 93 : : } 94 : : 95 [ + + ]: 195789 : if (mod->dw != NULL) 96 : : { 97 : 5345 : INTUSE(dwarf_end) (mod->dw); 98 [ + + ]: 5345 : if (mod->alt != NULL) 99 : : { 100 : 13 : INTUSE(dwarf_end) (mod->alt); 101 [ + - ]: 13 : if (mod->alt_elf != NULL) 102 : 13 : elf_end (mod->alt_elf); 103 [ + - ]: 13 : if (mod->alt_fd != -1) 104 : 13 : close (mod->alt_fd); 105 : : } 106 : : } 107 : : 108 [ + + ]: 195789 : if (mod->ebl != NULL) 109 : 410 : ebl_closebackend (mod->ebl); 110 : : 111 [ + + ]: 195789 : if (mod->debug.elf != mod->main.elf) 112 : 350 : free_file (&mod->debug); 113 : 195789 : free_file (&mod->main); 114 : 195789 : free_file (&mod->aux_sym); 115 : : 116 [ + + ]: 195789 : if (mod->build_id_bits != NULL) 117 : 183 : free (mod->build_id_bits); 118 : : 119 [ + + ]: 195789 : if (mod->reloc_info != NULL) 120 : 164 : free (mod->reloc_info); 121 : : 122 : 195789 : free (mod->name); 123 : 195789 : free (mod->elfdir); 124 : 195789 : free (mod); 125 : 195789 : } 126 : : 127 : : void 128 : 0 : dwfl_report_begin_add (Dwfl *dwfl __attribute__ ((unused))) 129 : : { 130 : : /* The lookup table will be cleared on demand, there is nothing we need 131 : : to do here. */ 132 : 0 : } 133 : : INTDEF (dwfl_report_begin_add) 134 : : 135 : : void 136 : 9 : dwfl_report_begin (Dwfl *dwfl) 137 : : { 138 : : /* Clear the segment lookup table. */ 139 : 9 : dwfl->lookup_elts = 0; 140 : : 141 [ + + ]: 13 : for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next) 142 : 4 : m->gc = true; 143 : : 144 : 9 : dwfl->offline_next_address = OFFLINE_REDZONE; 145 : 9 : } 146 : : INTDEF (dwfl_report_begin) 147 : : 148 : : static inline Dwfl_Module * 149 : 195832 : use (Dwfl_Module *mod, Dwfl_Module **tailp, Dwfl *dwfl) 150 : : { 151 : 195832 : mod->next = *tailp; 152 : 195832 : *tailp = mod; 153 : : 154 : 195832 : if (unlikely (dwfl->lookup_module != NULL)) 155 : : { 156 : 0 : free (dwfl->lookup_module); 157 : 0 : dwfl->lookup_module = NULL; 158 : : } 159 : : 160 : 4 : return mod; 161 : : } 162 : : 163 : : /* Report that a module called NAME spans addresses [START, END). 164 : : Returns the module handle, either existing or newly allocated, 165 : : or returns a null pointer for an allocation error. */ 166 : : Dwfl_Module * 167 : 195832 : dwfl_report_module (Dwfl *dwfl, const char *name, 168 : : GElf_Addr start, GElf_Addr end) 169 : : { 170 : 195832 : Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp; 171 : : 172 [ + + ]: 3902717 : for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next)) 173 : : { 174 [ + + + - ]: 3706889 : if (m->low_addr == start && m->high_addr == end 175 [ + - ]: 4 : && !strcmp (m->name, name)) 176 : : { 177 : : /* This module is still here. Move it to the place in the list 178 : : after the last module already reported. */ 179 : 4 : *prevp = m->next; 180 : 4 : m->gc = false; 181 [ - + ]: 4 : return use (m, tailp, dwfl); 182 : : } 183 : : 184 [ + - ]: 3706885 : if (! m->gc) 185 : 3706885 : tailp = &m->next; 186 : : } 187 : : 188 : 195828 : Dwfl_Module *mod = calloc (1, sizeof *mod); 189 [ - + ]: 195828 : if (mod == NULL) 190 : 0 : goto nomem; 191 : : 192 : 195828 : mod->name = strdup (name); 193 [ - + ]: 195828 : if (mod->name == NULL) 194 : : { 195 : 0 : free (mod); 196 : 0 : nomem: 197 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM); 198 : 0 : return NULL; 199 : : } 200 : : 201 : 195828 : mod->low_addr = start; 202 : 195828 : mod->high_addr = end; 203 : 195828 : mod->dwfl = dwfl; 204 : : 205 [ - + ]: 195828 : return use (mod, tailp, dwfl); 206 : : } 207 : : INTDEF (dwfl_report_module) 208 : : 209 : : 210 : : /* Finish reporting the current set of modules to the library. 211 : : If REMOVED is not null, it's called for each module that 212 : : existed before but was not included in the current report. 213 : : Returns a nonzero return value from the callback. 214 : : DWFL cannot be used until this function has returned zero. */ 215 : : int 216 : 5605 : dwfl_report_end (Dwfl *dwfl, 217 : : int (*removed) (Dwfl_Module *, void *, 218 : : const char *, Dwarf_Addr, 219 : : void *arg), 220 : : void *arg) 221 : : { 222 : 5605 : Dwfl_Module **tailp = &dwfl->modulelist; 223 [ + + ]: 201432 : while (*tailp != NULL) 224 : : { 225 : 195827 : Dwfl_Module *m = *tailp; 226 [ - + - - ]: 195827 : if (m->gc && removed != NULL) 227 : : { 228 : 0 : int result = (*removed) (MODCB_ARGS (m), arg); 229 [ # # ]: 0 : if (result != 0) 230 : 0 : return result; 231 : : } 232 [ - + ]: 195827 : if (m->gc) 233 : : { 234 : 0 : *tailp = m->next; 235 : 0 : __libdwfl_module_free (m); 236 : : } 237 : : else 238 : 195827 : tailp = &m->next; 239 : : } 240 : : 241 : : return 0; 242 : : } 243 : : INTDEF (dwfl_report_end)