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 5629 : free_cu (struct dwfl_cu *cu)
40 : {
41 5629 : if (cu->lines != NULL)
42 1141 : free (cu->lines);
43 5629 : free (cu);
44 5629 : }
45 :
46 : static void
47 5629 : nofree (void *arg __attribute__ ((unused)))
48 : {
49 5629 : }
50 :
51 : static void
52 91214 : free_file (struct dwfl_file *file)
53 : {
54 91214 : free (file->name);
55 :
56 : /* Close the fd only on the last reference. */
57 91214 : if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1)
58 5139 : close (file->fd);
59 91214 : }
60 :
61 : void
62 : internal_function
63 45497 : __libdwfl_module_free (Dwfl_Module *mod)
64 : {
65 45497 : if (mod->lazy_cu_root != NULL)
66 108 : tdestroy (mod->lazy_cu_root, nofree);
67 :
68 45497 : if (mod->aranges != NULL)
69 58 : free (mod->aranges);
70 :
71 45497 : if (mod->cu != NULL)
72 : {
73 5629 : for (size_t i = 0; i < mod->ncu; ++i)
74 5629 : free_cu (mod->cu[i]);
75 108 : 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 45497 : if (mod->eh_cfi != NULL)
81 : {
82 48 : if (mod->eh_cfi->ebl != NULL && mod->eh_cfi->ebl == mod->ebl)
83 48 : mod->eh_cfi->ebl = NULL;
84 48 : dwarf_cfi_end (mod->eh_cfi);
85 : }
86 :
87 45497 : if (mod->dwarf_cfi != NULL)
88 : {
89 11 : if (mod->dwarf_cfi->ebl != NULL && mod->dwarf_cfi->ebl == mod->ebl)
90 11 : 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 45497 : if (mod->dw != NULL)
96 : {
97 5219 : INTUSE(dwarf_end) (mod->dw);
98 5219 : if (mod->alt != NULL)
99 : {
100 6 : INTUSE(dwarf_end) (mod->alt);
101 6 : if (mod->alt_elf != NULL)
102 6 : elf_end (mod->alt_elf);
103 6 : if (mod->alt_fd != -1)
104 6 : close (mod->alt_fd);
105 : }
106 : }
107 :
108 45497 : if (mod->ebl != NULL)
109 237 : ebl_closebackend (mod->ebl);
110 :
111 45497 : if (mod->debug.elf != mod->main.elf)
112 220 : free_file (&mod->debug);
113 45497 : free_file (&mod->main);
114 45497 : free_file (&mod->aux_sym);
115 :
116 45497 : if (mod->build_id_bits != NULL)
117 168 : free (mod->build_id_bits);
118 :
119 45497 : if (mod->reloc_info != NULL)
120 117 : free (mod->reloc_info);
121 :
122 45497 : free (mod->name);
123 45497 : free (mod);
124 45497 : }
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 5 : dwfl_report_begin (Dwfl *dwfl)
136 : {
137 : /* Clear the segment lookup table. */
138 5 : dwfl->lookup_elts = 0;
139 :
140 9 : for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
141 4 : m->gc = true;
142 :
143 5 : dwfl->offline_next_address = OFFLINE_REDZONE;
144 5 : }
145 : INTDEF (dwfl_report_begin)
146 :
147 : static inline Dwfl_Module *
148 : use (Dwfl_Module *mod, Dwfl_Module **tailp, Dwfl *dwfl)
149 : {
150 45519 : mod->next = *tailp;
151 45519 : *tailp = mod;
152 :
153 45519 : if (unlikely (dwfl->lookup_module != NULL))
154 : {
155 1 : free (dwfl->lookup_module);
156 1 : dwfl->lookup_module = NULL;
157 : }
158 :
159 : 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 45519 : dwfl_report_module (Dwfl *dwfl, const char *name,
167 : GElf_Addr start, GElf_Addr end)
168 : {
169 45519 : Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
170 :
171 226001 : for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
172 : {
173 180486 : 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 180482 : if (! m->gc)
184 180482 : tailp = &m->next;
185 : }
186 :
187 45515 : Dwfl_Module *mod = calloc (1, sizeof *mod);
188 45515 : if (mod == NULL)
189 : goto nomem;
190 :
191 45515 : mod->name = strdup (name);
192 45515 : if (mod->name == NULL)
193 : {
194 0 : free (mod);
195 : nomem:
196 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
197 0 : return NULL;
198 : }
199 :
200 45515 : mod->low_addr = start;
201 45515 : mod->high_addr = end;
202 45515 : mod->dwfl = dwfl;
203 :
204 45515 : 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 5351 : dwfl_report_end (Dwfl *dwfl,
216 : int (*removed) (Dwfl_Module *, void *,
217 : const char *, Dwarf_Addr,
218 : void *arg),
219 : void *arg)
220 : {
221 5351 : Dwfl_Module **tailp = &dwfl->modulelist;
222 56218 : while (*tailp != NULL)
223 : {
224 45516 : Dwfl_Module *m = *tailp;
225 45516 : 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 45516 : if (m->gc)
232 : {
233 0 : *tailp = m->next;
234 0 : __libdwfl_module_free (m);
235 : }
236 : else
237 45516 : tailp = &m->next;
238 : }
239 :
240 : return 0;
241 : }
242 : INTDEF (dwfl_report_end)
|