blob: 8efcfaa594b1dc090d2bcb5ead2e417cf6ecfee5 [file] [log] [blame]
Ben Cheng25b3c042013-11-20 14:45:36 -08001/* Maintenance of module list in libdwfl.
Elliott Hughes03333822015-02-18 22:19:45 -08002 Copyright (C) 2005, 2006, 2007, 2008, 2014 Red Hat, Inc.
3 This file is part of elfutils.
Ben Cheng25b3c042013-11-20 14:45:36 -08004
Elliott Hughes03333822015-02-18 22:19:45 -08005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Ben Cheng25b3c042013-11-20 14:45:36 -08007
Elliott Hughes03333822015-02-18 22:19:45 -08008 * 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
Ben Cheng25b3c042013-11-20 14:45:36 -080021 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
Elliott Hughes03333822015-02-18 22:19:45 -080025 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/>. */
Ben Cheng25b3c042013-11-20 14:45:36 -080028
29#include "libdwflP.h"
30#include <search.h>
31#include <unistd.h>
32
33static void
34free_cu (struct dwfl_cu *cu)
35{
36 if (cu->lines != NULL)
37 free (cu->lines);
38 free (cu);
39}
40
41static void
42nofree (void *arg __attribute__ ((unused)))
43{
44}
45
46static void
47free_file (struct dwfl_file *file)
48{
49 free (file->name);
50
51 /* Close the fd only on the last reference. */
52 if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1)
53 close (file->fd);
54}
55
56void
57internal_function
58__libdwfl_module_free (Dwfl_Module *mod)
59{
60 if (mod->lazy_cu_root != NULL)
61 tdestroy (mod->lazy_cu_root, nofree);
62
63 if (mod->aranges != NULL)
64 free (mod->aranges);
65
66 if (mod->cu != NULL)
67 {
68 for (size_t i = 0; i < mod->ncu; ++i)
69 free_cu (mod->cu[i]);
70 free (mod->cu);
71 }
72
73 if (mod->dw != NULL)
Elliott Hughes03333822015-02-18 22:19:45 -080074 {
75 INTUSE(dwarf_end) (mod->dw);
76 if (mod->alt != NULL)
77 {
78 INTUSE(dwarf_end) (mod->alt);
79 if (mod->alt_elf != NULL)
80 elf_end (mod->alt_elf);
81 if (mod->alt_fd != -1)
82 close (mod->alt_fd);
83 }
84 }
Ben Cheng25b3c042013-11-20 14:45:36 -080085
86 if (mod->ebl != NULL)
87 ebl_closebackend (mod->ebl);
88
89 if (mod->debug.elf != mod->main.elf)
90 free_file (&mod->debug);
91 free_file (&mod->main);
Elliott Hughes03333822015-02-18 22:19:45 -080092 free_file (&mod->aux_sym);
Ben Cheng25b3c042013-11-20 14:45:36 -080093
94 if (mod->build_id_bits != NULL)
95 free (mod->build_id_bits);
96
Elliott Hughes03333822015-02-18 22:19:45 -080097 if (mod->reloc_info != NULL)
98 free (mod->reloc_info);
99
100 if (mod->eh_cfi != NULL)
101 dwarf_cfi_end (mod->eh_cfi);
102
Ben Cheng25b3c042013-11-20 14:45:36 -0800103 free (mod->name);
104 free (mod);
105}
106
107void
108dwfl_report_begin_add (Dwfl *dwfl __attribute__ ((unused)))
109{
110 /* The lookup table will be cleared on demand, there is nothing we need
111 to do here. */
112}
113INTDEF (dwfl_report_begin_add)
114
115void
116dwfl_report_begin (Dwfl *dwfl)
117{
118 /* Clear the segment lookup table. */
119 dwfl->lookup_elts = 0;
120
121 for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
122 m->gc = true;
123
124 dwfl->offline_next_address = OFFLINE_REDZONE;
125}
126INTDEF (dwfl_report_begin)
127
128/* Report that a module called NAME spans addresses [START, END).
129 Returns the module handle, either existing or newly allocated,
130 or returns a null pointer for an allocation error. */
131Dwfl_Module *
132dwfl_report_module (Dwfl *dwfl, const char *name,
133 GElf_Addr start, GElf_Addr end)
134{
135 Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
136
137 inline Dwfl_Module *use (Dwfl_Module *mod)
138 {
139 mod->next = *tailp;
140 *tailp = mod;
141
142 if (unlikely (dwfl->lookup_module != NULL))
143 {
144 free (dwfl->lookup_module);
145 dwfl->lookup_module = NULL;
146 }
147
148 return mod;
149 }
150
151 for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
152 {
153 if (m->low_addr == start && m->high_addr == end
154 && !strcmp (m->name, name))
155 {
156 /* This module is still here. Move it to the place in the list
157 after the last module already reported. */
158 *prevp = m->next;
159 m->gc = false;
160 return use (m);
161 }
162
163 if (! m->gc)
164 tailp = &m->next;
165 }
166
167 Dwfl_Module *mod = calloc (1, sizeof *mod);
168 if (mod == NULL)
169 goto nomem;
170
171 mod->name = strdup (name);
172 if (mod->name == NULL)
173 {
174 free (mod);
175 nomem:
176 __libdwfl_seterrno (DWFL_E_NOMEM);
177 return NULL;
178 }
179
180 mod->low_addr = start;
181 mod->high_addr = end;
182 mod->dwfl = dwfl;
183
184 return use (mod);
185}
186INTDEF (dwfl_report_module)
187
188
189/* Finish reporting the current set of modules to the library.
190 If REMOVED is not null, it's called for each module that
191 existed before but was not included in the current report.
192 Returns a nonzero return value from the callback.
193 DWFL cannot be used until this function has returned zero. */
194int
195dwfl_report_end (Dwfl *dwfl,
196 int (*removed) (Dwfl_Module *, void *,
197 const char *, Dwarf_Addr,
198 void *arg),
199 void *arg)
200{
201 Dwfl_Module **tailp = &dwfl->modulelist;
202 while (*tailp != NULL)
203 {
204 Dwfl_Module *m = *tailp;
205 if (m->gc && removed != NULL)
206 {
207 int result = (*removed) (MODCB_ARGS (m), arg);
208 if (result != 0)
209 return result;
210 }
211 if (m->gc)
212 {
213 *tailp = m->next;
214 __libdwfl_module_free (m);
215 }
216 else
217 tailp = &m->next;
218 }
219
220 return 0;
221}
222INTDEF (dwfl_report_end)