1 /* Free resources associated with Elf descriptor.
2 Copyright (C) 1998,1999,2000,2001,2002,2004,2005,2007,2015,2016 Red Hat, Inc.
3 Copyright (C) 2023 Mark J. Wielaard <[email protected]>
4 This file is part of elfutils.
5 Written by Ulrich Drepper <[email protected]>, 1998.
6
7 This file is free software; you can redistribute it and/or modify
8 it under the terms of either
9
10 * the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 3 of the License, or (at
12 your option) any later version
13
14 or
15
16 * the GNU General Public License as published by the Free
17 Software Foundation; either version 2 of the License, or (at
18 your option) any later version
19
20 or both in parallel, as here.
21
22 elfutils is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
26
27 You should have received copies of the GNU General Public License and
28 the GNU Lesser General Public License along with this program. If
29 not, see <http://www.gnu.org/licenses/>. */
30
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34
35 #include <assert.h>
36 #include <search.h>
37 #include <stddef.h>
38 #include <stdlib.h>
39
40 #include "libelfP.h"
41
42
43 static void
free_chunk(void * n)44 free_chunk (void *n)
45 {
46 Elf_Data_Chunk *rawchunk = (Elf_Data_Chunk *)n;
47 if (rawchunk->dummy_scn.flags & ELF_F_MALLOCED)
48 free (rawchunk->data.d.d_buf);
49 free (rawchunk);
50 }
51
52 int
elf_end(Elf * elf)53 elf_end (Elf *elf)
54 {
55 Elf *parent;
56
57 if (elf == NULL)
58 /* This is allowed and is a no-op. */
59 return 0;
60
61 /* Make sure we are alone. */
62 rwlock_wrlock (elf->lock);
63
64 if (elf->ref_count != 0 && --elf->ref_count != 0)
65 {
66 /* Not yet the last activation. */
67 int result = elf->ref_count;
68 rwlock_unlock (elf->lock);
69 return result;
70 }
71
72 if (elf->kind == ELF_K_AR)
73 {
74 /* We cannot remove the descriptor now since we still have some
75 descriptors which depend on it. But we can free the archive
76 symbol table since this is only available via the archive ELF
77 descriptor. The long name table cannot be freed yet since
78 the archive headers for the ELF files in the archive point
79 into this array. */
80 if (elf->state.ar.ar_sym != (Elf_Arsym *) -1l)
81 free (elf->state.ar.ar_sym);
82 elf->state.ar.ar_sym = NULL;
83
84 if (elf->state.ar.children != NULL)
85 {
86 rwlock_unlock(elf->lock);
87 return 0;
88 }
89 }
90
91 /* Remove this structure from the children list. */
92 parent = elf->parent;
93 if (parent != NULL)
94 {
95 /* This is tricky. Lock must be acquire from the father to
96 the child but here we already have the child lock. We
97 solve this problem by giving free the child lock. The
98 state of REF_COUNT==0 is handled all over the library, so
99 this should be ok. */
100 rwlock_unlock (elf->lock);
101 rwlock_rdlock (parent->lock);
102 rwlock_wrlock (elf->lock);
103
104 if (parent->state.ar.children == elf)
105 parent->state.ar.children = elf->next;
106 else
107 {
108 struct Elf *child = parent->state.ar.children;
109
110 while (child->next != elf)
111 child = child->next;
112
113 child->next = elf->next;
114 }
115
116 rwlock_unlock (parent->lock);
117 }
118
119 /* This was the last activation. Free all resources. */
120 switch (elf->kind)
121 {
122 case ELF_K_AR:
123 if (elf->state.ar.long_names != NULL)
124 free (elf->state.ar.long_names);
125 break;
126
127 case ELF_K_ELF:
128 {
129 void *rawchunks
130 = (elf->class == ELFCLASS32
131 || (offsetof (struct Elf, state.elf32.rawchunks)
132 == offsetof (struct Elf, state.elf64.rawchunks))
133 ? elf->state.elf32.rawchunks
134 : elf->state.elf64.rawchunks);
135 tdestroy (rawchunks, free_chunk);
136
137 Elf_ScnList *list = (elf->class == ELFCLASS32
138 || (offsetof (struct Elf, state.elf32.scns)
139 == offsetof (struct Elf, state.elf64.scns))
140 ? &elf->state.elf32.scns
141 : &elf->state.elf64.scns);
142
143 do
144 {
145 /* Free all separately allocated section headers. */
146 size_t cnt = list->max;
147
148 while (cnt-- > 0)
149 {
150 /* These pointers can be NULL; it's safe to use
151 'free' since it will check for this. */
152 Elf_Scn *scn = &list->data[cnt];
153 Elf_Data_List *runp;
154
155 if ((scn->shdr_flags & ELF_F_MALLOCED) != 0)
156 /* It doesn't matter which pointer. */
157 free (scn->shdr.e32);
158
159 /* Free zdata if uncompressed, but not yet used as
160 rawdata_base. If it is already used it will be
161 freed below. */
162 if (scn->zdata_base != scn->rawdata_base)
163 {
164 free (scn->zdata_base);
165 scn->zdata_base = NULL;
166 }
167
168 /* If the file has the same byte order and the
169 architecture doesn't require overly stringent
170 alignment the raw data buffer is the same as the
171 one used for presenting to the caller. */
172 if (scn->data_base != scn->rawdata_base)
173 free (scn->data_base);
174
175 /* The section data is allocated if we couldn't mmap
176 the file. Or if we had to decompress. */
177 if (elf->map_address == NULL
178 || scn->rawdata_base == scn->zdata_base
179 || (scn->flags & ELF_F_MALLOCED) != 0)
180 free (scn->rawdata_base);
181
182 /* Free the list of data buffers for the section.
183 We don't free the buffers themselves since this
184 is the users job. */
185 runp = scn->data_list.next;
186 while (runp != NULL)
187 {
188 Elf_Data_List *oldp = runp;
189 runp = runp->next;
190 if ((oldp->flags & ELF_F_MALLOCED) != 0)
191 free (oldp);
192 }
193 }
194
195 /* Free the memory for the array. */
196 Elf_ScnList *oldp = list;
197 list = list->next;
198 assert (list == NULL || oldp->cnt == oldp->max);
199 if (oldp != (elf->class == ELFCLASS32
200 || (offsetof (struct Elf, state.elf32.scns)
201 == offsetof (struct Elf, state.elf64.scns))
202 ? &elf->state.elf32.scns
203 : &elf->state.elf64.scns))
204 free (oldp);
205 }
206 while (list != NULL);
207 }
208
209 /* Free the section header. */
210 if (elf->state.elf.shdr_malloced != 0)
211 free (elf->class == ELFCLASS32
212 || (offsetof (struct Elf, state.elf32.shdr)
213 == offsetof (struct Elf, state.elf64.shdr))
214 ? (void *) elf->state.elf32.shdr
215 : (void *) elf->state.elf64.shdr);
216
217 /* Free the program header. */
218 if ((elf->state.elf.phdr_flags & ELF_F_MALLOCED) != 0)
219 free (elf->class == ELFCLASS32
220 || (offsetof (struct Elf, state.elf32.phdr)
221 == offsetof (struct Elf, state.elf64.phdr))
222 ? (void *) elf->state.elf32.phdr
223 : (void *) elf->state.elf64.phdr);
224 break;
225
226 default:
227 break;
228 }
229
230 if (elf->map_address != NULL && parent == NULL)
231 {
232 /* The file was read or mapped for this descriptor. */
233 if ((elf->flags & ELF_F_MALLOCED) != 0)
234 free (elf->map_address);
235 else if ((elf->flags & ELF_F_MMAPPED) != 0)
236 munmap (elf->map_address, elf->maximum_size);
237 }
238
239 rwlock_unlock (elf->lock);
240 rwlock_fini (elf->lock);
241
242 /* Finally the descriptor itself. */
243 free (elf);
244
245 return (parent != NULL && parent->ref_count == 0
246 ? INTUSE(elf_end) (parent) : 0);
247 }
248 INTDEF(elf_end)
249