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