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