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