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 : 8566 : free_cu (struct dwfl_cu *cu)
40 : : {
41 [ + + ]: 8566 : if (cu->lines != NULL)
42 : 1176 : free (cu->lines);
43 : 8566 : free (cu);
44 : 8566 : }
45 : :
46 : : static void
47 : 8566 : nofree (void *arg __attribute__ ((unused)))
48 : : {
49 : 8566 : }
50 : :
51 : : static void
52 : 112045 : free_file (struct dwfl_file *file)
53 : : {
54 : 112045 : free (file->name);
55 : :
56 : : /* Close the fd only on the last reference. */
57 [ + + + - : 112045 : if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1)
+ + ]
58 : 5107 : close (file->fd);
59 : 112045 : }
60 : :
61 : : void
62 : : internal_function
63 : 55832 : __libdwfl_module_free (Dwfl_Module *mod)
64 : : {
65 [ + + ]: 55832 : if (mod->lazy_cu_root != NULL)
66 : 143 : tdestroy (mod->lazy_cu_root, nofree);
67 : :
68 [ + + ]: 55832 : if (mod->aranges != NULL)
69 : 54 : free (mod->aranges);
70 : :
71 [ + + ]: 55832 : if (mod->cu != NULL)
72 : : {
73 [ + + ]: 8709 : for (size_t i = 0; i < mod->ncu; ++i)
74 : 8566 : free_cu (mod->cu[i]);
75 : 143 : 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 [ + + ]: 55832 : 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 [ + + ]: 55832 : 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 [ + + ]: 55832 : if (mod->dw != NULL)
96 : : {
97 : 5389 : INTUSE(dwarf_end) (mod->dw);
98 [ + + ]: 5389 : if (mod->alt != NULL)
99 : : {
100 : 19 : INTUSE(dwarf_end) (mod->alt);
101 [ + - ]: 19 : if (mod->alt_elf != NULL)
102 : 19 : elf_end (mod->alt_elf);
103 [ + - ]: 19 : if (mod->alt_fd != -1)
104 : 19 : close (mod->alt_fd);
105 : : }
106 : : }
107 : :
108 [ + + ]: 55832 : if (mod->ebl != NULL)
109 : 469 : ebl_closebackend (mod->ebl);
110 : :
111 [ + + ]: 55832 : if (mod->debug.elf != mod->main.elf)
112 : 381 : free_file (&mod->debug);
113 : 55832 : free_file (&mod->main);
114 : 55832 : free_file (&mod->aux_sym);
115 : :
116 [ + + ]: 55832 : if (mod->build_id_bits != NULL)
117 : 193 : free (mod->build_id_bits);
118 : :
119 [ + + ]: 55832 : if (mod->reloc_info != NULL)
120 : 196 : free (mod->reloc_info);
121 : :
122 : 55832 : free (mod->name);
123 : 55832 : free (mod->elfdir);
124 : 55832 : free (mod);
125 : 55832 : }
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 : 11 : dwfl_report_begin (Dwfl *dwfl)
137 : : {
138 : : /* Clear the segment lookup table. */
139 : 11 : dwfl->lookup_elts = 0;
140 : :
141 [ + + ]: 15 : for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
142 : 4 : m->gc = true;
143 : :
144 : 11 : dwfl->offline_next_address = OFFLINE_REDZONE;
145 : 11 : }
146 : : INTDEF (dwfl_report_begin)
147 : :
148 : : static inline Dwfl_Module *
149 : 55847 : use (Dwfl_Module *mod, Dwfl_Module **tailp, Dwfl *dwfl)
150 : : {
151 : 55847 : mod->next = *tailp;
152 : 55847 : *tailp = mod;
153 : :
154 : 55847 : 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 : 55847 : dwfl_report_module (Dwfl *dwfl, const char *name,
168 : : GElf_Addr start, GElf_Addr end)
169 : : {
170 : 55847 : Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
171 : :
172 [ + + ]: 331360 : for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
173 : : {
174 [ + + + - ]: 275517 : 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 [ + - ]: 275513 : if (! m->gc)
185 : 275513 : tailp = &m->next;
186 : : }
187 : :
188 : 55843 : Dwfl_Module *mod = calloc (1, sizeof *mod);
189 [ - + ]: 55843 : if (mod == NULL)
190 : 0 : goto nomem;
191 : :
192 : 55843 : mod->name = strdup (name);
193 [ - + ]: 55843 : 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 : 55843 : mod->low_addr = start;
202 : 55843 : mod->high_addr = end;
203 : 55843 : mod->dwfl = dwfl;
204 : :
205 [ - + ]: 55843 : 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 : 5674 : dwfl_report_end (Dwfl *dwfl,
217 : : int (*removed) (Dwfl_Module *, void *,
218 : : const char *, Dwarf_Addr,
219 : : void *arg),
220 : : void *arg)
221 : : {
222 : 5674 : Dwfl_Module **tailp = &dwfl->modulelist;
223 [ + + ]: 61514 : while (*tailp != NULL)
224 : : {
225 : 55840 : Dwfl_Module *m = *tailp;
226 [ - + - - ]: 55840 : 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 [ - + ]: 55840 : if (m->gc)
233 : : {
234 : 0 : *tailp = m->next;
235 : 0 : __libdwfl_module_free (m);
236 : : }
237 : : else
238 : 55840 : tailp = &m->next;
239 : : }
240 : :
241 : : return 0;
242 : : }
243 : : INTDEF (dwfl_report_end)
|