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 : 9627 : free_cu (struct dwfl_cu *cu)
39 : : {
40 [ + + ]: 9627 : if (cu->lines != NULL)
41 : 1213 : free (cu->lines);
42 : 9627 : free (cu);
43 : 9627 : }
44 : :
45 : : static void
46 : 9627 : nofree (void *arg __attribute__ ((unused)))
47 : : {
48 : 9627 : }
49 : :
50 : : static void
51 : 82256 : free_file (struct dwfl_file *file)
52 : : {
53 : 82256 : free (file->name);
54 : :
55 : : /* Close the fd only on the last reference. */
56 [ + + + - : 82256 : if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1)
+ + ]
57 : 5104 : close (file->fd);
58 : 82256 : }
59 : :
60 : : void
61 : : internal_function
62 : 40904 : __libdwfl_module_free (Dwfl_Module *mod)
63 : : {
64 [ + + ]: 40904 : if (mod->lazy_cu_root != NULL)
65 : 146 : tdestroy (mod->lazy_cu_root, nofree);
66 : :
67 [ + + ]: 40904 : if (mod->aranges != NULL)
68 : 58 : free (mod->aranges);
69 : :
70 [ + + ]: 40904 : if (mod->cu != NULL)
71 : : {
72 [ + + ]: 9773 : for (size_t i = 0; i < mod->ncu; ++i)
73 : 9627 : free_cu (mod->cu[i]);
74 : 146 : free (mod->cu);
75 : : }
76 : :
77 : : /* We might have primed the Dwarf_CFI ebl cache with our own ebl
78 : : in __libdwfl_set_cfi. Make sure we don't free it twice. */
79 [ + + ]: 40904 : if (mod->eh_cfi != NULL)
80 : : {
81 [ + - + - ]: 72 : if (mod->eh_cfi->ebl != NULL && mod->eh_cfi->ebl == mod->ebl)
82 : 72 : mod->eh_cfi->ebl = NULL;
83 : 72 : dwarf_cfi_end (mod->eh_cfi);
84 : : }
85 : :
86 [ + + ]: 40904 : if (mod->dwarf_cfi != NULL)
87 : : {
88 [ + - + - ]: 12 : if (mod->dwarf_cfi->ebl != NULL && mod->dwarf_cfi->ebl == mod->ebl)
89 : 12 : mod->dwarf_cfi->ebl = NULL;
90 : : /* We don't need to explicitly destroy the dwarf_cfi.
91 : : That will be done by dwarf_end. */
92 : : }
93 : :
94 [ + + ]: 40904 : if (mod->dw != NULL)
95 : : {
96 : 5398 : INTUSE(dwarf_end) (mod->dw);
97 [ + + ]: 5398 : if (mod->alt != NULL)
98 : : {
99 : 22 : INTUSE(dwarf_end) (mod->alt);
100 [ + - ]: 22 : if (mod->alt_elf != NULL)
101 : 22 : elf_end (mod->alt_elf);
102 [ + - ]: 22 : if (mod->alt_fd != -1)
103 : 22 : close (mod->alt_fd);
104 : : }
105 : : }
106 : :
107 [ + + ]: 40904 : if (mod->ebl != NULL)
108 : 447 : ebl_closebackend (mod->ebl);
109 : :
110 [ + + ]: 40904 : if (mod->debug.elf != mod->main.elf)
111 : 448 : free_file (&mod->debug);
112 : 40904 : free_file (&mod->main);
113 : 40904 : free_file (&mod->aux_sym);
114 : :
115 [ + + ]: 40904 : if (mod->build_id_bits != NULL)
116 : 195 : free (mod->build_id_bits);
117 : :
118 [ + + ]: 40904 : if (mod->reloc_info != NULL)
119 : 188 : free (mod->reloc_info);
120 : :
121 : 40904 : free (mod->name);
122 : 40904 : free (mod->elfdir);
123 : 40904 : free (mod);
124 : 40904 : }
125 : :
126 : : void
127 : 0 : dwfl_report_begin_add (Dwfl *dwfl __attribute__ ((unused)))
128 : : {
129 : : /* The lookup table will be cleared on demand, there is nothing we need
130 : : to do here. */
131 : 0 : }
132 : : INTDEF (dwfl_report_begin_add)
133 : :
134 : : void
135 : 11 : dwfl_report_begin (Dwfl *dwfl)
136 : : {
137 : : /* Clear the segment lookup table. */
138 : 11 : dwfl->lookup_elts = 0;
139 : :
140 [ + + ]: 15 : for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
141 : 4 : m->gc = true;
142 : :
143 : 11 : dwfl->offline_next_address = OFFLINE_REDZONE;
144 : 11 : }
145 : : INTDEF (dwfl_report_begin)
146 : :
147 : : static inline Dwfl_Module *
148 : 40916 : use (Dwfl_Module *mod, Dwfl_Module **tailp, Dwfl *dwfl)
149 : : {
150 : 40916 : mod->next = *tailp;
151 : 40916 : *tailp = mod;
152 : :
153 : 40916 : if (unlikely (dwfl->lookup_module != NULL))
154 : : {
155 : 1 : free (dwfl->lookup_module);
156 : 1 : dwfl->lookup_module = NULL;
157 : : }
158 : :
159 : 4 : return mod;
160 : : }
161 : :
162 : : /* Report that a module called NAME spans addresses [START, END).
163 : : Returns the module handle, either existing or newly allocated,
164 : : or returns a null pointer for an allocation error. */
165 : : Dwfl_Module *
166 : 40916 : dwfl_report_module (Dwfl *dwfl, const char *name,
167 : : GElf_Addr start, GElf_Addr end)
168 : : {
169 : 40916 : Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
170 : :
171 [ + + ]: 181346 : for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
172 : : {
173 [ + + + - ]: 140434 : if (m->low_addr == start && m->high_addr == end
174 [ + - ]: 4 : && !strcmp (m->name, name))
175 : : {
176 : : /* This module is still here. Move it to the place in the list
177 : : after the last module already reported. */
178 : 4 : *prevp = m->next;
179 : 4 : m->gc = false;
180 [ - + ]: 4 : return use (m, tailp, dwfl);
181 : : }
182 : :
183 [ + - ]: 140430 : if (! m->gc)
184 : 140430 : tailp = &m->next;
185 : : }
186 : :
187 : 40912 : Dwfl_Module *mod = calloc (1, sizeof *mod);
188 [ - + ]: 40912 : if (mod == NULL)
189 : 0 : goto nomem;
190 : :
191 : 40912 : mod->name = strdup (name);
192 [ - + ]: 40912 : if (mod->name == NULL)
193 : : {
194 : 0 : free (mod);
195 : 0 : nomem:
196 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
197 : 0 : return NULL;
198 : : }
199 : :
200 : 40912 : mod->low_addr = start;
201 : 40912 : mod->high_addr = end;
202 : 40912 : mod->dwfl = dwfl;
203 : :
204 [ + + ]: 40912 : 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 : 5751 : dwfl_report_end (Dwfl *dwfl,
216 : : int (*removed) (Dwfl_Module *, void *,
217 : : const char *, Dwarf_Addr,
218 : : void *arg),
219 : : void *arg)
220 : : {
221 : 5751 : Dwfl_Module **tailp = &dwfl->modulelist;
222 [ + + ]: 46658 : while (*tailp != NULL)
223 : : {
224 : 40907 : Dwfl_Module *m = *tailp;
225 [ - + - - ]: 40907 : 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 [ - + ]: 40907 : if (m->gc)
232 : : {
233 : 0 : *tailp = m->next;
234 : 0 : __libdwfl_module_free (m);
235 : : }
236 : : else
237 : 40907 : tailp = &m->next;
238 : : }
239 : :
240 : : return 0;
241 : : }
242 : : INTDEF (dwfl_report_end)
|