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