/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 | 79.4k | { |
53 | 79.4k | free (file->name); |
54 | | |
55 | | /* Close the fd only on the last reference. */ |
56 | 79.4k | if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1) |
57 | 33 | close (file->fd); |
58 | 79.4k | } |
59 | | |
60 | | void |
61 | | internal_function |
62 | | __libdwfl_module_free (Dwfl_Module *mod) |
63 | 27.9k | { |
64 | 27.9k | if (mod->lazy_cu_root != NULL) |
65 | 0 | tdestroy (mod->lazy_cu_root, nofree); |
66 | | |
67 | 27.9k | if (mod->aranges != NULL) |
68 | 0 | free (mod->aranges); |
69 | | |
70 | 27.9k | if (mod->cu != NULL) |
71 | 0 | { |
72 | 0 | for (size_t i = 0; i < mod->ncu; ++i) |
73 | 0 | free_cu (mod->cu[i]); |
74 | 0 | free (mod->cu); |
75 | 0 | } |
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 | 27.9k | if (mod->eh_cfi != NULL) |
80 | 0 | { |
81 | 0 | if (mod->eh_cfi->ebl != NULL && mod->eh_cfi->ebl == mod->ebl) |
82 | 0 | mod->eh_cfi->ebl = NULL; |
83 | 0 | dwarf_cfi_end (mod->eh_cfi); |
84 | 0 | } |
85 | | |
86 | 27.9k | if (mod->dwarf_cfi != NULL) |
87 | 0 | { |
88 | 0 | if (mod->dwarf_cfi->ebl != NULL && mod->dwarf_cfi->ebl == mod->ebl) |
89 | 0 | 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 | 0 | } |
93 | | |
94 | 27.9k | if (mod->dw != NULL) |
95 | 164 | { |
96 | 164 | INTUSE(dwarf_end) (mod->dw); |
97 | 164 | if (mod->alt != NULL) |
98 | 0 | { |
99 | 0 | INTUSE(dwarf_end) (mod->alt); |
100 | 0 | if (mod->alt_elf != NULL) |
101 | 0 | elf_end (mod->alt_elf); |
102 | 0 | if (mod->alt_fd != -1) |
103 | 0 | close (mod->alt_fd); |
104 | 0 | } |
105 | 164 | } |
106 | | |
107 | 27.9k | if (mod->ebl != NULL) |
108 | 0 | ebl_closebackend (mod->ebl); |
109 | | |
110 | 27.9k | if (mod->debug.elf != mod->main.elf) |
111 | 23.5k | free_file (&mod->debug); |
112 | 27.9k | free_file (&mod->main); |
113 | 27.9k | free_file (&mod->aux_sym); |
114 | | |
115 | 27.9k | if (mod->build_id_bits != NULL) |
116 | 390 | free (mod->build_id_bits); |
117 | | |
118 | 27.9k | if (mod->reloc_info != NULL) |
119 | 0 | free (mod->reloc_info); |
120 | | |
121 | 27.9k | free (mod->name); |
122 | 27.9k | free (mod->elfpath); |
123 | 27.9k | free (mod); |
124 | 27.9k | } |
125 | | |
126 | | void |
127 | | dwfl_report_begin_add (Dwfl *dwfl __attribute__ ((unused))) |
128 | 0 | { |
129 | | /* The lookup table will be cleared on demand, there is nothing we need |
130 | | to do here. */ |
131 | 0 | } |
132 | | INTDEF (dwfl_report_begin_add) |
133 | | |
134 | | void |
135 | | dwfl_report_begin (Dwfl *dwfl) |
136 | 11.7k | { |
137 | | /* Clear the segment lookup table. */ |
138 | 11.7k | dwfl->lookup_elts = 0; |
139 | | |
140 | 11.7k | for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next) |
141 | 0 | m->gc = true; |
142 | | |
143 | 11.7k | dwfl->offline_next_address = OFFLINE_REDZONE; |
144 | 11.7k | } |
145 | | INTDEF (dwfl_report_begin) |
146 | | |
147 | | static inline Dwfl_Module * |
148 | | use (Dwfl_Module *mod, Dwfl_Module **tailp, Dwfl *dwfl) |
149 | 41.7k | { |
150 | 41.7k | mod->next = *tailp; |
151 | 41.7k | *tailp = mod; |
152 | | |
153 | 41.7k | if (unlikely (dwfl->lookup_module != NULL)) |
154 | 0 | { |
155 | 0 | free (dwfl->lookup_module); |
156 | 0 | dwfl->lookup_module = NULL; |
157 | 0 | } |
158 | | |
159 | 41.7k | return mod; |
160 | 41.7k | } |
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 * |
166 | | dwfl_report_module (Dwfl *dwfl, const char *name, |
167 | | GElf_Addr start, GElf_Addr end) |
168 | 41.7k | { |
169 | 41.7k | Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp; |
170 | | |
171 | 2.69M | for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next)) |
172 | 2.67M | { |
173 | 2.67M | if (m->low_addr == start && m->high_addr == end |
174 | 35.7k | && !strcmp (m->name, name)) |
175 | 13.7k | { |
176 | | /* This module is still here. Move it to the place in the list |
177 | | after the last module already reported. */ |
178 | 13.7k | *prevp = m->next; |
179 | 13.7k | m->gc = false; |
180 | 13.7k | return use (m, tailp, dwfl); |
181 | 13.7k | } |
182 | | |
183 | 2.65M | if (! m->gc) |
184 | 2.65M | tailp = &m->next; |
185 | 2.65M | } |
186 | | |
187 | 27.9k | Dwfl_Module *mod = calloc (1, sizeof *mod); |
188 | 27.9k | if (mod == NULL) |
189 | 0 | goto nomem; |
190 | | |
191 | 27.9k | mod->name = strdup (name); |
192 | 27.9k | if (mod->name == NULL) |
193 | 0 | { |
194 | 0 | free (mod); |
195 | 0 | nomem: |
196 | 0 | __libdwfl_seterrno (DWFL_E_NOMEM); |
197 | 0 | return NULL; |
198 | 0 | } |
199 | | |
200 | 27.9k | mod->low_addr = start; |
201 | 27.9k | mod->high_addr = end; |
202 | 27.9k | mod->dwfl = dwfl; |
203 | | |
204 | 27.9k | return use (mod, tailp, dwfl); |
205 | 27.9k | } |
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 | 17.8k | { |
221 | 17.8k | Dwfl_Module **tailp = &dwfl->modulelist; |
222 | 24.3k | while (*tailp != NULL) |
223 | 6.50k | { |
224 | 6.50k | Dwfl_Module *m = *tailp; |
225 | 6.50k | 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 | 6.50k | if (m->gc) |
232 | 19 | { |
233 | 19 | *tailp = m->next; |
234 | 19 | __libdwfl_module_free (m); |
235 | 19 | } |
236 | 6.49k | else |
237 | 6.49k | tailp = &m->next; |
238 | 6.50k | } |
239 | | |
240 | 17.8k | return 0; |
241 | 17.8k | } |
242 | | INTDEF (dwfl_report_end) |