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