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 : 12452 : free_cu (struct dwfl_cu *cu)
39 : : {
40 [ + + ]: 12452 : if (cu->lines != NULL)
41 : 2508 : free (cu->lines);
42 : 12452 : free (cu);
43 : 12452 : }
44 : :
45 : : static void
46 : 12452 : nofree (void *arg __attribute__ ((unused)))
47 : : {
48 : 12452 : }
49 : :
50 : : static void
51 : 164794 : free_file (struct dwfl_file *file)
52 : : {
53 : 164794 : free (file->name);
54 : :
55 : : /* Close the fd only on the last reference. */
56 [ + + + - : 164794 : if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1)
+ + ]
57 : 10238 : close (file->fd);
58 : 164794 : }
59 : :
60 : : void
61 : : internal_function
62 : 81936 : __libdwfl_module_free (Dwfl_Module *mod)
63 : : {
64 : 81936 : eu_search_tree_fini (&mod->lazy_cu_tree, nofree);
65 : :
66 [ + + ]: 81936 : if (mod->aranges != NULL)
67 : 126 : free (mod->aranges);
68 : :
69 [ + + ]: 81936 : if (mod->cu != NULL)
70 : : {
71 [ + + ]: 12754 : for (size_t i = 0; i < mod->ncu; ++i)
72 : 12452 : free_cu (mod->cu[i]);
73 : 302 : 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 [ + + ]: 81936 : 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 [ + + ]: 81936 : 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 [ + + ]: 81936 : if (mod->dw != NULL)
94 : : {
95 : 10840 : INTUSE(dwarf_end) (mod->dw);
96 [ + + ]: 10840 : 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 [ + + ]: 81936 : if (mod->ebl != NULL)
107 : 890 : ebl_closebackend (mod->ebl);
108 : :
109 [ + + ]: 81936 : if (mod->debug.elf != mod->main.elf)
110 : 922 : free_file (&mod->debug);
111 : 81936 : free_file (&mod->main);
112 : 81936 : free_file (&mod->aux_sym);
113 : :
114 [ + + ]: 81936 : if (mod->build_id_bits != NULL)
115 : 512 : free (mod->build_id_bits);
116 : :
117 [ + + ]: 81936 : if (mod->reloc_info != NULL)
118 : 324 : free (mod->reloc_info);
119 : :
120 : 81936 : free (mod->name);
121 : 81936 : free (mod->elfpath);
122 : 81936 : free (mod);
123 : 81936 : }
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 : 81990 : use (Dwfl_Module *mod, Dwfl_Module **tailp, Dwfl *dwfl)
148 : : {
149 : 81990 : mod->next = *tailp;
150 : 81990 : *tailp = mod;
151 : :
152 : 81990 : 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 : 81990 : dwfl_report_module (Dwfl *dwfl, const char *name,
166 : : GElf_Addr start, GElf_Addr end)
167 : : {
168 : 81990 : Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
169 : :
170 [ + + ]: 363216 : for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
171 : : {
172 [ + + + - ]: 281264 : 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 [ + - ]: 281226 : if (! m->gc)
183 : 281226 : tailp = &m->next;
184 : : }
185 : :
186 : 81952 : Dwfl_Module *mod = calloc (1, sizeof *mod);
187 [ - + ]: 81952 : if (mod == NULL)
188 : 0 : goto nomem;
189 : :
190 : 81952 : mod->name = strdup (name);
191 [ - + ]: 81952 : 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 : 81952 : mod->low_addr = start;
200 : 81952 : mod->high_addr = end;
201 : 81952 : mod->dwfl = dwfl;
202 : 81952 : eu_search_tree_init (&mod->lazy_cu_tree);
203 : :
204 [ + + ]: 81952 : 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 : 11532 : dwfl_report_end (Dwfl *dwfl,
216 : : int (*removed) (Dwfl_Module *, void *,
217 : : const char *, Dwarf_Addr,
218 : : void *arg),
219 : : void *arg)
220 : : {
221 : 11532 : Dwfl_Module **tailp = &dwfl->modulelist;
222 [ + + ]: 93454 : while (*tailp != NULL)
223 : : {
224 : 81922 : Dwfl_Module *m = *tailp;
225 [ - + - - ]: 81922 : if (m->gc && removed != NULL)
226 : : {
227 : 0 : int result = (*removed) (MODCB_ARGS (m), arg);
228 [ # # ]: 0 : if (result != 0)
229 : : return result;
230 : : }
231 [ - + ]: 81922 : if (m->gc)
232 : : {
233 : 0 : *tailp = m->next;
234 : 0 : __libdwfl_module_free (m);
235 : : }
236 : : else
237 : 81922 : tailp = &m->next;
238 : : }
239 : :
240 : : return 0;
241 : : }
242 : : INTDEF (dwfl_report_end)
|